x86,objtool: Create .return_sites

commit d9e9d23006 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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Peter Zijlstra 2022-06-14 23:15:38 +02:00 коммит произвёл Greg Kroah-Hartman
Родитель 7bf553d9ee
Коммит 1920e4be8a
6 изменённых файлов: 84 добавлений и 0 удалений

Просмотреть файл

@ -722,3 +722,8 @@ bool arch_is_retpoline(struct symbol *sym)
{
return !strncmp(sym->name, "__x86_indirect_", 15);
}
bool arch_is_rethunk(struct symbol *sym)
{
return !strcmp(sym->name, "__x86_return_thunk");
}

Просмотреть файл

@ -654,6 +654,52 @@ static int create_retpoline_sites_sections(struct objtool_file *file)
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;
}
static int create_mcount_loc_sections(struct objtool_file *file)
{
struct section *sec;
@ -932,6 +978,11 @@ __weak bool arch_is_retpoline(struct symbol *sym)
return false;
}
__weak bool arch_is_rethunk(struct symbol *sym)
{
return false;
}
#define NEGATIVE_RELOC ((void *)-1L)
static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn)
@ -1092,6 +1143,19 @@ static void add_retpoline_call(struct objtool_file *file, struct instruction *in
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.
*/
@ -1116,6 +1180,9 @@ static int add_jump_destinations(struct objtool_file *file)
} else if (reloc->sym->retpoline_thunk) {
add_retpoline_call(file, insn);
continue;
} else if (reloc->sym->return_thunk) {
add_return_call(file, insn);
continue;
} else if (insn->func) {
/* internal or external sibling call (with reloc) */
add_call_dest(file, insn, reloc->sym, true);
@ -1937,6 +2004,9 @@ static int classify_symbols(struct objtool_file *file)
if (arch_is_retpoline(func))
func->retpoline_thunk = true;
if (arch_is_rethunk(func))
func->return_thunk = true;
if (!strcmp(func->name, "__fentry__"))
func->fentry = true;
@ -3413,6 +3483,11 @@ int check(struct objtool_file *file)
if (ret < 0)
goto out;
warnings += ret;
ret = create_return_sites_sections(file);
if (ret < 0)
goto out;
warnings += ret;
}
if (mcount) {

Просмотреть файл

@ -88,6 +88,7 @@ const char *arch_ret_insn(int len);
int arch_decode_hint_reg(u8 sp_reg, int *base);
bool arch_is_retpoline(struct symbol *sym);
bool arch_is_rethunk(struct symbol *sym);
int arch_rewrite_retpolines(struct objtool_file *file);

Просмотреть файл

@ -57,6 +57,7 @@ struct symbol {
u8 uaccess_safe : 1;
u8 static_call_tramp : 1;
u8 retpoline_thunk : 1;
u8 return_thunk : 1;
u8 fentry : 1;
u8 kcov : 1;
};

Просмотреть файл

@ -19,6 +19,7 @@ struct objtool_file {
struct list_head insn_list;
DECLARE_HASHTABLE(insn_hash, 20);
struct list_head retpoline_call_list;
struct list_head return_thunk_list;
struct list_head static_call_list;
struct list_head mcount_loc_list;
bool ignore_unreachables, c_file, hints, rodata;

Просмотреть файл

@ -126,6 +126,7 @@ struct objtool_file *objtool_open_read(const char *_objname)
INIT_LIST_HEAD(&file.insn_list);
hash_init(file.insn_hash);
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.mcount_loc_list);
file.c_file = !vmlinux && find_section_by_name(file.elf, ".comment");