Merge tag 'v5.7-rc1' into locking/kcsan, to resolve conflicts and refresh

Resolve these conflicts:

	arch/x86/Kconfig
	arch/x86/kernel/Makefile

Do a minor "evil merge" to move the KCSAN entry up a bit by a few lines
in the Kconfig to reduce the probability of future conflicts.

Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Ingo Molnar
2020-04-13 09:44:39 +02:00
10808 changed files with 507021 additions and 241301 deletions

View File

@@ -72,22 +72,22 @@ static struct instruction *next_insn_same_func(struct objtool_file *file,
return find_insn(file, func->cfunc->sec, func->cfunc->offset);
}
#define func_for_each_insn_all(file, func, insn) \
#define func_for_each_insn(file, func, insn) \
for (insn = find_insn(file, func->sec, func->offset); \
insn; \
insn = next_insn_same_func(file, insn))
#define func_for_each_insn(file, func, insn) \
for (insn = find_insn(file, func->sec, func->offset); \
#define sym_for_each_insn(file, sym, insn) \
for (insn = find_insn(file, sym->sec, sym->offset); \
insn && &insn->list != &file->insn_list && \
insn->sec == func->sec && \
insn->offset < func->offset + func->len; \
insn->sec == sym->sec && \
insn->offset < sym->offset + sym->len; \
insn = list_next_entry(insn, list))
#define func_for_each_insn_continue_reverse(file, func, insn) \
#define sym_for_each_insn_continue_reverse(file, sym, insn) \
for (insn = list_prev_entry(insn, list); \
&insn->list != &file->insn_list && \
insn->sec == func->sec && insn->offset >= func->offset; \
insn->sec == sym->sec && insn->offset >= sym->offset; \
insn = list_prev_entry(insn, list))
#define sec_for_each_insn_from(file, insn) \
@@ -97,14 +97,19 @@ static struct instruction *next_insn_same_func(struct objtool_file *file,
for (insn = next_insn_same_sec(file, insn); insn; \
insn = next_insn_same_sec(file, insn))
static bool is_static_jump(struct instruction *insn)
{
return insn->type == INSN_JUMP_CONDITIONAL ||
insn->type == INSN_JUMP_UNCONDITIONAL;
}
static bool is_sibling_call(struct instruction *insn)
{
/* An indirect jump is either a sibling call or a jump to a table. */
if (insn->type == INSN_JUMP_DYNAMIC)
return list_empty(&insn->alts);
if (insn->type != INSN_JUMP_CONDITIONAL &&
insn->type != INSN_JUMP_UNCONDITIONAL)
if (!is_static_jump(insn))
return false;
/* add_jump_destinations() sets insn->call_dest for sibling calls. */
@@ -165,7 +170,7 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
if (!insn->func)
return false;
func_for_each_insn_all(file, func, insn) {
func_for_each_insn(file, func, insn) {
empty = false;
if (insn->type == INSN_RETURN)
@@ -180,7 +185,7 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
* case, the function's dead-end status depends on whether the target
* of the sibling call returns.
*/
func_for_each_insn_all(file, func, insn) {
func_for_each_insn(file, func, insn) {
if (is_sibling_call(insn)) {
struct instruction *dest = insn->jump_dest;
@@ -234,6 +239,7 @@ static int decode_instructions(struct objtool_file *file)
struct symbol *func;
unsigned long offset;
struct instruction *insn;
unsigned long nr_insns = 0;
int ret;
for_each_sec(file, sec) {
@@ -269,6 +275,7 @@ static int decode_instructions(struct objtool_file *file)
hash_add(file->insn_hash, &insn->hash, insn->offset);
list_add_tail(&insn->list, &file->insn_list);
nr_insns++;
}
list_for_each_entry(func, &sec->symbol_list, list) {
@@ -281,11 +288,14 @@ static int decode_instructions(struct objtool_file *file)
return -1;
}
func_for_each_insn(file, func, insn)
sym_for_each_insn(file, func, insn)
insn->func = func;
}
}
if (stats)
printf("nr_insns: %lu\n", nr_insns);
return 0;
err:
@@ -415,8 +425,8 @@ static void add_ignores(struct objtool_file *file)
break;
case STT_SECTION:
func = find_symbol_by_offset(rela->sym->sec, rela->addend);
if (!func || func->type != STT_FUNC)
func = find_func_by_offset(rela->sym->sec, rela->addend);
if (!func)
continue;
break;
@@ -425,7 +435,7 @@ static void add_ignores(struct objtool_file *file)
continue;
}
func_for_each_insn_all(file, func, insn)
func_for_each_insn(file, func, insn)
insn->ignore = true;
}
}
@@ -496,6 +506,7 @@ static const char *uaccess_safe_builtin[] = {
"__sanitizer_cov_trace_cmp2",
"__sanitizer_cov_trace_cmp4",
"__sanitizer_cov_trace_cmp8",
"__sanitizer_cov_trace_switch",
/* UBSAN */
"ubsan_type_mismatch_common",
"__ubsan_handle_type_mismatch",
@@ -571,15 +582,14 @@ static int add_jump_destinations(struct objtool_file *file)
unsigned long dest_off;
for_each_insn(file, insn) {
if (insn->type != INSN_JUMP_CONDITIONAL &&
insn->type != INSN_JUMP_UNCONDITIONAL)
if (!is_static_jump(insn))
continue;
if (insn->ignore || insn->offset == FAKE_JUMP_OFFSET)
continue;
rela = find_rela_by_dest_range(insn->sec, insn->offset,
insn->len);
rela = find_rela_by_dest_range(file->elf, insn->sec,
insn->offset, insn->len);
if (!rela) {
dest_sec = insn->sec;
dest_off = insn->offset + insn->len + insn->immediate;
@@ -675,14 +685,18 @@ static int add_call_destinations(struct objtool_file *file)
if (insn->type != INSN_CALL)
continue;
rela = find_rela_by_dest_range(insn->sec, insn->offset,
insn->len);
rela = find_rela_by_dest_range(file->elf, insn->sec,
insn->offset, insn->len);
if (!rela) {
dest_off = insn->offset + insn->len + insn->immediate;
insn->call_dest = find_symbol_by_offset(insn->sec,
dest_off);
insn->call_dest = find_func_by_offset(insn->sec, dest_off);
if (!insn->call_dest)
insn->call_dest = find_symbol_by_offset(insn->sec, dest_off);
if (!insn->call_dest && !insn->ignore) {
if (insn->ignore)
continue;
if (!insn->call_dest) {
WARN_FUNC("unsupported intra-function call",
insn->sec, insn->offset);
if (retpoline)
@@ -690,11 +704,16 @@ static int add_call_destinations(struct objtool_file *file)
return -1;
}
if (insn->func && insn->call_dest->type != STT_FUNC) {
WARN_FUNC("unsupported call to non-function",
insn->sec, insn->offset);
return -1;
}
} else if (rela->sym->type == STT_SECTION) {
insn->call_dest = find_symbol_by_offset(rela->sym->sec,
rela->addend+4);
if (!insn->call_dest ||
insn->call_dest->type != STT_FUNC) {
insn->call_dest = find_func_by_offset(rela->sym->sec,
rela->addend+4);
if (!insn->call_dest) {
WARN_FUNC("can't find call dest symbol at %s+0x%x",
insn->sec, insn->offset,
rela->sym->sec->name,
@@ -782,8 +801,28 @@ static int handle_group_alt(struct objtool_file *file,
insn->ignore = orig_insn->ignore_alts;
insn->func = orig_insn->func;
if (insn->type != INSN_JUMP_CONDITIONAL &&
insn->type != INSN_JUMP_UNCONDITIONAL)
/*
* Since alternative replacement code is copy/pasted by the
* kernel after applying relocations, generally such code can't
* have relative-address relocation references to outside the
* .altinstr_replacement section, unless the arch's
* alternatives code can adjust the relative offsets
* accordingly.
*
* The x86 alternatives code adjusts the offsets only when it
* encounters a branch instruction at the very beginning of the
* replacement group.
*/
if ((insn->offset != special_alt->new_off ||
(insn->type != INSN_CALL && !is_static_jump(insn))) &&
find_rela_by_dest_range(file->elf, insn->sec, insn->offset, insn->len)) {
WARN_FUNC("unsupported relocation in alternatives section",
insn->sec, insn->offset);
return -1;
}
if (!is_static_jump(insn))
continue;
if (!insn->immediate)
@@ -1019,7 +1058,7 @@ static struct rela *find_jump_table(struct objtool_file *file,
struct instruction *insn)
{
struct rela *text_rela, *table_rela;
struct instruction *orig_insn = insn;
struct instruction *dest_insn, *orig_insn = insn;
struct section *table_sec;
unsigned long table_offset;
@@ -1046,8 +1085,8 @@ static struct rela *find_jump_table(struct objtool_file *file,
break;
/* look for a relocation which references .rodata */
text_rela = find_rela_by_dest_range(insn->sec, insn->offset,
insn->len);
text_rela = find_rela_by_dest_range(file->elf, insn->sec,
insn->offset, insn->len);
if (!text_rela || text_rela->sym->type != STT_SECTION ||
!text_rela->sym->sec->rodata)
continue;
@@ -1071,10 +1110,17 @@ static struct rela *find_jump_table(struct objtool_file *file,
strcmp(table_sec->name, C_JUMP_TABLE_SECTION))
continue;
/* Each table entry has a rela associated with it. */
table_rela = find_rela_by_dest(table_sec, table_offset);
/*
* Each table entry has a rela associated with it. The rela
* should reference text in the same function as the original
* instruction.
*/
table_rela = find_rela_by_dest(file->elf, table_sec, table_offset);
if (!table_rela)
continue;
dest_insn = find_insn(file, table_rela->sym->sec, table_rela->addend);
if (!dest_insn || !dest_insn->func || dest_insn->func->pfunc != func)
continue;
/*
* Use of RIP-relative switch jumps is quite rare, and
@@ -1100,7 +1146,7 @@ static void mark_func_jump_tables(struct objtool_file *file,
struct instruction *insn, *last = NULL;
struct rela *rela;
func_for_each_insn_all(file, func, insn) {
func_for_each_insn(file, func, insn) {
if (!last)
last = insn;
@@ -1135,7 +1181,7 @@ static int add_func_jump_tables(struct objtool_file *file,
struct instruction *insn;
int ret;
func_for_each_insn_all(file, func, insn) {
func_for_each_insn(file, func, insn) {
if (!insn->jump_table)
continue;
@@ -1205,7 +1251,7 @@ static int read_unwind_hints(struct objtool_file *file)
for (i = 0; i < sec->len / sizeof(struct unwind_hint); i++) {
hint = (struct unwind_hint *)sec->data->d_buf + i;
rela = find_rela_by_dest(sec, i * sizeof(*hint));
rela = find_rela_by_dest(file->elf, sec, i * sizeof(*hint));
if (!rela) {
WARN("can't find rela for unwind_hints[%d]", i);
return -1;
@@ -1953,6 +1999,41 @@ static int validate_sibling_call(struct instruction *insn, struct insn_state *st
return validate_call(insn, state);
}
static int validate_return(struct symbol *func, struct instruction *insn, struct insn_state *state)
{
if (state->uaccess && !func_uaccess_safe(func)) {
WARN_FUNC("return with UACCESS enabled",
insn->sec, insn->offset);
return 1;
}
if (!state->uaccess && func_uaccess_safe(func)) {
WARN_FUNC("return with UACCESS disabled from a UACCESS-safe function",
insn->sec, insn->offset);
return 1;
}
if (state->df) {
WARN_FUNC("return with DF set",
insn->sec, insn->offset);
return 1;
}
if (func && has_modified_stack_frame(state)) {
WARN_FUNC("return with modified stack frame",
insn->sec, insn->offset);
return 1;
}
if (state->bp_scratch) {
WARN("%s uses BP as a scratch register",
func->name);
return 1;
}
return 0;
}
/*
* Follow the branch starting at the given instruction, and recursively follow
* any other branches (jumps). Meanwhile, track the frame pointer state at
@@ -2007,7 +2088,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
i = insn;
save_insn = NULL;
func_for_each_insn_continue_reverse(file, func, i) {
sym_for_each_insn_continue_reverse(file, func, i) {
if (i->save) {
save_insn = i;
break;
@@ -2068,34 +2149,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
switch (insn->type) {
case INSN_RETURN:
if (state.uaccess && !func_uaccess_safe(func)) {
WARN_FUNC("return with UACCESS enabled", sec, insn->offset);
return 1;
}
if (!state.uaccess && func_uaccess_safe(func)) {
WARN_FUNC("return with UACCESS disabled from a UACCESS-safe function", sec, insn->offset);
return 1;
}
if (state.df) {
WARN_FUNC("return with DF set", sec, insn->offset);
return 1;
}
if (func && has_modified_stack_frame(&state)) {
WARN_FUNC("return with modified stack frame",
sec, insn->offset);
return 1;
}
if (state.bp_scratch) {
WARN("%s uses BP as a scratch register",
func->name);
return 1;
}
return 0;
return validate_return(func, insn, &state);
case INSN_CALL:
case INSN_CALL_DYNAMIC:
@@ -2360,9 +2414,8 @@ static bool ignore_unreachable_insn(struct instruction *insn)
return false;
}
static int validate_functions(struct objtool_file *file)
static int validate_section(struct objtool_file *file, struct section *sec)
{
struct section *sec;
struct symbol *func;
struct instruction *insn;
struct insn_state state;
@@ -2375,36 +2428,45 @@ static int validate_functions(struct objtool_file *file)
CFI_NUM_REGS * sizeof(struct cfi_reg));
state.stack_size = initial_func_cfi.cfa.offset;
for_each_sec(file, sec) {
list_for_each_entry(func, &sec->symbol_list, list) {
if (func->type != STT_FUNC)
continue;
list_for_each_entry(func, &sec->symbol_list, list) {
if (func->type != STT_FUNC)
continue;
if (!func->len) {
WARN("%s() is missing an ELF size annotation",
func->name);
warnings++;
}
if (func->pfunc != func || func->alias != func)
continue;
insn = find_insn(file, sec, func->offset);
if (!insn || insn->ignore || insn->visited)
continue;
state.uaccess = func->uaccess_safe;
ret = validate_branch(file, func, insn, state);
if (ret && backtrace)
BT_FUNC("<=== (func)", insn);
warnings += ret;
if (!func->len) {
WARN("%s() is missing an ELF size annotation",
func->name);
warnings++;
}
if (func->pfunc != func || func->alias != func)
continue;
insn = find_insn(file, sec, func->offset);
if (!insn || insn->ignore || insn->visited)
continue;
state.uaccess = func->uaccess_safe;
ret = validate_branch(file, func, insn, state);
if (ret && backtrace)
BT_FUNC("<=== (func)", insn);
warnings += ret;
}
return warnings;
}
static int validate_functions(struct objtool_file *file)
{
struct section *sec;
int warnings = 0;
for_each_sec(file, sec)
warnings += validate_section(file, sec);
return warnings;
}
static int validate_reachable_instructions(struct objtool_file *file)
{
struct instruction *insn;
@@ -2423,23 +2485,6 @@ static int validate_reachable_instructions(struct objtool_file *file)
return 0;
}
static void cleanup(struct objtool_file *file)
{
struct instruction *insn, *tmpinsn;
struct alternative *alt, *tmpalt;
list_for_each_entry_safe(insn, tmpinsn, &file->insn_list, list) {
list_for_each_entry_safe(alt, tmpalt, &insn->alts, list) {
list_del(&alt->list);
free(alt);
}
list_del(&insn->list);
hash_del(&insn->hash);
free(insn);
}
elf_close(file->elf);
}
static struct objtool_file file;
int check(const char *_objname, bool orc)
@@ -2507,10 +2552,14 @@ int check(const char *_objname, bool orc)
}
out:
cleanup(&file);
if (ret < 0) {
/*
* Fatal error. The binary is corrupt or otherwise broken in
* some way, or objtool itself is broken. Fail the kernel
* build.
*/
return ret;
}
/* ignore warnings for now until we get all the code cleaned up */
if (ret || warnings)
return 0;
return 0;
}