]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.16-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 30 May 2018 08:13:16 +0000 (10:13 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 30 May 2018 08:13:16 +0000 (10:13 +0200)
added patches:
objtool-detect-rip-relative-switch-table-references-part-2.patch
objtool-detect-rip-relative-switch-table-references.patch
objtool-fix-noreturn-detection-for-recursive-sibling-calls.patch
objtool-support-gcc-8-s-cold-subfunctions.patch
objtool-support-gcc-8-switch-tables.patch
x86-mce-amd-cache-smca-misc-block-addresses.patch
x86-mce-amd-carve-out-smca-get_block_address-code.patch

queue-4.16/objtool-detect-rip-relative-switch-table-references-part-2.patch [new file with mode: 0644]
queue-4.16/objtool-detect-rip-relative-switch-table-references.patch [new file with mode: 0644]
queue-4.16/objtool-fix-noreturn-detection-for-recursive-sibling-calls.patch [new file with mode: 0644]
queue-4.16/objtool-support-gcc-8-s-cold-subfunctions.patch [new file with mode: 0644]
queue-4.16/objtool-support-gcc-8-switch-tables.patch [new file with mode: 0644]
queue-4.16/series
queue-4.16/x86-mce-amd-cache-smca-misc-block-addresses.patch [new file with mode: 0644]
queue-4.16/x86-mce-amd-carve-out-smca-get_block_address-code.patch [new file with mode: 0644]

diff --git a/queue-4.16/objtool-detect-rip-relative-switch-table-references-part-2.patch b/queue-4.16/objtool-detect-rip-relative-switch-table-references-part-2.patch
new file mode 100644 (file)
index 0000000..0937d6d
--- /dev/null
@@ -0,0 +1,120 @@
+From 7dec80ccbe310fb7e225bf21c48c672bb780ce7b Mon Sep 17 00:00:00 2001
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+Date: Fri, 18 May 2018 15:10:34 -0500
+Subject: objtool: Detect RIP-relative switch table references, part 2
+
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+
+commit 7dec80ccbe310fb7e225bf21c48c672bb780ce7b upstream.
+
+With the following commit:
+
+  fd35c88b7417 ("objtool: Support GCC 8 switch tables")
+
+I added a "can't find switch jump table" warning, to stop covering up
+silent failures if add_switch_table() can't find anything.
+
+That warning found yet another bug in the objtool switch table detection
+logic.  For cases 1 and 2 (as described in the comments of
+find_switch_table()), the find_symbol_containing() check doesn't adjust
+the offset for RIP-relative switch jumps.
+
+Incidentally, this bug was already fixed for case 3 with:
+
+  6f5ec2993b1f ("objtool: Detect RIP-relative switch table references")
+
+However, that commit missed the fix for cases 1 and 2.
+
+The different cases are now starting to look more and more alike.  So
+fix the bug by consolidating them into a single case, by checking the
+original dynamic jump instruction in the case 3 loop.
+
+This also simplifies the code and makes it more robust against future
+switch table detection issues -- of which I'm sure there will be many...
+
+Switch table detection has been the most fragile area of objtool, by
+far.  I long for the day when we'll have a GCC plugin for annotating
+switch tables.  Linus asked me to delay such a plugin due to the
+flakiness of the plugin infrastructure in older versions of GCC, so this
+rickety code is what we're stuck with for now.  At least the code is now
+a little simpler than it was.
+
+Reported-by: kbuild test robot <lkp@intel.com>
+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/f400541613d45689086329432f3095119ffbc328.1526674218.git.jpoimboe@redhat.com
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/objtool/check.c |   37 ++++++++++++-------------------------
+ 1 file changed, 12 insertions(+), 25 deletions(-)
+
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -901,40 +901,19 @@ static struct rela *find_switch_table(st
+       struct instruction *orig_insn = insn;
+       unsigned long table_offset;
+-      /* case 1 & 2 */
+-      text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
+-      if (text_rela && text_rela->sym == file->rodata->sym &&
+-          !find_symbol_containing(file->rodata, text_rela->addend)) {
+-
+-              table_offset = text_rela->addend;
+-              if (text_rela->type == R_X86_64_PC32) {
+-                      /* case 2 */
+-                      table_offset += 4;
+-                      file->ignore_unreachables = true;
+-              }
+-
+-              rodata_rela = find_rela_by_dest(file->rodata, table_offset);
+-              if (!rodata_rela)
+-                      return NULL;
+-
+-              return rodata_rela;
+-      }
+-
+-      /* case 3 */
+       /*
+        * Backward search using the @first_jump_src links, these help avoid
+        * much of the 'in between' code. Which avoids us getting confused by
+        * it.
+        */
+-      for (insn = list_prev_entry(insn, list);
+-
++      for (;
+            &insn->list != &file->insn_list &&
+            insn->sec == func->sec &&
+            insn->offset >= func->offset;
+            insn = insn->first_jump_src ?: list_prev_entry(insn, list)) {
+-              if (insn->type == INSN_JUMP_DYNAMIC)
++              if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC)
+                       break;
+               /* allow small jumps within the range */
+@@ -961,10 +940,18 @@ static struct rela *find_switch_table(st
+               if (find_symbol_containing(file->rodata, table_offset))
+                       continue;
+-              /* mov [rodata addr], %reg */
+               rodata_rela = find_rela_by_dest(file->rodata, table_offset);
+-              if (rodata_rela)
++              if (rodata_rela) {
++                      /*
++                       * Use of RIP-relative switch jumps is quite rare, and
++                       * indicates a rare GCC quirk/bug which can leave dead
++                       * code behind.
++                       */
++                      if (text_rela->type == R_X86_64_PC32)
++                              file->ignore_unreachables = true;
++
+                       return rodata_rela;
++              }
+       }
+       return NULL;
diff --git a/queue-4.16/objtool-detect-rip-relative-switch-table-references.patch b/queue-4.16/objtool-detect-rip-relative-switch-table-references.patch
new file mode 100644 (file)
index 0000000..21b39a0
--- /dev/null
@@ -0,0 +1,115 @@
+From 6f5ec2993b1f39aed12fa6fd56e8dc2272ee8a33 Mon Sep 17 00:00:00 2001
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+Date: Mon, 14 May 2018 08:53:24 -0500
+Subject: objtool: Detect RIP-relative switch table references
+
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+
+commit 6f5ec2993b1f39aed12fa6fd56e8dc2272ee8a33 upstream.
+
+Typically a switch table can be found by detecting a .rodata access
+followed an indirect jump:
+
+    1969:      4a 8b 0c e5 00 00 00    mov    0x0(,%r12,8),%rcx
+    1970:      00
+                       196d: R_X86_64_32S      .rodata+0x438
+    1971:      e9 00 00 00 00          jmpq   1976 <dispc_runtime_suspend+0xb6a>
+                       1972: R_X86_64_PC32     __x86_indirect_thunk_rcx-0x4
+
+Randy Dunlap reported a case (seen with GCC 4.8) where the .rodata
+access uses RIP-relative addressing:
+
+    19bd:      48 8b 3d 00 00 00 00    mov    0x0(%rip),%rdi        # 19c4 <dispc_runtime_suspend+0xbb8>
+                       19c0: R_X86_64_PC32     .rodata+0x45c
+    19c4:      e9 00 00 00 00          jmpq   19c9 <dispc_runtime_suspend+0xbbd>
+                       19c5: R_X86_64_PC32     __x86_indirect_thunk_rdi-0x4
+
+In this case the relocation addend needs to be adjusted accordingly in
+order to find the location of the switch table.
+
+The fix is for case 3 (as described in the comments), but also make the
+existing case 1 & 2 checks more precise by only adjusting the addend for
+R_X86_64_PC32 relocations.
+
+This fixes the following warnings:
+
+  drivers/video/fbdev/omap2/omapfb/dss/dispc.o: warning: objtool: dispc_runtime_suspend()+0xbb8: sibling call from callable instruction with modified stack frame
+  drivers/video/fbdev/omap2/omapfb/dss/dispc.o: warning: objtool: dispc_runtime_resume()+0xcc5: sibling call from callable instruction with modified stack frame
+
+Reported-by: Randy Dunlap <rdunlap@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/b6098294fd67afb69af8c47c9883d7a68bf0f8ea.1526305958.git.jpoimboe@redhat.com
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/objtool/check.c |   33 ++++++++++++++++++---------------
+ 1 file changed, 18 insertions(+), 15 deletions(-)
+
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -899,24 +899,24 @@ static struct rela *find_switch_table(st
+ {
+       struct rela *text_rela, *rodata_rela;
+       struct instruction *orig_insn = insn;
++      unsigned long table_offset;
++      /* case 1 & 2 */
+       text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
+       if (text_rela && text_rela->sym == file->rodata->sym &&
+           !find_symbol_containing(file->rodata, text_rela->addend)) {
+-              /* case 1 */
+-              rodata_rela = find_rela_by_dest(file->rodata,
+-                                              text_rela->addend);
+-              if (rodata_rela)
+-                      return rodata_rela;
++              table_offset = text_rela->addend;
++              if (text_rela->type == R_X86_64_PC32) {
++                      /* case 2 */
++                      table_offset += 4;
++                      file->ignore_unreachables = true;
++              }
+-              /* case 2 */
+-              rodata_rela = find_rela_by_dest(file->rodata,
+-                                              text_rela->addend + 4);
++              rodata_rela = find_rela_by_dest(file->rodata, table_offset);
+               if (!rodata_rela)
+                       return NULL;
+-              file->ignore_unreachables = true;
+               return rodata_rela;
+       }
+@@ -950,18 +950,21 @@ static struct rela *find_switch_table(st
+               if (!text_rela || text_rela->sym != file->rodata->sym)
+                       continue;
++              table_offset = text_rela->addend;
++              if (text_rela->type == R_X86_64_PC32)
++                      table_offset += 4;
++
+               /*
+                * Make sure the .rodata address isn't associated with a
+                * symbol.  gcc jump tables are anonymous data.
+                */
+-              if (find_symbol_containing(file->rodata, text_rela->addend))
++              if (find_symbol_containing(file->rodata, table_offset))
+                       continue;
+-              rodata_rela = find_rela_by_dest(file->rodata, text_rela->addend);
+-              if (!rodata_rela)
+-                      continue;
+-
+-              return rodata_rela;
++              /* mov [rodata addr], %reg */
++              rodata_rela = find_rela_by_dest(file->rodata, table_offset);
++              if (rodata_rela)
++                      return rodata_rela;
+       }
+       return NULL;
diff --git a/queue-4.16/objtool-fix-noreturn-detection-for-recursive-sibling-calls.patch b/queue-4.16/objtool-fix-noreturn-detection-for-recursive-sibling-calls.patch
new file mode 100644 (file)
index 0000000..e033477
--- /dev/null
@@ -0,0 +1,60 @@
+From 0afd0d9e0e7879d666c1df2fa1bea4d8716909fe Mon Sep 17 00:00:00 2001
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+Date: Wed, 9 May 2018 22:39:14 -0500
+Subject: objtool: Fix "noreturn" detection for recursive sibling calls
+
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+
+commit 0afd0d9e0e7879d666c1df2fa1bea4d8716909fe upstream.
+
+Objtool has some crude logic for detecting static "noreturn" functions
+(aka "dead ends").  This is necessary for being able to correctly follow
+GCC code flow when such functions are called.
+
+It's remotely possible for two functions to call each other via sibling
+calls.  If they don't have RET instructions, objtool's noreturn
+detection logic goes into a recursive loop:
+
+  drivers/char/ipmi/ipmi_ssif.o: warning: objtool: return_hosed_msg()+0x0: infinite recursion (objtool bug!)
+  drivers/char/ipmi/ipmi_ssif.o: warning: objtool: deliver_recv_msg()+0x0: infinite recursion (objtool bug!)
+
+Instead of reporting an error in this case, consider the functions to be
+non-dead-ends.
+
+Reported-and-tested-by: Randy Dunlap <rdunlap@infradead.org>
+Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
+Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: David Laight <David.Laight@ACULAB.COM>
+Cc: Greg KH <gregkh@linuxfoundation.org>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: damian <damian.tometzki@icloud.com>
+Link: http://lkml.kernel.org/r/7cc156408c5781a1f62085d352ced1fe39fe2f91.1525923412.git.jpoimboe@redhat.com
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/objtool/check.c |   10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -208,9 +208,13 @@ static int __dead_end_function(struct ob
+                               /* local sibling call */
+                               if (recursion == 5) {
+-                                      WARN_FUNC("infinite recursion (objtool bug!)",
+-                                                dest->sec, dest->offset);
+-                                      return -1;
++                                      /*
++                                       * Infinite recursion: two functions
++                                       * have sibling calls to each other.
++                                       * This is a very rare case.  It means
++                                       * they aren't dead ends.
++                                       */
++                                      return 0;
+                               }
+                               return __dead_end_function(file, dest->func,
diff --git a/queue-4.16/objtool-support-gcc-8-s-cold-subfunctions.patch b/queue-4.16/objtool-support-gcc-8-s-cold-subfunctions.patch
new file mode 100644 (file)
index 0000000..9478029
--- /dev/null
@@ -0,0 +1,334 @@
+From 13810435b9a7014fb92eb715f77da488f3b65b99 Mon Sep 17 00:00:00 2001
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+Date: Wed, 9 May 2018 22:39:15 -0500
+Subject: objtool: Support GCC 8's cold subfunctions
+
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+
+commit 13810435b9a7014fb92eb715f77da488f3b65b99 upstream.
+
+GCC 8 moves a lot of unlikely code out of line to "cold" subfunctions in
+.text.unlikely.  Properly detect the new subfunctions and treat them as
+extensions of the original functions.
+
+This fixes a bunch of warnings like:
+
+  kernel/cgroup/cgroup.o: warning: objtool: parse_cgroup_root_flags()+0x33: sibling call from callable instruction with modified stack frame
+  kernel/cgroup/cgroup.o: warning: objtool: cgroup_addrm_files()+0x290: sibling call from callable instruction with modified stack frame
+  kernel/cgroup/cgroup.o: warning: objtool: cgroup_apply_control_enable()+0x25b: sibling call from callable instruction with modified stack frame
+  kernel/cgroup/cgroup.o: warning: objtool: rebind_subsystems()+0x325: sibling call from callable instruction with modified stack frame
+
+Reported-and-tested-by: damian <damian.tometzki@icloud.com>
+Reported-by: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
+Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Cc: David Laight <David.Laight@ACULAB.COM>
+Cc: Greg KH <gregkh@linuxfoundation.org>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Randy Dunlap <rdunlap@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Link: http://lkml.kernel.org/r/0965e7fcfc5f31a276f0c7f298ff770c19b68706.1525923412.git.jpoimboe@redhat.com
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/objtool/check.c |   93 +++++++++++++++++++++++++++-----------------------
+ tools/objtool/elf.c   |   42 +++++++++++++++++++++-
+ tools/objtool/elf.h   |    2 +
+ 3 files changed, 93 insertions(+), 44 deletions(-)
+
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -59,6 +59,31 @@ static struct instruction *next_insn_sam
+       return next;
+ }
++static struct instruction *next_insn_same_func(struct objtool_file *file,
++                                             struct instruction *insn)
++{
++      struct instruction *next = list_next_entry(insn, list);
++      struct symbol *func = insn->func;
++
++      if (!func)
++              return NULL;
++
++      if (&next->list != &file->insn_list && next->func == func)
++              return next;
++
++      /* Check if we're already in the subfunction: */
++      if (func == func->cfunc)
++              return NULL;
++
++      /* Move to the subfunction: */
++      return find_insn(file, func->cfunc->sec, func->cfunc->offset);
++}
++
++#define func_for_each_insn_all(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);           \
+            insn && &insn->list != &file->insn_list &&                 \
+@@ -149,10 +174,14 @@ static int __dead_end_function(struct ob
+                       if (!strcmp(func->name, global_noreturns[i]))
+                               return 1;
+-      if (!func->sec)
++      if (!func->len)
++              return 0;
++
++      insn = find_insn(file, func->sec, func->offset);
++      if (!insn->func)
+               return 0;
+-      func_for_each_insn(file, func, insn) {
++      func_for_each_insn_all(file, func, insn) {
+               empty = false;
+               if (insn->type == INSN_RETURN)
+@@ -167,35 +196,24 @@ static int __dead_end_function(struct ob
+        * case, the function's dead-end status depends on whether the target
+        * of the sibling call returns.
+        */
+-      func_for_each_insn(file, func, insn) {
+-              if (insn->sec != func->sec ||
+-                  insn->offset >= func->offset + func->len)
+-                      break;
+-
++      func_for_each_insn_all(file, func, insn) {
+               if (insn->type == INSN_JUMP_UNCONDITIONAL) {
+                       struct instruction *dest = insn->jump_dest;
+-                      struct symbol *dest_func;
+                       if (!dest)
+                               /* sibling call to another file */
+                               return 0;
+-                      if (dest->sec != func->sec ||
+-                          dest->offset < func->offset ||
+-                          dest->offset >= func->offset + func->len) {
+-                              /* local sibling call */
+-                              dest_func = find_symbol_by_offset(dest->sec,
+-                                                                dest->offset);
+-                              if (!dest_func)
+-                                      continue;
++                      if (dest->func && dest->func->pfunc != insn->func->pfunc) {
++                              /* local sibling call */
+                               if (recursion == 5) {
+                                       WARN_FUNC("infinite recursion (objtool bug!)",
+                                                 dest->sec, dest->offset);
+                                       return -1;
+                               }
+-                              return __dead_end_function(file, dest_func,
++                              return __dead_end_function(file, dest->func,
+                                                          recursion + 1);
+                       }
+               }
+@@ -422,7 +440,7 @@ static void add_ignores(struct objtool_f
+                       if (!ignore_func(file, func))
+                               continue;
+-                      func_for_each_insn(file, func, insn)
++                      func_for_each_insn_all(file, func, insn)
+                               insn->ignore = true;
+               }
+       }
+@@ -782,9 +800,8 @@ out:
+       return ret;
+ }
+-static int add_switch_table(struct objtool_file *file, struct symbol *func,
+-                          struct instruction *insn, struct rela *table,
+-                          struct rela *next_table)
++static int add_switch_table(struct objtool_file *file, struct instruction *insn,
++                          struct rela *table, struct rela *next_table)
+ {
+       struct rela *rela = table;
+       struct instruction *alt_insn;
+@@ -794,18 +811,13 @@ static int add_switch_table(struct objto
+               if (rela == next_table)
+                       break;
+-              if (rela->sym->sec != insn->sec ||
+-                  rela->addend <= func->offset ||
+-                  rela->addend >= func->offset + func->len)
++              alt_insn = find_insn(file, rela->sym->sec, rela->addend);
++              if (!alt_insn)
+                       break;
+-              alt_insn = find_insn(file, insn->sec, rela->addend);
+-              if (!alt_insn) {
+-                      WARN("%s: can't find instruction at %s+0x%x",
+-                           file->rodata->rela->name, insn->sec->name,
+-                           rela->addend);
+-                      return -1;
+-              }
++              /* Make sure the jmp dest is in the function or subfunction: */
++              if (alt_insn->func->pfunc != insn->func->pfunc)
++                      break;
+               alt = malloc(sizeof(*alt));
+               if (!alt) {
+@@ -943,7 +955,7 @@ static int add_func_switch_tables(struct
+       struct rela *rela, *prev_rela = NULL;
+       int ret;
+-      func_for_each_insn(file, func, insn) {
++      func_for_each_insn_all(file, func, insn) {
+               if (!last)
+                       last = insn;
+@@ -974,8 +986,7 @@ static int add_func_switch_tables(struct
+                * the beginning of another switch table in the same function.
+                */
+               if (prev_jump) {
+-                      ret = add_switch_table(file, func, prev_jump, prev_rela,
+-                                             rela);
++                      ret = add_switch_table(file, prev_jump, prev_rela, rela);
+                       if (ret)
+                               return ret;
+               }
+@@ -985,7 +996,7 @@ static int add_func_switch_tables(struct
+       }
+       if (prev_jump) {
+-              ret = add_switch_table(file, func, prev_jump, prev_rela, NULL);
++              ret = add_switch_table(file, prev_jump, prev_rela, NULL);
+               if (ret)
+                       return ret;
+       }
+@@ -1749,15 +1760,13 @@ static int validate_branch(struct objtoo
+       while (1) {
+               next_insn = next_insn_same_sec(file, insn);
+-
+-              if (file->c_file && func && insn->func && func != insn->func) {
++              if (file->c_file && func && insn->func && func != insn->func->pfunc) {
+                       WARN("%s() falls through to next function %s()",
+                            func->name, insn->func->name);
+                       return 1;
+               }
+-              if (insn->func)
+-                      func = insn->func;
++              func = insn->func ? insn->func->pfunc : NULL;
+               if (func && insn->ignore) {
+                       WARN_FUNC("BUG: why am I validating an ignored function?",
+@@ -1778,7 +1787,7 @@ static int validate_branch(struct objtoo
+                               i = insn;
+                               save_insn = NULL;
+-                              func_for_each_insn_continue_reverse(file, func, i) {
++                              func_for_each_insn_continue_reverse(file, insn->func, i) {
+                                       if (i->save) {
+                                               save_insn = i;
+                                               break;
+@@ -1865,7 +1874,7 @@ static int validate_branch(struct objtoo
+               case INSN_JUMP_UNCONDITIONAL:
+                       if (insn->jump_dest &&
+                           (!func || !insn->jump_dest->func ||
+-                           func == insn->jump_dest->func)) {
++                           insn->jump_dest->func->pfunc == func)) {
+                               ret = validate_branch(file, insn->jump_dest,
+                                                     state);
+                               if (ret)
+@@ -2060,7 +2069,7 @@ static int validate_functions(struct obj
+       for_each_sec(file, sec) {
+               list_for_each_entry(func, &sec->symbol_list, list) {
+-                      if (func->type != STT_FUNC)
++                      if (func->type != STT_FUNC || func->pfunc != func)
+                               continue;
+                       insn = find_insn(file, sec, func->offset);
+--- a/tools/objtool/elf.c
++++ b/tools/objtool/elf.c
+@@ -79,6 +79,19 @@ struct symbol *find_symbol_by_offset(str
+       return NULL;
+ }
++struct symbol *find_symbol_by_name(struct elf *elf, const char *name)
++{
++      struct section *sec;
++      struct symbol *sym;
++
++      list_for_each_entry(sec, &elf->sections, list)
++              list_for_each_entry(sym, &sec->symbol_list, list)
++                      if (!strcmp(sym->name, name))
++                              return sym;
++
++      return NULL;
++}
++
+ struct symbol *find_symbol_containing(struct section *sec, unsigned long offset)
+ {
+       struct symbol *sym;
+@@ -203,10 +216,11 @@ static int read_sections(struct elf *elf
+ static int read_symbols(struct elf *elf)
+ {
+-      struct section *symtab;
+-      struct symbol *sym;
++      struct section *symtab, *sec;
++      struct symbol *sym, *pfunc;
+       struct list_head *entry, *tmp;
+       int symbols_nr, i;
++      char *coldstr;
+       symtab = find_section_by_name(elf, ".symtab");
+       if (!symtab) {
+@@ -281,6 +295,30 @@ static int read_symbols(struct elf *elf)
+               hash_add(sym->sec->symbol_hash, &sym->hash, sym->idx);
+       }
++      /* Create parent/child links for any cold subfunctions */
++      list_for_each_entry(sec, &elf->sections, list) {
++              list_for_each_entry(sym, &sec->symbol_list, list) {
++                      if (sym->type != STT_FUNC)
++                              continue;
++                      sym->pfunc = sym->cfunc = sym;
++                      coldstr = strstr(sym->name, ".cold.");
++                      if (coldstr) {
++                              coldstr[0] = '\0';
++                              pfunc = find_symbol_by_name(elf, sym->name);
++                              coldstr[0] = '.';
++
++                              if (!pfunc) {
++                                      WARN("%s(): can't find parent function",
++                                           sym->name);
++                                      goto err;
++                              }
++
++                              sym->pfunc = pfunc;
++                              pfunc->cfunc = sym;
++                      }
++              }
++      }
++
+       return 0;
+ err:
+--- a/tools/objtool/elf.h
++++ b/tools/objtool/elf.h
+@@ -61,6 +61,7 @@ struct symbol {
+       unsigned char bind, type;
+       unsigned long offset;
+       unsigned int len;
++      struct symbol *pfunc, *cfunc;
+ };
+ struct rela {
+@@ -86,6 +87,7 @@ struct elf {
+ struct elf *elf_open(const char *name, int flags);
+ struct section *find_section_by_name(struct elf *elf, const char *name);
+ struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
++struct symbol *find_symbol_by_name(struct elf *elf, const char *name);
+ struct symbol *find_symbol_containing(struct section *sec, unsigned long offset);
+ struct rela *find_rela_by_dest(struct section *sec, unsigned long offset);
+ struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset,
diff --git a/queue-4.16/objtool-support-gcc-8-switch-tables.patch b/queue-4.16/objtool-support-gcc-8-switch-tables.patch
new file mode 100644 (file)
index 0000000..514519b
--- /dev/null
@@ -0,0 +1,115 @@
+From fd35c88b74170d9335530d9abf271d5d73eb5401 Mon Sep 17 00:00:00 2001
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+Date: Thu, 10 May 2018 17:48:49 -0500
+Subject: objtool: Support GCC 8 switch tables
+
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+
+commit fd35c88b74170d9335530d9abf271d5d73eb5401 upstream.
+
+With GCC 8, some issues were found with the objtool switch table
+detection.
+
+1) In the .rodata section, immediately after the switch table, there can
+   be another object which contains a pointer to the function which had
+   the switch statement.  In this case objtool wrongly considers the
+   function pointer to be part of the switch table.  Fix it by:
+
+   a) making sure there are no pointers to the beginning of the
+      function; and
+
+   b) making sure there are no gaps in the switch table.
+
+   Only the former was needed, the latter adds additional protection for
+   future optimizations.
+
+2) In find_switch_table(), case 1 and case 2 are missing the check to
+   ensure that the .rodata switch table data is anonymous, i.e. that it
+   isn't already associated with an ELF symbol.  Fix it by adding the
+   same find_symbol_containing() check which is used for case 3.
+
+This fixes the following warnings with GCC 8:
+
+  drivers/block/virtio_blk.o: warning: objtool: virtio_queue_rq()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+72
+  net/ipv6/icmp.o: warning: objtool: icmpv6_rcv()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+64
+  drivers/usb/core/quirks.o: warning: objtool: quirks_param_set()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+48
+  drivers/mtd/nand/raw/nand_hynix.o: warning: objtool: hynix_nand_decode_id()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+24
+  drivers/mtd/nand/raw/nand_samsung.o: warning: objtool: samsung_nand_decode_id()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+32
+  drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.o: warning: objtool: gk104_top_oneinit()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+64
+
+Reported-by: Arnd Bergmann <arnd@arndb.de>
+Reported-by: kbuild test robot <lkp@intel.com>
+Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
+Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Cc: David Laight <David.Laight@ACULAB.COM>
+Cc: Greg KH <gregkh@linuxfoundation.org>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Randy Dunlap <rdunlap@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: damian <damian.tometzki@icloud.com>
+Link: http://lkml.kernel.org/r/20180510224849.xwi34d6tzheb5wgw@treble
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/objtool/check.c |   24 ++++++++++++++++++++++--
+ 1 file changed, 22 insertions(+), 2 deletions(-)
+
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -806,17 +806,28 @@ static int add_switch_table(struct objto
+       struct rela *rela = table;
+       struct instruction *alt_insn;
+       struct alternative *alt;
++      struct symbol *pfunc = insn->func->pfunc;
++      unsigned int prev_offset = 0;
+       list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) {
+               if (rela == next_table)
+                       break;
++              /* Make sure the switch table entries are consecutive: */
++              if (prev_offset && rela->offset != prev_offset + 8)
++                      break;
++
++              /* Detect function pointers from contiguous objects: */
++              if (rela->sym->sec == pfunc->sec &&
++                  rela->addend == pfunc->offset)
++                      break;
++
+               alt_insn = find_insn(file, rela->sym->sec, rela->addend);
+               if (!alt_insn)
+                       break;
+               /* Make sure the jmp dest is in the function or subfunction: */
+-              if (alt_insn->func->pfunc != insn->func->pfunc)
++              if (alt_insn->func->pfunc != pfunc)
+                       break;
+               alt = malloc(sizeof(*alt));
+@@ -827,6 +838,13 @@ static int add_switch_table(struct objto
+               alt->insn = alt_insn;
+               list_add_tail(&alt->list, &insn->alts);
++              prev_offset = rela->offset;
++      }
++
++      if (!prev_offset) {
++              WARN_FUNC("can't find switch jump table",
++                        insn->sec, insn->offset);
++              return -1;
+       }
+       return 0;
+@@ -883,7 +901,9 @@ static struct rela *find_switch_table(st
+       struct instruction *orig_insn = insn;
+       text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
+-      if (text_rela && text_rela->sym == file->rodata->sym) {
++      if (text_rela && text_rela->sym == file->rodata->sym &&
++          !find_symbol_containing(file->rodata, text_rela->addend)) {
++
+               /* case 1 */
+               rodata_rela = find_rela_by_dest(file->rodata,
+                                               text_rela->addend);
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a8f185155dcf1e7251ad2f9ae036ca680bd65420 100644 (file)
@@ -0,0 +1,7 @@
+objtool-support-gcc-8-s-cold-subfunctions.patch
+objtool-support-gcc-8-switch-tables.patch
+objtool-detect-rip-relative-switch-table-references.patch
+objtool-detect-rip-relative-switch-table-references-part-2.patch
+objtool-fix-noreturn-detection-for-recursive-sibling-calls.patch
+x86-mce-amd-carve-out-smca-get_block_address-code.patch
+x86-mce-amd-cache-smca-misc-block-addresses.patch
diff --git a/queue-4.16/x86-mce-amd-cache-smca-misc-block-addresses.patch b/queue-4.16/x86-mce-amd-cache-smca-misc-block-addresses.patch
new file mode 100644 (file)
index 0000000..fd25dff
--- /dev/null
@@ -0,0 +1,92 @@
+From 78ce241099bb363b19dbd0245442e66c8de8f567 Mon Sep 17 00:00:00 2001
+From: Borislav Petkov <bp@suse.de>
+Date: Thu, 17 May 2018 10:46:26 +0200
+Subject: x86/MCE/AMD: Cache SMCA MISC block addresses
+
+From: Borislav Petkov <bp@suse.de>
+
+commit 78ce241099bb363b19dbd0245442e66c8de8f567 upstream.
+
+... into a global, two-dimensional array and service subsequent reads from
+that cache to avoid rdmsr_on_cpu() calls during CPU hotplug (IPIs with IRQs
+disabled).
+
+In addition, this fixes a KASAN slab-out-of-bounds read due to wrong usage
+of the bank->blocks pointer.
+
+Fixes: 27bd59502702 ("x86/mce/AMD: Get address from already initialized block")
+Reported-by: Johannes Hirte <johannes.hirte@datenkhaos.de>
+Tested-by: Johannes Hirte <johannes.hirte@datenkhaos.de>
+Signed-off-by: Borislav Petkov <bp@suse.de>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Cc: Yazen Ghannam <yazen.ghannam@amd.com>
+Link: http://lkml.kernel.org/r/20180414004230.GA2033@probook
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/kernel/cpu/mcheck/mce_amd.c |   29 ++++++++++++++---------------
+ 1 file changed, 14 insertions(+), 15 deletions(-)
+
+--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
++++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
+@@ -94,6 +94,11 @@ static struct smca_bank_name smca_names[
+       [SMCA_SMU]      = { "smu",              "System Management Unit" },
+ };
++static u32 smca_bank_addrs[MAX_NR_BANKS][NR_BLOCKS] __ro_after_init =
++{
++      [0 ... MAX_NR_BANKS - 1] = { [0 ... NR_BLOCKS - 1] = -1 }
++};
++
+ const char *smca_get_name(enum smca_bank_types t)
+ {
+       if (t >= N_SMCA_BANK_TYPES)
+@@ -443,20 +448,26 @@ static u32 smca_get_block_address(unsign
+       if (!block)
+               return MSR_AMD64_SMCA_MCx_MISC(bank);
++      /* Check our cache first: */
++      if (smca_bank_addrs[bank][block] != -1)
++              return smca_bank_addrs[bank][block];
++
+       /*
+        * For SMCA enabled processors, BLKPTR field of the first MISC register
+        * (MCx_MISC0) indicates presence of additional MISC regs set (MISC1-4).
+        */
+       if (rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_CONFIG(bank), &low, &high))
+-              return addr;
++              goto out;
+       if (!(low & MCI_CONFIG_MCAX))
+-              return addr;
++              goto out;
+       if (!rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_MISC(bank), &low, &high) &&
+           (low & MASK_BLKPTR_LO))
+-              return MSR_AMD64_SMCA_MCx_MISCy(bank, block - 1);
++              addr = MSR_AMD64_SMCA_MCx_MISCy(bank, block - 1);
++out:
++      smca_bank_addrs[bank][block] = addr;
+       return addr;
+ }
+@@ -468,18 +479,6 @@ static u32 get_block_address(unsigned in
+       if ((bank >= mca_cfg.banks) || (block >= NR_BLOCKS))
+               return addr;
+-      /* Get address from already initialized block. */
+-      if (per_cpu(threshold_banks, cpu)) {
+-              struct threshold_bank *bankp = per_cpu(threshold_banks, cpu)[bank];
+-
+-              if (bankp && bankp->blocks) {
+-                      struct threshold_block *blockp = &bankp->blocks[block];
+-
+-                      if (blockp)
+-                              return blockp->address;
+-              }
+-      }
+-
+       if (mce_flags.smca)
+               return smca_get_block_address(cpu, bank, block);
diff --git a/queue-4.16/x86-mce-amd-carve-out-smca-get_block_address-code.patch b/queue-4.16/x86-mce-amd-carve-out-smca-get_block_address-code.patch
new file mode 100644 (file)
index 0000000..5ad2b24
--- /dev/null
@@ -0,0 +1,104 @@
+From 8a331f4a0863bea758561c921b94b4d28f7c4029 Mon Sep 17 00:00:00 2001
+From: Yazen Ghannam <yazen.ghannam@amd.com>
+Date: Wed, 21 Feb 2018 11:19:00 +0100
+Subject: x86/mce/AMD: Carve out SMCA get_block_address() code
+
+From: Yazen Ghannam <yazen.ghannam@amd.com>
+
+commit 8a331f4a0863bea758561c921b94b4d28f7c4029 upstream.
+
+Carve out the SMCA code in get_block_address() into a separate helper
+function.
+
+No functional change.
+
+Signed-off-by: Yazen Ghannam <yazen.ghannam@amd.com>
+[ Save an indentation level. ]
+Signed-off-by: Borislav Petkov <bp@suse.de>
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Tony Luck <tony.luck@intel.com>
+Cc: linux-edac <linux-edac@vger.kernel.org>
+Link: http://lkml.kernel.org/r/20180215210943.11530-4-Yazen.Ghannam@amd.com
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/kernel/cpu/mcheck/mce_amd.c |   57 +++++++++++++++++++----------------
+ 1 file changed, 31 insertions(+), 26 deletions(-)
+
+--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
++++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
+@@ -431,6 +431,35 @@ static void deferred_error_interrupt_ena
+       wrmsr(MSR_CU_DEF_ERR, low, high);
+ }
++static u32 smca_get_block_address(unsigned int cpu, unsigned int bank,
++                                unsigned int block)
++{
++      u32 low, high;
++      u32 addr = 0;
++
++      if (smca_get_bank_type(bank) == SMCA_RESERVED)
++              return addr;
++
++      if (!block)
++              return MSR_AMD64_SMCA_MCx_MISC(bank);
++
++      /*
++       * For SMCA enabled processors, BLKPTR field of the first MISC register
++       * (MCx_MISC0) indicates presence of additional MISC regs set (MISC1-4).
++       */
++      if (rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_CONFIG(bank), &low, &high))
++              return addr;
++
++      if (!(low & MCI_CONFIG_MCAX))
++              return addr;
++
++      if (!rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_MISC(bank), &low, &high) &&
++          (low & MASK_BLKPTR_LO))
++              return MSR_AMD64_SMCA_MCx_MISCy(bank, block - 1);
++
++      return addr;
++}
++
+ static u32 get_block_address(unsigned int cpu, u32 current_addr, u32 low, u32 high,
+                            unsigned int bank, unsigned int block)
+ {
+@@ -451,32 +480,8 @@ static u32 get_block_address(unsigned in
+               }
+       }
+-      if (mce_flags.smca) {
+-              if (smca_get_bank_type(bank) == SMCA_RESERVED)
+-                      return addr;
+-
+-              if (!block) {
+-                      addr = MSR_AMD64_SMCA_MCx_MISC(bank);
+-              } else {
+-                      /*
+-                       * For SMCA enabled processors, BLKPTR field of the
+-                       * first MISC register (MCx_MISC0) indicates presence of
+-                       * additional MISC register set (MISC1-4).
+-                       */
+-                      u32 low, high;
+-
+-                      if (rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_CONFIG(bank), &low, &high))
+-                              return addr;
+-
+-                      if (!(low & MCI_CONFIG_MCAX))
+-                              return addr;
+-
+-                      if (!rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_MISC(bank), &low, &high) &&
+-                          (low & MASK_BLKPTR_LO))
+-                              addr = MSR_AMD64_SMCA_MCx_MISCy(bank, block - 1);
+-              }
+-              return addr;
+-      }
++      if (mce_flags.smca)
++              return smca_get_block_address(cpu, bank, block);
+       /* Fall back to method we used for older processors: */
+       switch (block) {