1 From 338c7d8678b82c46668ce3b73f7339f71ab69cc8 Mon Sep 17 00:00:00 2001
2 From: Josh Poimboeuf <jpoimboe@redhat.com>
3 Date: Tue, 11 Jul 2017 10:33:43 -0500
4 Subject: [PATCH 034/241] objtool, x86: Add facility for asm code to provide
7 Content-Type: text/plain; charset=UTF-8
8 Content-Transfer-Encoding: 8bit
12 Some asm (and inline asm) code does special things to the stack which
13 objtool can't understand. (Nor can GCC or GNU assembler, for that
14 matter.) In such cases we need a facility for the code to provide
15 annotations, so the unwinder can unwind through it.
17 This provides such a facility, in the form of unwind hints. They're
18 similar to the GNU assembler .cfi* directives, but they give more
19 information, and are needed in far fewer places, because objtool can
20 fill in the blanks by following branches and adjusting the stack pointer
23 Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
24 Cc: Andy Lutomirski <luto@kernel.org>
25 Cc: Borislav Petkov <bp@alien8.de>
26 Cc: Brian Gerst <brgerst@gmail.com>
27 Cc: Denys Vlasenko <dvlasenk@redhat.com>
28 Cc: H. Peter Anvin <hpa@zytor.com>
29 Cc: Jiri Slaby <jslaby@suse.cz>
30 Cc: Linus Torvalds <torvalds@linux-foundation.org>
31 Cc: Mike Galbraith <efault@gmx.de>
32 Cc: Peter Zijlstra <peterz@infradead.org>
33 Cc: Thomas Gleixner <tglx@linutronix.de>
34 Cc: live-patching@vger.kernel.org
35 Link: http://lkml.kernel.org/r/0f5f3c9104fca559ff4088bece1d14ae3bca52d5.1499786555.git.jpoimboe@redhat.com
36 Signed-off-by: Ingo Molnar <mingo@kernel.org>
37 (cherry picked from commit 39358a033b2e4432052265c1fa0f36f572d8cfb5)
38 Signed-off-by: Andy Whitcroft <apw@canonical.com>
39 Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
40 (cherry picked from commit a1fed2e10e84d48643a09861c2d127968621813e)
41 Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
43 tools/objtool/Makefile | 3 +
44 arch/x86/include/asm/orc_types.h | 107 ++++++++++++++++++++
45 arch/x86/include/asm/unwind_hints.h | 103 +++++++++++++++++++
46 tools/objtool/check.h | 4 +-
47 tools/objtool/orc_types.h | 22 +++++
48 tools/objtool/check.c | 191 +++++++++++++++++++++++++++++++++---
49 6 files changed, 417 insertions(+), 13 deletions(-)
50 create mode 100644 arch/x86/include/asm/orc_types.h
51 create mode 100644 arch/x86/include/asm/unwind_hints.h
53 diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile
54 index 0e2765e243c0..3a6425fefc43 100644
55 --- a/tools/objtool/Makefile
56 +++ b/tools/objtool/Makefile
57 @@ -52,6 +52,9 @@ $(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN)
58 diff -I'^#include' arch/x86/insn/inat.h ../../arch/x86/include/asm/inat.h >/dev/null && \
59 diff -I'^#include' arch/x86/insn/inat_types.h ../../arch/x86/include/asm/inat_types.h >/dev/null) \
60 || echo "warning: objtool: x86 instruction decoder differs from kernel" >&2 )) || true
61 + @(test -d ../../kernel -a -d ../../tools -a -d ../objtool && (( \
62 + diff ../../arch/x86/include/asm/orc_types.h orc_types.h >/dev/null) \
63 + || echo "warning: objtool: orc_types.h differs from kernel" >&2 )) || true
64 $(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@
67 diff --git a/arch/x86/include/asm/orc_types.h b/arch/x86/include/asm/orc_types.h
69 index 000000000000..7dc777a6cb40
71 +++ b/arch/x86/include/asm/orc_types.h
74 + * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
76 + * This program is free software; you can redistribute it and/or
77 + * modify it under the terms of the GNU General Public License
78 + * as published by the Free Software Foundation; either version 2
79 + * of the License, or (at your option) any later version.
81 + * This program is distributed in the hope that it will be useful,
82 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
83 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
84 + * GNU General Public License for more details.
86 + * You should have received a copy of the GNU General Public License
87 + * along with this program; if not, see <http://www.gnu.org/licenses/>.
93 +#include <linux/types.h>
94 +#include <linux/compiler.h>
97 + * The ORC_REG_* registers are base registers which are used to find other
98 + * registers on the stack.
100 + * ORC_REG_PREV_SP, also known as DWARF Call Frame Address (CFA), is the
101 + * address of the previous frame: the caller's SP before it called the current
104 + * ORC_REG_UNDEFINED means the corresponding register's value didn't change in
105 + * the current frame.
107 + * The most commonly used base registers are SP and BP -- which the previous SP
108 + * is usually based on -- and PREV_SP and UNDEFINED -- which the previous BP is
109 + * usually based on.
111 + * The rest of the base registers are needed for special cases like entry code
112 + * and GCC realigned stacks.
114 +#define ORC_REG_UNDEFINED 0
115 +#define ORC_REG_PREV_SP 1
116 +#define ORC_REG_DX 2
117 +#define ORC_REG_DI 3
118 +#define ORC_REG_BP 4
119 +#define ORC_REG_SP 5
120 +#define ORC_REG_R10 6
121 +#define ORC_REG_R13 7
122 +#define ORC_REG_BP_INDIRECT 8
123 +#define ORC_REG_SP_INDIRECT 9
124 +#define ORC_REG_MAX 15
127 + * ORC_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP (the
128 + * caller's SP right before it made the call). Used for all callable
129 + * functions, i.e. all C code and all callable asm functions.
131 + * ORC_TYPE_REGS: Used in entry code to indicate that sp_reg+sp_offset points
132 + * to a fully populated pt_regs from a syscall, interrupt, or exception.
134 + * ORC_TYPE_REGS_IRET: Used in entry code to indicate that sp_reg+sp_offset
135 + * points to the iret return frame.
137 + * The UNWIND_HINT macros are used only for the unwind_hint struct. They
138 + * aren't used in struct orc_entry due to size and complexity constraints.
139 + * Objtool converts them to real types when it converts the hints to orc
142 +#define ORC_TYPE_CALL 0
143 +#define ORC_TYPE_REGS 1
144 +#define ORC_TYPE_REGS_IRET 2
145 +#define UNWIND_HINT_TYPE_SAVE 3
146 +#define UNWIND_HINT_TYPE_RESTORE 4
148 +#ifndef __ASSEMBLY__
150 + * This struct is more or less a vastly simplified version of the DWARF Call
151 + * Frame Information standard. It contains only the necessary parts of DWARF
152 + * CFI, simplified for ease of access by the in-kernel unwinder. It tells the
153 + * unwinder how to find the previous SP and BP (and sometimes entry regs) on
154 + * the stack for a given code address. Each instance of the struct corresponds
155 + * to one or more code locations.
166 + * This struct is used by asm and inline asm code to manually annotate the
167 + * location of registers on the stack for the ORC unwinder.
169 + * Type can be either ORC_TYPE_* or UNWIND_HINT_TYPE_*.
171 +struct unwind_hint {
177 +#endif /* __ASSEMBLY__ */
179 +#endif /* _ORC_TYPES_H */
180 diff --git a/arch/x86/include/asm/unwind_hints.h b/arch/x86/include/asm/unwind_hints.h
182 index 000000000000..5e02b11c9b86
184 +++ b/arch/x86/include/asm/unwind_hints.h
186 +#ifndef _ASM_X86_UNWIND_HINTS_H
187 +#define _ASM_X86_UNWIND_HINTS_H
189 +#include "orc_types.h"
194 + * In asm, there are two kinds of code: normal C-type callable functions and
195 + * the rest. The normal callable functions can be called by other code, and
196 + * don't do anything unusual with the stack. Such normal callable functions
197 + * are annotated with the ENTRY/ENDPROC macros. Most asm code falls in this
198 + * category. In this case, no special debugging annotations are needed because
199 + * objtool can automatically generate the ORC data for the ORC unwinder to read
202 + * Anything which doesn't fall into the above category, such as syscall and
203 + * interrupt handlers, tends to not be called directly by other functions, and
204 + * often does unusual non-C-function-type things with the stack pointer. Such
205 + * code needs to be annotated such that objtool can understand it. The
206 + * following CFI hint macros are for this type of code.
208 + * These macros provide hints to objtool about the state of the stack at each
209 + * instruction. Objtool starts from the hints and follows the code flow,
210 + * making automatic CFI adjustments when it sees pushes and pops, filling out
211 + * the debuginfo as necessary. It will also warn if it sees any
214 +.macro UNWIND_HINT sp_reg=ORC_REG_SP sp_offset=0 type=ORC_TYPE_CALL
215 +#ifdef CONFIG_STACK_VALIDATION
216 +.Lunwind_hint_ip_\@:
217 + .pushsection .discard.unwind_hints
218 + /* struct unwind_hint */
219 + .long .Lunwind_hint_ip_\@ - .
227 +.macro UNWIND_HINT_EMPTY
228 + UNWIND_HINT sp_reg=ORC_REG_UNDEFINED
231 +.macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 iret=0
232 + .if \base == %rsp && \indirect
233 + .set sp_reg, ORC_REG_SP_INDIRECT
234 + .elseif \base == %rsp
235 + .set sp_reg, ORC_REG_SP
236 + .elseif \base == %rbp
237 + .set sp_reg, ORC_REG_BP
238 + .elseif \base == %rdi
239 + .set sp_reg, ORC_REG_DI
240 + .elseif \base == %rdx
241 + .set sp_reg, ORC_REG_DX
242 + .elseif \base == %r10
243 + .set sp_reg, ORC_REG_R10
245 + .error "UNWIND_HINT_REGS: bad base register"
248 + .set sp_offset, \offset
251 + .set type, ORC_TYPE_REGS_IRET
252 + .elseif \extra == 0
253 + .set type, ORC_TYPE_REGS_IRET
254 + .set sp_offset, \offset + (16*8)
256 + .set type, ORC_TYPE_REGS
259 + UNWIND_HINT sp_reg=sp_reg sp_offset=sp_offset type=type
262 +.macro UNWIND_HINT_IRET_REGS base=%rsp offset=0
263 + UNWIND_HINT_REGS base=\base offset=\offset iret=1
266 +.macro UNWIND_HINT_FUNC sp_offset=8
267 + UNWIND_HINT sp_offset=\sp_offset
270 +#else /* !__ASSEMBLY__ */
272 +#define UNWIND_HINT(sp_reg, sp_offset, type) \
274 + ".pushsection .discard.unwind_hints\n\t" \
275 + /* struct unwind_hint */ \
276 + ".long 987b - .\n\t" \
277 + ".short " __stringify(sp_offset) "\n\t" \
278 + ".byte " __stringify(sp_reg) "\n\t" \
279 + ".byte " __stringify(type) "\n\t" \
282 +#define UNWIND_HINT_SAVE UNWIND_HINT(0, 0, UNWIND_HINT_TYPE_SAVE)
284 +#define UNWIND_HINT_RESTORE UNWIND_HINT(0, 0, UNWIND_HINT_TYPE_RESTORE)
286 +#endif /* __ASSEMBLY__ */
288 +#endif /* _ASM_X86_UNWIND_HINTS_H */
289 diff --git a/tools/objtool/check.h b/tools/objtool/check.h
290 index 046874bbe226..ac3d4b13f17b 100644
291 --- a/tools/objtool/check.h
292 +++ b/tools/objtool/check.h
293 @@ -43,7 +43,7 @@ struct instruction {
296 unsigned long immediate;
297 - bool alt_group, visited, dead_end, ignore;
298 + bool alt_group, visited, dead_end, ignore, hint, save, restore;
299 struct symbol *call_dest;
300 struct instruction *jump_dest;
301 struct list_head alts;
302 @@ -58,7 +58,7 @@ struct objtool_file {
303 struct list_head insn_list;
304 DECLARE_HASHTABLE(insn_hash, 16);
305 struct section *rodata, *whitelist;
306 - bool ignore_unreachables, c_file;
307 + bool ignore_unreachables, c_file, hints;
310 int check(const char *objname, bool nofp, bool orc);
311 diff --git a/tools/objtool/orc_types.h b/tools/objtool/orc_types.h
312 index fc5cf6cffd9a..9c9dc579bd7d 100644
313 --- a/tools/objtool/orc_types.h
314 +++ b/tools/objtool/orc_types.h
317 * ORC_TYPE_REGS_IRET: Used in entry code to indicate that sp_reg+sp_offset
318 * points to the iret return frame.
320 + * The UNWIND_HINT macros are used only for the unwind_hint struct. They
321 + * aren't used in struct orc_entry due to size and complexity constraints.
322 + * Objtool converts them to real types when it converts the hints to orc
325 #define ORC_TYPE_CALL 0
326 #define ORC_TYPE_REGS 1
327 #define ORC_TYPE_REGS_IRET 2
328 +#define UNWIND_HINT_TYPE_SAVE 3
329 +#define UNWIND_HINT_TYPE_RESTORE 4
331 +#ifndef __ASSEMBLY__
333 * This struct is more or less a vastly simplified version of the DWARF Call
334 * Frame Information standard. It contains only the necessary parts of DWARF
335 @@ -82,4 +90,18 @@ struct orc_entry {
340 + * This struct is used by asm and inline asm code to manually annotate the
341 + * location of registers on the stack for the ORC unwinder.
343 + * Type can be either ORC_TYPE_* or UNWIND_HINT_TYPE_*.
345 +struct unwind_hint {
351 +#endif /* __ASSEMBLY__ */
353 #endif /* _ORC_TYPES_H */
354 diff --git a/tools/objtool/check.c b/tools/objtool/check.c
355 index cb57c526ba17..368275de5f23 100644
356 --- a/tools/objtool/check.c
357 +++ b/tools/objtool/check.c
358 @@ -100,7 +100,6 @@ static bool gcov_enabled(struct objtool_file *file)
359 static bool ignore_func(struct objtool_file *file, struct symbol *func)
362 - struct instruction *insn;
364 /* check for STACK_FRAME_NON_STANDARD */
365 if (file->whitelist && file->whitelist->rela)
366 @@ -113,11 +112,6 @@ static bool ignore_func(struct objtool_file *file, struct symbol *func)
370 - /* check if it has a context switching instruction */
371 - func_for_each_insn(file, func, insn)
372 - if (insn->type == INSN_CONTEXT_SWITCH)
378 @@ -879,6 +873,99 @@ static int add_switch_table_alts(struct objtool_file *file)
382 +static int read_unwind_hints(struct objtool_file *file)
384 + struct section *sec, *relasec;
386 + struct unwind_hint *hint;
387 + struct instruction *insn;
388 + struct cfi_reg *cfa;
391 + sec = find_section_by_name(file->elf, ".discard.unwind_hints");
395 + relasec = sec->rela;
397 + WARN("missing .rela.discard.unwind_hints section");
401 + if (sec->len % sizeof(struct unwind_hint)) {
402 + WARN("struct unwind_hint size mismatch");
406 + file->hints = true;
408 + for (i = 0; i < sec->len / sizeof(struct unwind_hint); i++) {
409 + hint = (struct unwind_hint *)sec->data->d_buf + i;
411 + rela = find_rela_by_dest(sec, i * sizeof(*hint));
413 + WARN("can't find rela for unwind_hints[%d]", i);
417 + insn = find_insn(file, rela->sym->sec, rela->addend);
419 + WARN("can't find insn for unwind_hints[%d]", i);
423 + cfa = &insn->state.cfa;
425 + if (hint->type == UNWIND_HINT_TYPE_SAVE) {
429 + } else if (hint->type == UNWIND_HINT_TYPE_RESTORE) {
430 + insn->restore = true;
437 + switch (hint->sp_reg) {
438 + case ORC_REG_UNDEFINED:
439 + cfa->base = CFI_UNDEFINED;
442 + cfa->base = CFI_SP;
445 + cfa->base = CFI_BP;
447 + case ORC_REG_SP_INDIRECT:
448 + cfa->base = CFI_SP_INDIRECT;
451 + cfa->base = CFI_R10;
454 + cfa->base = CFI_R13;
457 + cfa->base = CFI_DI;
460 + cfa->base = CFI_DX;
463 + WARN_FUNC("unsupported unwind_hint sp base reg %d",
464 + insn->sec, insn->offset, hint->sp_reg);
468 + cfa->offset = hint->sp_offset;
469 + insn->state.type = hint->type;
475 static int decode_sections(struct objtool_file *file)
478 @@ -909,6 +996,10 @@ static int decode_sections(struct objtool_file *file)
482 + ret = read_unwind_hints(file);
489 @@ -1382,7 +1473,7 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
490 struct insn_state state)
492 struct alternative *alt;
493 - struct instruction *insn;
494 + struct instruction *insn, *next_insn;
496 struct symbol *func = NULL;
498 @@ -1397,6 +1488,8 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
502 + next_insn = next_insn_same_sec(file, insn);
504 if (file->c_file && insn->func) {
505 if (func && func != insn->func) {
506 WARN("%s() falls through to next function %s()",
507 @@ -1414,13 +1507,54 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
511 - if (!!insn_state_match(insn, &state))
512 + if (!insn->hint && !insn_state_match(insn, &state))
518 - insn->state = state;
520 + if (insn->restore) {
521 + struct instruction *save_insn, *i;
525 + func_for_each_insn_continue_reverse(file, func, i) {
533 + WARN_FUNC("no corresponding CFI save for CFI restore",
534 + sec, insn->offset);
538 + if (!save_insn->visited) {
540 + * Oops, no state to copy yet.
541 + * Hopefully we can reach this
542 + * instruction from another branch
543 + * after the save insn has been
549 + WARN_FUNC("objtool isn't smart enough to handle this CFI save/restore combo",
550 + sec, insn->offset);
554 + insn->state = save_insn->state;
557 + state = insn->state;
560 + insn->state = state;
562 insn->visited = true;
564 @@ -1497,6 +1631,14 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
568 + case INSN_CONTEXT_SWITCH:
569 + if (func && (!next_insn || !next_insn->hint)) {
570 + WARN_FUNC("unsupported instruction in callable function",
571 + sec, insn->offset);
577 if (update_insn_state(insn, &state))
579 @@ -1510,7 +1652,7 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
583 - insn = next_insn_same_sec(file, insn);
586 WARN("%s: unexpected end of section", sec->name);
588 @@ -1520,6 +1662,27 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
592 +static int validate_unwind_hints(struct objtool_file *file)
594 + struct instruction *insn;
595 + int ret, warnings = 0;
596 + struct insn_state state;
601 + clear_insn_state(&state);
603 + for_each_insn(file, insn) {
604 + if (insn->hint && !insn->visited) {
605 + ret = validate_branch(file, insn, state);
613 static bool is_kasan_insn(struct instruction *insn)
615 return (insn->type == INSN_CALL &&
616 @@ -1665,8 +1828,9 @@ int check(const char *_objname, bool _nofp, bool orc)
617 hash_init(file.insn_hash);
618 file.whitelist = find_section_by_name(file.elf, ".discard.func_stack_frame_non_standard");
619 file.rodata = find_section_by_name(file.elf, ".rodata");
620 - file.ignore_unreachables = false;
621 file.c_file = find_section_by_name(file.elf, ".comment");
622 + file.ignore_unreachables = false;
623 + file.hints = false;
625 arch_initial_func_cfi_state(&initial_func_cfi);
627 @@ -1683,6 +1847,11 @@ int check(const char *_objname, bool _nofp, bool orc)
631 + ret = validate_unwind_hints(&file);
637 ret = validate_reachable_instructions(&file);