Merge branch 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull objtool fixes from Ingo Molnar: "A handful of objtool fixes related to unreachable code, plus a build fix for out of tree modules" * 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: objtool: Enclose contents of unreachable() macro in a block objtool: Prevent GCC from merging annotate_unreachable() objtool: Improve detection of BUG() and other dead ends objtool: Fix CONFIG_STACK_VALIDATION=y warning for out-of-tree modules
This commit is contained in:
24
Makefile
24
Makefile
@@ -910,6 +910,18 @@ mod_sign_cmd = true
|
|||||||
endif
|
endif
|
||||||
export mod_sign_cmd
|
export mod_sign_cmd
|
||||||
|
|
||||||
|
ifdef CONFIG_STACK_VALIDATION
|
||||||
|
has_libelf := $(call try-run,\
|
||||||
|
echo "int main() {}" | $(HOSTCC) -xc -o /dev/null -lelf -,1,0)
|
||||||
|
ifeq ($(has_libelf),1)
|
||||||
|
objtool_target := tools/objtool FORCE
|
||||||
|
else
|
||||||
|
$(warning "Cannot use CONFIG_STACK_VALIDATION, please install libelf-dev, libelf-devel or elfutils-libelf-devel")
|
||||||
|
SKIP_STACK_VALIDATION := 1
|
||||||
|
export SKIP_STACK_VALIDATION
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
ifeq ($(KBUILD_EXTMOD),)
|
ifeq ($(KBUILD_EXTMOD),)
|
||||||
core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/
|
core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/
|
||||||
@@ -1037,18 +1049,6 @@ prepare0: archprepare gcc-plugins
|
|||||||
# All the preparing..
|
# All the preparing..
|
||||||
prepare: prepare0 prepare-objtool
|
prepare: prepare0 prepare-objtool
|
||||||
|
|
||||||
ifdef CONFIG_STACK_VALIDATION
|
|
||||||
has_libelf := $(call try-run,\
|
|
||||||
echo "int main() {}" | $(HOSTCC) -xc -o /dev/null -lelf -,1,0)
|
|
||||||
ifeq ($(has_libelf),1)
|
|
||||||
objtool_target := tools/objtool FORCE
|
|
||||||
else
|
|
||||||
$(warning "Cannot use CONFIG_STACK_VALIDATION, please install libelf-dev, libelf-devel or elfutils-libelf-devel")
|
|
||||||
SKIP_STACK_VALIDATION := 1
|
|
||||||
export SKIP_STACK_VALIDATION
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
PHONY += prepare-objtool
|
PHONY += prepare-objtool
|
||||||
prepare-objtool: $(objtool_target)
|
prepare-objtool: $(objtool_target)
|
||||||
|
|
||||||
|
|||||||
@@ -346,6 +346,7 @@ SECTIONS
|
|||||||
/DISCARD/ : {
|
/DISCARD/ : {
|
||||||
*(.eh_frame)
|
*(.eh_frame)
|
||||||
*(__func_stack_frame_non_standard)
|
*(__func_stack_frame_non_standard)
|
||||||
|
*(__unreachable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -197,6 +197,17 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_STACK_VALIDATION
|
||||||
|
#define annotate_unreachable() ({ \
|
||||||
|
asm("%c0:\t\n" \
|
||||||
|
".pushsection __unreachable, \"a\"\t\n" \
|
||||||
|
".long %c0b\t\n" \
|
||||||
|
".popsection\t\n" : : "i" (__LINE__)); \
|
||||||
|
})
|
||||||
|
#else
|
||||||
|
#define annotate_unreachable()
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mark a position in code as unreachable. This can be used to
|
* Mark a position in code as unreachable. This can be used to
|
||||||
* suppress control flow warnings after asm blocks that transfer
|
* suppress control flow warnings after asm blocks that transfer
|
||||||
@@ -206,7 +217,8 @@
|
|||||||
* this in the preprocessor, but we can live with this because they're
|
* this in the preprocessor, but we can live with this because they're
|
||||||
* unreleased. Really, we need to have autoconf for the kernel.
|
* unreleased. Really, we need to have autoconf for the kernel.
|
||||||
*/
|
*/
|
||||||
#define unreachable() __builtin_unreachable()
|
#define unreachable() \
|
||||||
|
do { annotate_unreachable(); __builtin_unreachable(); } while (0)
|
||||||
|
|
||||||
/* Mark a function definition as prohibited from being cloned. */
|
/* Mark a function definition as prohibited from being cloned. */
|
||||||
#define __noclone __attribute__((__noclone__, __optimize__("no-tracer")))
|
#define __noclone __attribute__((__noclone__, __optimize__("no-tracer")))
|
||||||
|
|||||||
@@ -31,9 +31,8 @@
|
|||||||
#define INSN_CALL_DYNAMIC 8
|
#define INSN_CALL_DYNAMIC 8
|
||||||
#define INSN_RETURN 9
|
#define INSN_RETURN 9
|
||||||
#define INSN_CONTEXT_SWITCH 10
|
#define INSN_CONTEXT_SWITCH 10
|
||||||
#define INSN_BUG 11
|
#define INSN_NOP 11
|
||||||
#define INSN_NOP 12
|
#define INSN_OTHER 12
|
||||||
#define INSN_OTHER 13
|
|
||||||
#define INSN_LAST INSN_OTHER
|
#define INSN_LAST INSN_OTHER
|
||||||
|
|
||||||
int arch_decode_instruction(struct elf *elf, struct section *sec,
|
int arch_decode_instruction(struct elf *elf, struct section *sec,
|
||||||
|
|||||||
@@ -118,9 +118,6 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
|
|||||||
op2 == 0x35)
|
op2 == 0x35)
|
||||||
/* sysenter, sysret */
|
/* sysenter, sysret */
|
||||||
*type = INSN_CONTEXT_SWITCH;
|
*type = INSN_CONTEXT_SWITCH;
|
||||||
else if (op2 == 0x0b || op2 == 0xb9)
|
|
||||||
/* ud2 */
|
|
||||||
*type = INSN_BUG;
|
|
||||||
else if (op2 == 0x0d || op2 == 0x1f)
|
else if (op2 == 0x0d || op2 == 0x1f)
|
||||||
/* nopl/nopw */
|
/* nopl/nopw */
|
||||||
*type = INSN_NOP;
|
*type = INSN_NOP;
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ struct instruction {
|
|||||||
unsigned int len, state;
|
unsigned int len, state;
|
||||||
unsigned char type;
|
unsigned char type;
|
||||||
unsigned long immediate;
|
unsigned long immediate;
|
||||||
bool alt_group, visited;
|
bool alt_group, visited, dead_end;
|
||||||
struct symbol *call_dest;
|
struct symbol *call_dest;
|
||||||
struct instruction *jump_dest;
|
struct instruction *jump_dest;
|
||||||
struct list_head alts;
|
struct list_head alts;
|
||||||
@@ -329,6 +329,54 @@ static int decode_instructions(struct objtool_file *file)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find all uses of the unreachable() macro, which are code path dead ends.
|
||||||
|
*/
|
||||||
|
static int add_dead_ends(struct objtool_file *file)
|
||||||
|
{
|
||||||
|
struct section *sec;
|
||||||
|
struct rela *rela;
|
||||||
|
struct instruction *insn;
|
||||||
|
bool found;
|
||||||
|
|
||||||
|
sec = find_section_by_name(file->elf, ".rela__unreachable");
|
||||||
|
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 .rela__unreachable");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
insn = find_insn(file, rela->sym->sec, rela->addend);
|
||||||
|
if (insn)
|
||||||
|
insn = list_prev_entry(insn, list);
|
||||||
|
else if (rela->addend == rela->sym->sec->len) {
|
||||||
|
found = false;
|
||||||
|
list_for_each_entry_reverse(insn, &file->insn_list, list) {
|
||||||
|
if (insn->sec == rela->sym->sec) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
WARN("can't find unreachable insn at %s+0x%x",
|
||||||
|
rela->sym->sec->name, rela->addend);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
WARN("can't find unreachable insn at %s+0x%x",
|
||||||
|
rela->sym->sec->name, rela->addend);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
insn->dead_end = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Warnings shouldn't be reported for ignored functions.
|
* Warnings shouldn't be reported for ignored functions.
|
||||||
*/
|
*/
|
||||||
@@ -843,6 +891,10 @@ static int decode_sections(struct objtool_file *file)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
ret = add_dead_ends(file);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
add_ignores(file);
|
add_ignores(file);
|
||||||
|
|
||||||
ret = add_jump_destinations(file);
|
ret = add_jump_destinations(file);
|
||||||
@@ -1037,13 +1089,13 @@ static int validate_branch(struct objtool_file *file,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case INSN_BUG:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (insn->dead_end)
|
||||||
|
return 0;
|
||||||
|
|
||||||
insn = next_insn_same_sec(file, insn);
|
insn = next_insn_same_sec(file, insn);
|
||||||
if (!insn) {
|
if (!insn) {
|
||||||
WARN("%s: unexpected end of section", sec->name);
|
WARN("%s: unexpected end of section", sec->name);
|
||||||
|
|||||||
Reference in New Issue
Block a user