]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge branch 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 28 Feb 2017 18:15:59 +0000 (10:15 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 28 Feb 2017 18:15:59 +0000 (10:15 -0800)
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

Makefile
arch/x86/kernel/vmlinux.lds.S
include/linux/compiler-gcc.h
tools/objtool/arch.h
tools/objtool/arch/x86/decode.c
tools/objtool/builtin-check.c

index b83109b5d217cc2652aba6cf99c6b4f92a5b8cea..4cb6b0a1152b5f57f783f0afa64207e956112c42 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -910,6 +910,18 @@ mod_sign_cmd = true
 endif
 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),)
 core-y         += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/
@@ -1037,18 +1049,6 @@ prepare0: archprepare gcc-plugins
 # All the preparing..
 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
 prepare-objtool: $(objtool_target)
 
index e79f15f108a8d43d8d5644f7fc967f32c3282b47..ad0118fbce90d79e80211a923fced106c39f9316 100644 (file)
@@ -346,6 +346,7 @@ SECTIONS
        /DISCARD/ : {
                *(.eh_frame)
                *(__func_stack_frame_non_standard)
+               *(__unreachable)
        }
 }
 
index 811f7a915658d6c7063d07eb7bfd046db3d6ad01..76e28c22980586a6aa1cc3114b79de7cb5001fcd 100644 (file)
 #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
  * suppress control flow warnings after asm blocks that transfer
  * 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() \
+       do { annotate_unreachable(); __builtin_unreachable(); } while (0)
 
 /* Mark a function definition as prohibited from being cloned. */
 #define __noclone      __attribute__((__noclone__, __optimize__("no-tracer")))
index f7350fcedc70dc6c0ef04159d9fa6e33cc76bcdc..a59e061c0b4a0abcf3e9fc7a76e462fd2c41954b 100644 (file)
@@ -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,
index 039636ffb6c8a3edb6c14fd9a2b3a854ab84f982..6ac99e3266eb8218aa485081501e9e0da17c4c77 100644 (file)
@@ -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;
index e8a1f699058a29ba695bfbf24781562c665e4525..5fc52ee3264c1ad9b191c454c404b5df21486beb 100644 (file)
@@ -51,7 +51,7 @@ struct instruction {
        unsigned int len, state;
        unsigned char type;
        unsigned long immediate;
-       bool alt_group, visited;
+       bool alt_group, visited, dead_end;
        struct symbol *call_dest;
        struct instruction *jump_dest;
        struct list_head alts;
@@ -329,6 +329,54 @@ static int decode_instructions(struct objtool_file *file)
        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.
  */
@@ -843,6 +891,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_jump_destinations(file);
@@ -1037,13 +1089,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);