Commit d9e9d230 authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Borislav Petkov
Browse files

x86,objtool: Create .return_sites



Find all the return-thunk sites and record them in a .return_sites
section such that the kernel can undo this.

Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Reviewed-by: default avatarJosh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
parent 15e67227
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -787,3 +787,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");
}
+74 −0
Original line number Diff line number Diff line
@@ -749,6 +749,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_ibt_endbr_seal_sections(struct objtool_file *file)
{
	struct instruction *insn;
@@ -1083,6 +1129,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)
@@ -1250,6 +1301,18 @@ 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);
}

static bool same_function(struct instruction *insn1, struct instruction *insn2)
{
	return insn1->func->pfunc == insn2->func->pfunc;
@@ -1302,6 +1365,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) {
			/*
			 * External sibling call or internal sibling call with
@@ -2184,6 +2250,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;

@@ -3972,6 +4041,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 (opts.mcount) {
+1 −0
Original line number Diff line number Diff line
@@ -89,6 +89,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);

+1 −0
Original line number Diff line number Diff line
@@ -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 profiling_func    : 1;
	struct list_head pv_target;
+1 −0
Original line number Diff line number Diff line
@@ -24,6 +24,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;
	struct list_head endbr_list;
Loading