From: Greg Kroah-Hartman Date: Wed, 30 May 2018 08:13:16 +0000 (+0200) Subject: 4.16-stable patches X-Git-Tag: v4.14.46~7 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3d54fef68a7fb41f298beb6031570522c6528565;p=thirdparty%2Fkernel%2Fstable-queue.git 4.16-stable patches 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 --- 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 index 00000000000..0937d6d3920 --- /dev/null +++ b/queue-4.16/objtool-detect-rip-relative-switch-table-references-part-2.patch @@ -0,0 +1,120 @@ +From 7dec80ccbe310fb7e225bf21c48c672bb780ce7b Mon Sep 17 00:00:00 2001 +From: Josh Poimboeuf +Date: Fri, 18 May 2018 15:10:34 -0500 +Subject: objtool: Detect RIP-relative switch table references, part 2 + +From: Josh Poimboeuf + +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 +Signed-off-by: Josh Poimboeuf +Cc: Linus Torvalds +Cc: Peter Zijlstra +Cc: Thomas Gleixner +Link: http://lkml.kernel.org/r/f400541613d45689086329432f3095119ffbc328.1526674218.git.jpoimboe@redhat.com +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..21b39a0eb70 --- /dev/null +++ b/queue-4.16/objtool-detect-rip-relative-switch-table-references.patch @@ -0,0 +1,115 @@ +From 6f5ec2993b1f39aed12fa6fd56e8dc2272ee8a33 Mon Sep 17 00:00:00 2001 +From: Josh Poimboeuf +Date: Mon, 14 May 2018 08:53:24 -0500 +Subject: objtool: Detect RIP-relative switch table references + +From: Josh Poimboeuf + +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 + 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 + 19c0: R_X86_64_PC32 .rodata+0x45c + 19c4: e9 00 00 00 00 jmpq 19c9 + 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 +Signed-off-by: Josh Poimboeuf +Cc: Linus Torvalds +Cc: Peter Zijlstra +Cc: Thomas Gleixner +Link: http://lkml.kernel.org/r/b6098294fd67afb69af8c47c9883d7a68bf0f8ea.1526305958.git.jpoimboe@redhat.com +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..e03347701ae --- /dev/null +++ b/queue-4.16/objtool-fix-noreturn-detection-for-recursive-sibling-calls.patch @@ -0,0 +1,60 @@ +From 0afd0d9e0e7879d666c1df2fa1bea4d8716909fe Mon Sep 17 00:00:00 2001 +From: Josh Poimboeuf +Date: Wed, 9 May 2018 22:39:14 -0500 +Subject: objtool: Fix "noreturn" detection for recursive sibling calls + +From: Josh Poimboeuf + +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 +Signed-off-by: Josh Poimboeuf +Acked-by: Peter Zijlstra (Intel) +Cc: Arnd Bergmann +Cc: David Laight +Cc: Greg KH +Cc: Linus Torvalds +Cc: Peter Zijlstra +Cc: Thomas Gleixner +Cc: damian +Link: http://lkml.kernel.org/r/7cc156408c5781a1f62085d352ced1fe39fe2f91.1525923412.git.jpoimboe@redhat.com +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..9478029f158 --- /dev/null +++ b/queue-4.16/objtool-support-gcc-8-s-cold-subfunctions.patch @@ -0,0 +1,334 @@ +From 13810435b9a7014fb92eb715f77da488f3b65b99 Mon Sep 17 00:00:00 2001 +From: Josh Poimboeuf +Date: Wed, 9 May 2018 22:39:15 -0500 +Subject: objtool: Support GCC 8's cold subfunctions + +From: Josh Poimboeuf + +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 +Reported-by: Arnd Bergmann +Signed-off-by: Josh Poimboeuf +Acked-by: Peter Zijlstra (Intel) +Cc: David Laight +Cc: Greg KH +Cc: Linus Torvalds +Cc: Peter Zijlstra +Cc: Randy Dunlap +Cc: Thomas Gleixner +Link: http://lkml.kernel.org/r/0965e7fcfc5f31a276f0c7f298ff770c19b68706.1525923412.git.jpoimboe@redhat.com +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..514519bfcd8 --- /dev/null +++ b/queue-4.16/objtool-support-gcc-8-switch-tables.patch @@ -0,0 +1,115 @@ +From fd35c88b74170d9335530d9abf271d5d73eb5401 Mon Sep 17 00:00:00 2001 +From: Josh Poimboeuf +Date: Thu, 10 May 2018 17:48:49 -0500 +Subject: objtool: Support GCC 8 switch tables + +From: Josh Poimboeuf + +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 +Reported-by: kbuild test robot +Signed-off-by: Josh Poimboeuf +Acked-by: Peter Zijlstra (Intel) +Cc: David Laight +Cc: Greg KH +Cc: Linus Torvalds +Cc: Peter Zijlstra +Cc: Randy Dunlap +Cc: Thomas Gleixner +Cc: damian +Link: http://lkml.kernel.org/r/20180510224849.xwi34d6tzheb5wgw@treble +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + 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); diff --git a/queue-4.16/series b/queue-4.16/series index e69de29bb2d..a8f185155dc 100644 --- a/queue-4.16/series +++ b/queue-4.16/series @@ -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 index 00000000000..fd25dffe2b1 --- /dev/null +++ b/queue-4.16/x86-mce-amd-cache-smca-misc-block-addresses.patch @@ -0,0 +1,92 @@ +From 78ce241099bb363b19dbd0245442e66c8de8f567 Mon Sep 17 00:00:00 2001 +From: Borislav Petkov +Date: Thu, 17 May 2018 10:46:26 +0200 +Subject: x86/MCE/AMD: Cache SMCA MISC block addresses + +From: Borislav Petkov + +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 +Tested-by: Johannes Hirte +Signed-off-by: Borislav Petkov +Signed-off-by: Thomas Gleixner +Cc: Yazen Ghannam +Link: http://lkml.kernel.org/r/20180414004230.GA2033@probook +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..5ad2b24cd53 --- /dev/null +++ b/queue-4.16/x86-mce-amd-carve-out-smca-get_block_address-code.patch @@ -0,0 +1,104 @@ +From 8a331f4a0863bea758561c921b94b4d28f7c4029 Mon Sep 17 00:00:00 2001 +From: Yazen Ghannam +Date: Wed, 21 Feb 2018 11:19:00 +0100 +Subject: x86/mce/AMD: Carve out SMCA get_block_address() code + +From: Yazen Ghannam + +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 +[ Save an indentation level. ] +Signed-off-by: Borislav Petkov +Cc: Borislav Petkov +Cc: Linus Torvalds +Cc: Peter Zijlstra +Cc: Thomas Gleixner +Cc: Tony Luck +Cc: linux-edac +Link: http://lkml.kernel.org/r/20180215210943.11530-4-Yazen.Ghannam@amd.com +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + 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) {