objtool: Allow alternatives to be ignored
Getting objtool to understand retpolines is going to be a bit of a challenge. For now, take advantage of the fact that retpolines are patched in with alternatives. Just read the original (sane) non-alternative instruction, and ignore the patched-in retpoline. This allows objtool to understand the control flow *around* the retpoline, even if it can't yet follow what's inside. This means the ORC unwinder will fail to unwind from inside a retpoline, but will work fine otherwise. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Signed-off-by: David Woodhouse <dwmw@amazon.co.uk> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: gnomes@lxorguk.ukuu.org.uk Cc: Rik van Riel <riel@redhat.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: thomas.lendacky@amd.com Cc: Peter Zijlstra <peterz@infradead.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Jiri Kosina <jikos@kernel.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Dave Hansen <dave.hansen@intel.com> Cc: Kees Cook <keescook@google.com> Cc: Tim Chen <tim.c.chen@linux.intel.com> Cc: Greg Kroah-Hartman <gregkh@linux-foundation.org> Cc: Paul Turner <pjt@google.com> Link: https://lkml.kernel.org/r/1515707194-20531-3-git-send-email-dwmw@amazon.co.uk
This commit is contained in:
Родитель
39b735332c
Коммит
258c76059c
|
@ -427,6 +427,40 @@ static void add_ignores(struct objtool_file *file)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: For now, just ignore any alternatives which add retpolines. This is
|
||||
* a temporary hack, as it doesn't allow ORC to unwind from inside a retpoline.
|
||||
* But it at least allows objtool to understand the control flow *around* the
|
||||
* retpoline.
|
||||
*/
|
||||
static int add_nospec_ignores(struct objtool_file *file)
|
||||
{
|
||||
struct section *sec;
|
||||
struct rela *rela;
|
||||
struct instruction *insn;
|
||||
|
||||
sec = find_section_by_name(file->elf, ".rela.discard.nospec");
|
||||
if (!sec)
|
||||
return 0;
|
||||
|
||||
list_for_each_entry(rela, &sec->rela_list, list) {
|
||||
if (rela->sym->type != STT_SECTION) {
|
||||
WARN("unexpected relocation symbol type in %s", sec->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
insn = find_insn(file, rela->sym->sec, rela->addend);
|
||||
if (!insn) {
|
||||
WARN("bad .discard.nospec entry");
|
||||
return -1;
|
||||
}
|
||||
|
||||
insn->ignore_alts = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the destination instructions for all jumps.
|
||||
*/
|
||||
|
@ -509,11 +543,18 @@ static int add_call_destinations(struct objtool_file *file)
|
|||
dest_off = insn->offset + insn->len + insn->immediate;
|
||||
insn->call_dest = find_symbol_by_offset(insn->sec,
|
||||
dest_off);
|
||||
/*
|
||||
* FIXME: Thanks to retpolines, it's now considered
|
||||
* normal for a function to call within itself. So
|
||||
* disable this warning for now.
|
||||
*/
|
||||
#if 0
|
||||
if (!insn->call_dest) {
|
||||
WARN_FUNC("can't find call dest symbol at offset 0x%lx",
|
||||
insn->sec, insn->offset, dest_off);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
} else if (rela->sym->type == STT_SECTION) {
|
||||
insn->call_dest = find_symbol_by_offset(rela->sym->sec,
|
||||
rela->addend+4);
|
||||
|
@ -678,12 +719,6 @@ static int add_special_section_alts(struct objtool_file *file)
|
|||
return ret;
|
||||
|
||||
list_for_each_entry_safe(special_alt, tmp, &special_alts, list) {
|
||||
alt = malloc(sizeof(*alt));
|
||||
if (!alt) {
|
||||
WARN("malloc failed");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
orig_insn = find_insn(file, special_alt->orig_sec,
|
||||
special_alt->orig_off);
|
||||
|
@ -694,6 +729,10 @@ static int add_special_section_alts(struct objtool_file *file)
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* Ignore retpoline alternatives. */
|
||||
if (orig_insn->ignore_alts)
|
||||
continue;
|
||||
|
||||
new_insn = NULL;
|
||||
if (!special_alt->group || special_alt->new_len) {
|
||||
new_insn = find_insn(file, special_alt->new_sec,
|
||||
|
@ -719,6 +758,13 @@ static int add_special_section_alts(struct objtool_file *file)
|
|||
goto out;
|
||||
}
|
||||
|
||||
alt = malloc(sizeof(*alt));
|
||||
if (!alt) {
|
||||
WARN("malloc failed");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
alt->insn = new_insn;
|
||||
list_add_tail(&alt->list, &orig_insn->alts);
|
||||
|
||||
|
@ -1035,6 +1081,10 @@ static int decode_sections(struct objtool_file *file)
|
|||
|
||||
add_ignores(file);
|
||||
|
||||
ret = add_nospec_ignores(file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = add_jump_destinations(file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
@ -44,7 +44,7 @@ struct instruction {
|
|||
unsigned int len;
|
||||
unsigned char type;
|
||||
unsigned long immediate;
|
||||
bool alt_group, visited, dead_end, ignore, hint, save, restore;
|
||||
bool alt_group, visited, dead_end, ignore, hint, save, restore, ignore_alts;
|
||||
struct symbol *call_dest;
|
||||
struct instruction *jump_dest;
|
||||
struct list_head alts;
|
||||
|
|
Загрузка…
Ссылка в новой задаче