x86,objtool: Create .return_sites
commit d9e9d2300681d68a775c28de6aa6e5290ae17796 upstream. Find all the return-thunk sites and record them in a .return_sites section such that the kernel can undo this. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Borislav Petkov <bp@suse.de> Reviewed-by: Josh Poimboeuf <jpoimboe@kernel.org> Signed-off-by: Borislav Petkov <bp@suse.de> [cascardo: conflict fixup because of functions added to support IBT] Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com> [bwh: Backported to 5.10: adjust context] Signed-off-by: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
716410960b
commit
8bdb25f7ae
@@ -89,6 +89,7 @@ const char *arch_ret_insn(int len);
|
|||||||
int arch_decode_hint_reg(u8 sp_reg, int *base);
|
int arch_decode_hint_reg(u8 sp_reg, int *base);
|
||||||
|
|
||||||
bool arch_is_retpoline(struct symbol *sym);
|
bool arch_is_retpoline(struct symbol *sym);
|
||||||
|
bool arch_is_rethunk(struct symbol *sym);
|
||||||
|
|
||||||
int arch_rewrite_retpolines(struct objtool_file *file);
|
int arch_rewrite_retpolines(struct objtool_file *file);
|
||||||
|
|
||||||
|
@@ -649,3 +649,8 @@ bool arch_is_retpoline(struct symbol *sym)
|
|||||||
{
|
{
|
||||||
return !strncmp(sym->name, "__x86_indirect_", 15);
|
return !strncmp(sym->name, "__x86_indirect_", 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool arch_is_rethunk(struct symbol *sym)
|
||||||
|
{
|
||||||
|
return !strcmp(sym->name, "__x86_return_thunk");
|
||||||
|
}
|
||||||
|
@@ -653,6 +653,52 @@ static int create_retpoline_sites_sections(struct objtool_file *file)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int create_return_sites_sections(struct objtool_file *file)
|
||||||
|
{
|
||||||
|
struct instruction *insn;
|
||||||
|
struct section *sec;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
sec = find_section_by_name(file->elf, ".return_sites");
|
||||||
|
if (sec) {
|
||||||
|
WARN("file already has .return_sites, skipping");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = 0;
|
||||||
|
list_for_each_entry(insn, &file->return_thunk_list, call_node)
|
||||||
|
idx++;
|
||||||
|
|
||||||
|
if (!idx)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
sec = elf_create_section(file->elf, ".return_sites", 0,
|
||||||
|
sizeof(int), idx);
|
||||||
|
if (!sec) {
|
||||||
|
WARN("elf_create_section: .return_sites");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = 0;
|
||||||
|
list_for_each_entry(insn, &file->return_thunk_list, call_node) {
|
||||||
|
|
||||||
|
int *site = (int *)sec->data->d_buf + idx;
|
||||||
|
*site = 0;
|
||||||
|
|
||||||
|
if (elf_add_reloc_to_insn(file->elf, sec,
|
||||||
|
idx * sizeof(int),
|
||||||
|
R_X86_64_PC32,
|
||||||
|
insn->sec, insn->offset)) {
|
||||||
|
WARN("elf_add_reloc_to_insn: .return_sites");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Warnings shouldn't be reported for ignored functions.
|
* Warnings shouldn't be reported for ignored functions.
|
||||||
*/
|
*/
|
||||||
@@ -888,6 +934,11 @@ __weak bool arch_is_retpoline(struct symbol *sym)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__weak bool arch_is_rethunk(struct symbol *sym)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#define NEGATIVE_RELOC ((void *)-1L)
|
#define NEGATIVE_RELOC ((void *)-1L)
|
||||||
|
|
||||||
static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn)
|
static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn)
|
||||||
@@ -1029,6 +1080,19 @@ static void add_retpoline_call(struct objtool_file *file, struct instruction *in
|
|||||||
|
|
||||||
annotate_call_site(file, insn, false);
|
annotate_call_site(file, insn, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void add_return_call(struct objtool_file *file, struct instruction *insn)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Return thunk tail calls are really just returns in disguise,
|
||||||
|
* so convert them accordingly.
|
||||||
|
*/
|
||||||
|
insn->type = INSN_RETURN;
|
||||||
|
insn->retpoline_safe = true;
|
||||||
|
|
||||||
|
list_add_tail(&insn->call_node, &file->return_thunk_list);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the destination instructions for all jumps.
|
* Find the destination instructions for all jumps.
|
||||||
*/
|
*/
|
||||||
@@ -1053,6 +1117,9 @@ static int add_jump_destinations(struct objtool_file *file)
|
|||||||
} else if (reloc->sym->retpoline_thunk) {
|
} else if (reloc->sym->retpoline_thunk) {
|
||||||
add_retpoline_call(file, insn);
|
add_retpoline_call(file, insn);
|
||||||
continue;
|
continue;
|
||||||
|
} else if (reloc->sym->return_thunk) {
|
||||||
|
add_return_call(file, insn);
|
||||||
|
continue;
|
||||||
} else if (insn->func) {
|
} else if (insn->func) {
|
||||||
/* internal or external sibling call (with reloc) */
|
/* internal or external sibling call (with reloc) */
|
||||||
add_call_dest(file, insn, reloc->sym, true);
|
add_call_dest(file, insn, reloc->sym, true);
|
||||||
@@ -1842,6 +1909,9 @@ static int classify_symbols(struct objtool_file *file)
|
|||||||
if (arch_is_retpoline(func))
|
if (arch_is_retpoline(func))
|
||||||
func->retpoline_thunk = true;
|
func->retpoline_thunk = true;
|
||||||
|
|
||||||
|
if (arch_is_rethunk(func))
|
||||||
|
func->return_thunk = true;
|
||||||
|
|
||||||
if (!strcmp(func->name, "__fentry__"))
|
if (!strcmp(func->name, "__fentry__"))
|
||||||
func->fentry = true;
|
func->fentry = true;
|
||||||
|
|
||||||
@@ -3235,6 +3305,11 @@ int check(struct objtool_file *file)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
warnings += ret;
|
warnings += ret;
|
||||||
|
|
||||||
|
ret = create_return_sites_sections(file);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
warnings += ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stats) {
|
if (stats) {
|
||||||
|
@@ -58,6 +58,7 @@ struct symbol {
|
|||||||
u8 uaccess_safe : 1;
|
u8 uaccess_safe : 1;
|
||||||
u8 static_call_tramp : 1;
|
u8 static_call_tramp : 1;
|
||||||
u8 retpoline_thunk : 1;
|
u8 retpoline_thunk : 1;
|
||||||
|
u8 return_thunk : 1;
|
||||||
u8 fentry : 1;
|
u8 fentry : 1;
|
||||||
u8 kcov : 1;
|
u8 kcov : 1;
|
||||||
};
|
};
|
||||||
|
@@ -62,6 +62,7 @@ struct objtool_file *objtool_open_read(const char *_objname)
|
|||||||
INIT_LIST_HEAD(&file.insn_list);
|
INIT_LIST_HEAD(&file.insn_list);
|
||||||
hash_init(file.insn_hash);
|
hash_init(file.insn_hash);
|
||||||
INIT_LIST_HEAD(&file.retpoline_call_list);
|
INIT_LIST_HEAD(&file.retpoline_call_list);
|
||||||
|
INIT_LIST_HEAD(&file.return_thunk_list);
|
||||||
INIT_LIST_HEAD(&file.static_call_list);
|
INIT_LIST_HEAD(&file.static_call_list);
|
||||||
file.c_file = !vmlinux && find_section_by_name(file.elf, ".comment");
|
file.c_file = !vmlinux && find_section_by_name(file.elf, ".comment");
|
||||||
file.ignore_unreachables = no_unreachable;
|
file.ignore_unreachables = no_unreachable;
|
||||||
|
@@ -19,6 +19,7 @@ struct objtool_file {
|
|||||||
struct list_head insn_list;
|
struct list_head insn_list;
|
||||||
DECLARE_HASHTABLE(insn_hash, 20);
|
DECLARE_HASHTABLE(insn_hash, 20);
|
||||||
struct list_head retpoline_call_list;
|
struct list_head retpoline_call_list;
|
||||||
|
struct list_head return_thunk_list;
|
||||||
struct list_head static_call_list;
|
struct list_head static_call_list;
|
||||||
bool ignore_unreachables, c_file, hints, rodata;
|
bool ignore_unreachables, c_file, hints, rodata;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user