diff options
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.9.21/0086-objtool-Improve-detection-of-BUG-and-other-dead-ends.patch')
-rw-r--r-- | common/recipes-kernel/linux/linux-yocto-4.9.21/0086-objtool-Improve-detection-of-BUG-and-other-dead-ends.patch | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.9.21/0086-objtool-Improve-detection-of-BUG-and-other-dead-ends.patch b/common/recipes-kernel/linux/linux-yocto-4.9.21/0086-objtool-Improve-detection-of-BUG-and-other-dead-ends.patch new file mode 100644 index 00000000..f659e885 --- /dev/null +++ b/common/recipes-kernel/linux/linux-yocto-4.9.21/0086-objtool-Improve-detection-of-BUG-and-other-dead-ends.patch @@ -0,0 +1,217 @@ +From 655125acee5c084743a8bae4ffe2b723856594ce Mon Sep 17 00:00:00 2001 +From: Josh Poimboeuf <jpoimboe@redhat.com> +Date: Tue, 21 Feb 2017 15:35:32 -0600 +Subject: [PATCH 86/93] objtool: Improve detection of BUG() and other dead ends + +commit d1091c7fa3d52ebce4dd3f15d04155b3469b2f90 upstream. + +The BUG() macro's use of __builtin_unreachable() via the unreachable() +macro tells gcc that the instruction is a dead end, and that it's safe +to assume the current code path will not execute past the previous +instruction. + +On x86, the BUG() macro is implemented with the 'ud2' instruction. When +objtool's branch analysis sees that instruction, it knows the current +code path has come to a dead end. + +Peter Zijlstra has been working on a patch to change the WARN macros to +use 'ud2'. That patch will break objtool's assumption that 'ud2' is +always a dead end. + +Generally it's best for objtool to avoid making those kinds of +assumptions anyway. The more ignorant it is of kernel code internals, +the better. + +So create a more generic way for objtool to detect dead ends by adding +an annotation to the unreachable() macro. The annotation stores a +pointer to the end of the unreachable code path in an '__unreachable' +section. Objtool can read that section to find the dead ends. + +Tested-by: Peter Zijlstra (Intel) <peterz@infradead.org> +Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> +Cc: Linus Torvalds <torvalds@linux-foundation.org> +Cc: Peter Zijlstra <peterz@infradead.org> +Cc: Thomas Gleixner <tglx@linutronix.de> +Link: http://lkml.kernel.org/r/41a6d33971462ebd944a1c60ad4bf5be86c17b77.1487712920.git.jpoimboe@redhat.com +Signed-off-by: Ingo Molnar <mingo@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + arch/x86/kernel/vmlinux.lds.S | 1 + + include/linux/compiler-gcc.h | 13 ++++++++- + tools/objtool/arch.h | 5 ++-- + tools/objtool/arch/x86/decode.c | 3 --- + tools/objtool/builtin-check.c | 60 ++++++++++++++++++++++++++++++++++++++--- + 5 files changed, 71 insertions(+), 11 deletions(-) + +diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S +index c7194e9..4ef267f 100644 +--- a/arch/x86/kernel/vmlinux.lds.S ++++ b/arch/x86/kernel/vmlinux.lds.S +@@ -353,6 +353,7 @@ SECTIONS + /DISCARD/ : { + *(.eh_frame) + *(__func_stack_frame_non_standard) ++ *(__unreachable) + } + } + +diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h +index 362a1e17..b69d102 100644 +--- a/include/linux/compiler-gcc.h ++++ b/include/linux/compiler-gcc.h +@@ -199,6 +199,17 @@ + #endif + #endif + ++#ifdef CONFIG_STACK_VALIDATION ++#define annotate_unreachable() ({ \ ++ asm("1:\t\n" \ ++ ".pushsection __unreachable, \"a\"\t\n" \ ++ ".long 1b\t\n" \ ++ ".popsection\t\n"); \ ++}) ++#else ++#define annotate_unreachable() ++#endif ++ + /* + * Mark a position in code as unreachable. This can be used to + * suppress control flow warnings after asm blocks that transfer +@@ -208,7 +219,7 @@ + * this in the preprocessor, but we can live with this because they're + * unreleased. Really, we need to have autoconf for the kernel. + */ +-#define unreachable() __builtin_unreachable() ++#define unreachable() annotate_unreachable(); __builtin_unreachable() + + /* Mark a function definition as prohibited from being cloned. */ + #define __noclone __attribute__((__noclone__, __optimize__("no-tracer"))) +diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h +index f7350fc..a59e061 100644 +--- a/tools/objtool/arch.h ++++ b/tools/objtool/arch.h +@@ -31,9 +31,8 @@ + #define INSN_CALL_DYNAMIC 8 + #define INSN_RETURN 9 + #define INSN_CONTEXT_SWITCH 10 +-#define INSN_BUG 11 +-#define INSN_NOP 12 +-#define INSN_OTHER 13 ++#define INSN_NOP 11 ++#define INSN_OTHER 12 + #define INSN_LAST INSN_OTHER + + int arch_decode_instruction(struct elf *elf, struct section *sec, +diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c +index 5e0dea2..9fb487f 100644 +--- a/tools/objtool/arch/x86/decode.c ++++ b/tools/objtool/arch/x86/decode.c +@@ -118,9 +118,6 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, + op2 == 0x35) + /* sysenter, sysret */ + *type = INSN_CONTEXT_SWITCH; +- else if (op2 == 0x0b || op2 == 0xb9) +- /* ud2 */ +- *type = INSN_BUG; + else if (op2 == 0x0d || op2 == 0x1f) + /* nopl/nopw */ + *type = INSN_NOP; +diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c +index 377bff0..ad9eda9 100644 +--- a/tools/objtool/builtin-check.c ++++ b/tools/objtool/builtin-check.c +@@ -51,7 +51,7 @@ struct instruction { + unsigned int len, state; + unsigned char type; + unsigned long immediate; +- bool alt_group, visited, ignore_alts; ++ bool alt_group, visited, dead_end, ignore_alts; + struct symbol *call_dest; + struct instruction *jump_dest; + struct list_head alts; +@@ -330,6 +330,54 @@ static int decode_instructions(struct objtool_file *file) + } + + /* ++ * 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. + */ + static void add_ignores(struct objtool_file *file) +@@ -896,6 +944,10 @@ static int decode_sections(struct objtool_file *file) + if (ret) + return ret; + ++ ret = add_dead_ends(file); ++ if (ret) ++ return ret; ++ + add_ignores(file); + + ret = add_nospec_ignores(file); +@@ -1094,13 +1146,13 @@ static int validate_branch(struct objtool_file *file, + + return 0; + +- case INSN_BUG: +- return 0; +- + default: + break; + } + ++ if (insn->dead_end) ++ return 0; ++ + insn = next_insn_same_sec(file, insn); + if (!insn) { + WARN("%s: unexpected end of section", sec->name); +-- +2.7.4 + |