From: Ard Biesheuvel <ardb+git@google.com>
To: linux-kernel@vger.kernel.org
Cc: llvm@lists.linux.dev, keescook@chromium.org,
linux-hardening@vger.kernel.org, nathan@kernel.org,
Ard Biesheuvel <ardb@kernel.org>,
Josh Poimboeuf <jpoimboe@kernel.org>,
Peter Zijlstra <peterz@infradead.org>,
Jan Beulich <jbeulich@suse.com>,
"Jose E. Marchesi" <jemarch@gnu.org>,
Kees Cook <kees@kernel.org>
Subject: [PATCH v3 5/8] objtool: Add generic support for jump table annotations
Date: Fri, 11 Oct 2024 19:08:53 +0200 [thread overview]
Message-ID: <20241011170847.334429-15-ardb+git@google.com> (raw)
In-Reply-To: <20241011170847.334429-10-ardb+git@google.com>
From: Ard Biesheuvel <ardb@kernel.org>
Refactor the jump table handling code so that a generic code path is
provided that can identify jump tables attached to indirect jumps based
only on compiler provided annotations. This will be used by non-x86
architectures which do not support jump tables at all at this point.
Refactor the x86 code to share the logic that follows relocations on
instructions into the .rodata section and finds the associated symbols.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
tools/objtool/arch/x86/special.c | 46 ++++------
tools/objtool/check.c | 88 +++++++++++++++++++-
tools/objtool/include/objtool/check.h | 4 +
3 files changed, 106 insertions(+), 32 deletions(-)
diff --git a/tools/objtool/arch/x86/special.c b/tools/objtool/arch/x86/special.c
index cd964b85e2b1..08a5ce662974 100644
--- a/tools/objtool/arch/x86/special.c
+++ b/tools/objtool/arch/x86/special.c
@@ -112,46 +112,34 @@ static struct reloc *find_switch_table(struct objtool_file *file,
struct instruction *insn,
unsigned long *table_size)
{
- struct reloc *text_reloc, *rodata_reloc;
- struct section *table_sec;
- unsigned long table_offset;
-
- /* look for a relocation which references .rodata */
- text_reloc = find_reloc_by_dest_range(file->elf, insn->sec,
- insn->offset, insn->len);
- if (!text_reloc || text_reloc->sym->type != STT_SECTION ||
- !text_reloc->sym->sec->rodata)
- return NULL;
-
- table_offset = reloc_addend(text_reloc);
- table_sec = text_reloc->sym->sec;
+ struct reloc *rodata_reloc;
+ struct symbol *sym = NULL;
- if (reloc_type(text_reloc) == R_X86_64_PC32)
- table_offset += 4;
+ /*
+ * Each table entry has a rela associated with it. The rela
+ * should reference text in the same function as the original
+ * instruction.
+ */
+ rodata_reloc = find_rodata_sym_reference(file, insn, &sym);
/*
- * Make sure the .rodata address isn't associated with a
- * symbol. GCC jump tables are anonymous data.
+ * Annotations, if present, are attached to the indirect jump
+ * instruction directly. In this case, a symbol annotation is
+ * expected.
+ *
+ * Otherwise, make sure the .rodata address isn't associated with
+ * a symbol. Unannotated GCC jump tables are anonymous data.
*
* Also support C jump tables which are in the same format as
* switch jump tables. For objtool to recognize them, they
* need to be placed in the C_JUMP_TABLE_SECTION section. They
* have symbols associated with them.
*/
- if (find_symbol_containing(table_sec, table_offset) &&
- strcmp(table_sec->name, C_JUMP_TABLE_SECTION))
- return NULL;
-
- /*
- * Each table entry has a rela associated with it. The rela
- * should reference text in the same function as the original
- * instruction.
- */
- rodata_reloc = find_reloc_by_dest(file->elf, table_sec, table_offset);
- if (!rodata_reloc)
+ if (insn->type != INSN_JUMP_DYNAMIC && sym &&
+ strcmp(sym->sec->name, C_JUMP_TABLE_SECTION))
return NULL;
- *table_size = 0;
+ *table_size = sym ? sym->len : 0;
return rodata_reloc;
}
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 389475dde47c..b923d4a4efcb 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1372,6 +1372,8 @@ __weak const char *arch_nop_fentry_call(int len)
static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn)
{
+ unsigned long offset = insn->offset;
+ unsigned int len = insn->len;
struct reloc *reloc;
if (insn->no_reloc)
@@ -1380,8 +1382,12 @@ static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *i
if (!file)
return NULL;
- reloc = find_reloc_by_dest_range(file->elf, insn->sec,
- insn->offset, insn->len);
+ do {
+ /* Skip any R_*_NONE relocations */
+ reloc = find_reloc_by_dest_range(file->elf, insn->sec,
+ offset++, len--);
+ } while (len && reloc && reloc_type(reloc) == R_NONE);
+
if (!reloc) {
insn->no_reloc = 1;
return NULL;
@@ -2169,10 +2175,86 @@ int add_jump_table(struct objtool_file *file, struct instruction *insn,
return 0;
}
+struct reloc *find_rodata_sym_reference(struct objtool_file *file,
+ struct instruction *insn,
+ struct symbol **table_sym)
+{
+ struct reloc *text_reloc, *rodata_reloc;
+ unsigned long addend;
+ struct symbol *sym;
+
+ /*
+ * Look for a relocation which references .rodata. We must use
+ * find_reloc_by_dest_range() directly here, as insn_reloc() filters
+ * out R_*_NONE relocations which are used for jump table annotations.
+ */
+ text_reloc = find_reloc_by_dest_range(file->elf, insn->sec,
+ insn->offset, insn->len);
+ if (!text_reloc) {
+ insn->no_reloc = 1;
+ return NULL;
+ }
+
+ sym = text_reloc->sym;
+ if (!sym->sec->rodata)
+ return NULL;
+
+ if (reloc_type(text_reloc) == elf_data_rela_type(file->elf))
+ addend = arch_dest_reloc_offset(reloc_addend(text_reloc));
+ else
+ addend = reloc_addend(text_reloc);
+
+ rodata_reloc = find_reloc_by_dest(file->elf, sym->sec,
+ sym->offset + addend);
+ if (!rodata_reloc)
+ return NULL;
+
+ /*
+ * Find the ELF symbol covering the destination of the relocation. This
+ * is trivial if the reloc refers to a STT_OBJECT directly, but it may
+ * have been emitted as section relative as well.
+ */
+ if (sym->type == STT_SECTION)
+ sym = find_symbol_containing(sym->sec, addend);
+
+ *table_sym = sym;
+ return rodata_reloc;
+}
+
+/*
+ * Generic version of jump table handling, relying strictly on annotations
+ * provided by the compiler. Overridden for x86 using heuristics that attempt
+ * to correlate indirect jump instructions with preceding .rodata references.
+ */
int __weak add_func_jump_tables(struct objtool_file *file,
struct symbol *func)
{
- return 0;
+ struct instruction *insn;
+ int ret = 0;
+
+ func_for_each_insn(file, func, insn) {
+ struct reloc *reloc;
+ struct symbol *sym;
+
+ if (insn->type != INSN_JUMP_DYNAMIC)
+ continue;
+
+ /*
+ * Look for a relocation attached to this indirect jump that
+ * references an ELF object in .rodata. This should be the jump
+ * table annotation emitted by the compiler.
+ */
+ reloc = find_rodata_sym_reference(file, insn, &sym);
+ if (reloc && sym && sym->len) {
+ insn->_jump_table = reloc;
+ insn->_jump_table_size = sym->len;
+
+ ret = add_jump_table(file, insn, NULL);
+ if (ret)
+ break;
+ }
+ }
+ return ret;
}
/*
diff --git a/tools/objtool/include/objtool/check.h b/tools/objtool/include/objtool/check.h
index e2f755484c4a..7781100c9340 100644
--- a/tools/objtool/include/objtool/check.h
+++ b/tools/objtool/include/objtool/check.h
@@ -140,4 +140,8 @@ struct instruction *next_insn_same_func(struct objtool_file *file, struct instru
insn; \
insn = next_insn_same_func(file, insn))
+struct reloc *find_rodata_sym_reference(struct objtool_file *file,
+ struct instruction *insn,
+ struct symbol **sym);
+
#endif /* _CHECK_H */
--
2.47.0.rc1.288.g06298d1525-goog
next prev parent reply other threads:[~2024-10-11 17:09 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-11 17:08 [PATCH v3 0/8] Improve objtool jump table handling Ard Biesheuvel
2024-10-11 17:08 ` [PATCH v3 1/8] objtool: Deal with relative jump tables correctly Ard Biesheuvel
2024-10-11 17:08 ` [PATCH v3 2/8] objtool: Allow arch code to discover jump table size Ard Biesheuvel
2024-12-03 10:45 ` [tip: objtool/core] " tip-bot2 for Ard Biesheuvel
2024-10-11 17:08 ` [PATCH v3 3/8] objtool: Make some helper functions globally accessible Ard Biesheuvel
2024-10-11 17:08 ` [PATCH v3 4/8] objtool: Move jump table heuristics to a x86 specific source file Ard Biesheuvel
2024-10-11 17:08 ` Ard Biesheuvel [this message]
2024-10-11 17:08 ` [PATCH v3 6/8] crypto: x86/crc32c - Use idiomatic relative jump table Ard Biesheuvel
2024-10-14 4:28 ` Eric Biggers
2024-10-14 9:36 ` Ard Biesheuvel
2024-10-11 17:08 ` [PATCH v3 7/8] crypto: x86/crc32c - Add jump table annotation Ard Biesheuvel
2024-10-11 17:08 ` [PATCH v3 8/8] crypto: x86/crc32c-intel - Tweaks to make objtool's life harder Ard Biesheuvel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20241011170847.334429-15-ardb+git@google.com \
--to=ardb+git@google.com \
--cc=ardb@kernel.org \
--cc=jbeulich@suse.com \
--cc=jemarch@gnu.org \
--cc=jpoimboe@kernel.org \
--cc=kees@kernel.org \
--cc=keescook@chromium.org \
--cc=linux-hardening@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=llvm@lists.linux.dev \
--cc=nathan@kernel.org \
--cc=peterz@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox