Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull core fixes from Thomas Gleixner:

- A collection of objtool fixes which address recent fallout partially
exposed by newer toolchains, clang, BPF and general code changes.

- Force USER_DS for user stack traces

[ Note: the "objtool fixes" are not all to objtool itself, but for
kernel code that triggers objtool warnings.

Things like missing function size annotations, or code that confuses
the unwinder etc. - Linus]

* 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (27 commits)
objtool: Support conditional retpolines
objtool: Convert insn type to enum
objtool: Fix seg fault on bad switch table entry
objtool: Support repeated uses of the same C jump table
objtool: Refactor jump table code
objtool: Refactor sibling call detection logic
objtool: Do frame pointer check before dead end check
objtool: Change dead_end_function() to return boolean
objtool: Warn on zero-length functions
objtool: Refactor function alias logic
objtool: Track original function across branches
objtool: Add mcsafe_handle_tail() to the uaccess safe list
bpf: Disable GCC -fgcse optimization for ___bpf_prog_run()
x86/uaccess: Remove redundant CLACs in getuser/putuser error paths
x86/uaccess: Don't leak AC flag into fentry from mcsafe_handle_tail()
x86/uaccess: Remove ELF function annotation from copy_user_handle_tail()
x86/head/64: Annotate start_cpu0() as non-callable
x86/entry: Fix thunk function ELF sizes
x86/kvm: Don't call kvm_spurious_fault() from .fixup
x86/kvm: Replace vmx_vmenter()'s call to kvm_spurious_fault() with UD2
...

+312 -246
+2 -3
arch/x86/entry/thunk_64.S
··· 12 12 13 13 /* rdi: arg1 ... normal C conventions. rax is saved/restored. */ 14 14 .macro THUNK name, func, put_ret_addr_in_rdi=0 15 - .globl \name 16 - .type \name, @function 17 - \name: 15 + ENTRY(\name) 18 16 pushq %rbp 19 17 movq %rsp, %rbp 20 18 ··· 33 35 34 36 call \func 35 37 jmp .L_restore 38 + ENDPROC(\name) 36 39 _ASM_NOKPROBE(\name) 37 40 .endm 38 41
+19 -15
arch/x86/include/asm/kvm_host.h
··· 1496 1496 #define kvm_arch_vcpu_memslots_id(vcpu) ((vcpu)->arch.hflags & HF_SMM_MASK ? 1 : 0) 1497 1497 #define kvm_memslots_for_spte_role(kvm, role) __kvm_memslots(kvm, (role).smm) 1498 1498 1499 + asmlinkage void __noreturn kvm_spurious_fault(void); 1500 + 1499 1501 /* 1500 1502 * Hardware virtualization extension instructions may fault if a 1501 1503 * reboot turns off virtualization while processes are running. 1502 - * Trap the fault and ignore the instruction if that happens. 1504 + * Usually after catching the fault we just panic; during reboot 1505 + * instead the instruction is ignored. 1503 1506 */ 1504 - asmlinkage void kvm_spurious_fault(void); 1505 - 1506 - #define ____kvm_handle_fault_on_reboot(insn, cleanup_insn) \ 1507 - "666: " insn "\n\t" \ 1508 - "668: \n\t" \ 1509 - ".pushsection .fixup, \"ax\" \n" \ 1510 - "667: \n\t" \ 1511 - cleanup_insn "\n\t" \ 1512 - "cmpb $0, kvm_rebooting \n\t" \ 1513 - "jne 668b \n\t" \ 1514 - __ASM_SIZE(push) " $666b \n\t" \ 1515 - "jmp kvm_spurious_fault \n\t" \ 1516 - ".popsection \n\t" \ 1517 - _ASM_EXTABLE(666b, 667b) 1507 + #define ____kvm_handle_fault_on_reboot(insn, cleanup_insn) \ 1508 + "666: \n\t" \ 1509 + insn "\n\t" \ 1510 + "jmp 668f \n\t" \ 1511 + "667: \n\t" \ 1512 + "call kvm_spurious_fault \n\t" \ 1513 + "668: \n\t" \ 1514 + ".pushsection .fixup, \"ax\" \n\t" \ 1515 + "700: \n\t" \ 1516 + cleanup_insn "\n\t" \ 1517 + "cmpb $0, kvm_rebooting\n\t" \ 1518 + "je 667b \n\t" \ 1519 + "jmp 668b \n\t" \ 1520 + ".popsection \n\t" \ 1521 + _ASM_EXTABLE(666b, 700b) 1518 1522 1519 1523 #define __kvm_handle_fault_on_reboot(insn) \ 1520 1524 ____kvm_handle_fault_on_reboot(insn, "")
+1
arch/x86/include/asm/paravirt.h
··· 746 746 PV_RESTORE_ALL_CALLER_REGS \ 747 747 FRAME_END \ 748 748 "ret;" \ 749 + ".size " PV_THUNK_NAME(func) ", .-" PV_THUNK_NAME(func) ";" \ 749 750 ".popsection") 750 751 751 752 /* Get a reference to a callee-save function */
+2 -2
arch/x86/kernel/head_64.S
··· 253 253 * start_secondary() via .Ljump_to_C_code. 254 254 */ 255 255 ENTRY(start_cpu0) 256 - movq initial_stack(%rip), %rsp 257 256 UNWIND_HINT_EMPTY 257 + movq initial_stack(%rip), %rsp 258 258 jmp .Ljump_to_C_code 259 - ENDPROC(start_cpu0) 259 + END(start_cpu0) 260 260 #endif 261 261 262 262 /* Both SMP bootup and ACPI suspend change these variables */
+1
arch/x86/kernel/kvm.c
··· 838 838 "cmpb $0, " __stringify(KVM_STEAL_TIME_preempted) "+steal_time(%rax);" 839 839 "setne %al;" 840 840 "ret;" 841 + ".size __raw_callee_save___kvm_vcpu_is_preempted, .-__raw_callee_save___kvm_vcpu_is_preempted;" 841 842 ".popsection"); 842 843 843 844 #endif
+31 -13
arch/x86/kvm/emulate.c
··· 312 312 313 313 static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *)); 314 314 315 - #define FOP_FUNC(name) \ 315 + #define __FOP_FUNC(name) \ 316 316 ".align " __stringify(FASTOP_SIZE) " \n\t" \ 317 317 ".type " name ", @function \n\t" \ 318 318 name ":\n\t" 319 319 320 - #define FOP_RET "ret \n\t" 320 + #define FOP_FUNC(name) \ 321 + __FOP_FUNC(#name) 322 + 323 + #define __FOP_RET(name) \ 324 + "ret \n\t" \ 325 + ".size " name ", .-" name "\n\t" 326 + 327 + #define FOP_RET(name) \ 328 + __FOP_RET(#name) 321 329 322 330 #define FOP_START(op) \ 323 331 extern void em_##op(struct fastop *fake); \ 324 332 asm(".pushsection .text, \"ax\" \n\t" \ 325 333 ".global em_" #op " \n\t" \ 326 - FOP_FUNC("em_" #op) 334 + ".align " __stringify(FASTOP_SIZE) " \n\t" \ 335 + "em_" #op ":\n\t" 327 336 328 337 #define FOP_END \ 329 338 ".popsection") 330 339 340 + #define __FOPNOP(name) \ 341 + __FOP_FUNC(name) \ 342 + __FOP_RET(name) 343 + 331 344 #define FOPNOP() \ 332 - FOP_FUNC(__stringify(__UNIQUE_ID(nop))) \ 333 - FOP_RET 345 + __FOPNOP(__stringify(__UNIQUE_ID(nop))) 334 346 335 347 #define FOP1E(op, dst) \ 336 - FOP_FUNC(#op "_" #dst) \ 337 - "10: " #op " %" #dst " \n\t" FOP_RET 348 + __FOP_FUNC(#op "_" #dst) \ 349 + "10: " #op " %" #dst " \n\t" \ 350 + __FOP_RET(#op "_" #dst) 338 351 339 352 #define FOP1EEX(op, dst) \ 340 353 FOP1E(op, dst) _ASM_EXTABLE(10b, kvm_fastop_exception) ··· 379 366 FOP_END 380 367 381 368 #define FOP2E(op, dst, src) \ 382 - FOP_FUNC(#op "_" #dst "_" #src) \ 383 - #op " %" #src ", %" #dst " \n\t" FOP_RET 369 + __FOP_FUNC(#op "_" #dst "_" #src) \ 370 + #op " %" #src ", %" #dst " \n\t" \ 371 + __FOP_RET(#op "_" #dst "_" #src) 384 372 385 373 #define FASTOP2(op) \ 386 374 FOP_START(op) \ ··· 419 405 FOP_END 420 406 421 407 #define FOP3E(op, dst, src, src2) \ 422 - FOP_FUNC(#op "_" #dst "_" #src "_" #src2) \ 423 - #op " %" #src2 ", %" #src ", %" #dst " \n\t" FOP_RET 408 + __FOP_FUNC(#op "_" #dst "_" #src "_" #src2) \ 409 + #op " %" #src2 ", %" #src ", %" #dst " \n\t"\ 410 + __FOP_RET(#op "_" #dst "_" #src "_" #src2) 424 411 425 412 /* 3-operand, word-only, src2=cl */ 426 413 #define FASTOP3WCL(op) \ ··· 438 423 ".type " #op ", @function \n\t" \ 439 424 #op ": \n\t" \ 440 425 #op " %al \n\t" \ 441 - FOP_RET 426 + __FOP_RET(#op) 442 427 443 428 asm(".pushsection .fixup, \"ax\"\n" 444 429 ".global kvm_fastop_exception \n" ··· 464 449 FOP_SETCC(setnle) 465 450 FOP_END; 466 451 467 - FOP_START(salc) "pushf; sbb %al, %al; popf \n\t" FOP_RET 452 + FOP_START(salc) 453 + FOP_FUNC(salc) 454 + "pushf; sbb %al, %al; popf \n\t" 455 + FOP_RET(salc) 468 456 FOP_END; 469 457 470 458 /*
+3 -3
arch/x86/kvm/vmx/vmenter.S
··· 54 54 ret 55 55 56 56 3: cmpb $0, kvm_rebooting 57 - jne 4f 58 - call kvm_spurious_fault 59 - 4: ret 57 + je 4f 58 + ret 59 + 4: ud2 60 60 61 61 .pushsection .fixup, "ax" 62 62 5: jmp 3b
+1 -1
arch/x86/lib/copy_user_64.S
··· 239 239 ret 240 240 241 241 _ASM_EXTABLE_UA(1b, 2b) 242 - ENDPROC(copy_user_handle_tail) 242 + END(copy_user_handle_tail) 243 243 244 244 /* 245 245 * copy_user_nocache - Uncached memory copy with exception handling
+10 -10
arch/x86/lib/getuser.S
··· 115 115 EXPORT_SYMBOL(__get_user_8) 116 116 117 117 118 + bad_get_user_clac: 119 + ASM_CLAC 118 120 bad_get_user: 119 121 xor %edx,%edx 120 122 mov $(-EFAULT),%_ASM_AX 121 - ASM_CLAC 122 123 ret 123 - END(bad_get_user) 124 124 125 125 #ifdef CONFIG_X86_32 126 + bad_get_user_8_clac: 127 + ASM_CLAC 126 128 bad_get_user_8: 127 129 xor %edx,%edx 128 130 xor %ecx,%ecx 129 131 mov $(-EFAULT),%_ASM_AX 130 - ASM_CLAC 131 132 ret 132 - END(bad_get_user_8) 133 133 #endif 134 134 135 - _ASM_EXTABLE_UA(1b, bad_get_user) 136 - _ASM_EXTABLE_UA(2b, bad_get_user) 137 - _ASM_EXTABLE_UA(3b, bad_get_user) 135 + _ASM_EXTABLE_UA(1b, bad_get_user_clac) 136 + _ASM_EXTABLE_UA(2b, bad_get_user_clac) 137 + _ASM_EXTABLE_UA(3b, bad_get_user_clac) 138 138 #ifdef CONFIG_X86_64 139 - _ASM_EXTABLE_UA(4b, bad_get_user) 139 + _ASM_EXTABLE_UA(4b, bad_get_user_clac) 140 140 #else 141 - _ASM_EXTABLE_UA(4b, bad_get_user_8) 142 - _ASM_EXTABLE_UA(5b, bad_get_user_8) 141 + _ASM_EXTABLE_UA(4b, bad_get_user_8_clac) 142 + _ASM_EXTABLE_UA(5b, bad_get_user_8_clac) 143 143 #endif
+16 -13
arch/x86/lib/putuser.S
··· 32 32 */ 33 33 34 34 #define ENTER mov PER_CPU_VAR(current_task), %_ASM_BX 35 - #define EXIT ASM_CLAC ; \ 36 - ret 37 35 38 36 .text 39 37 ENTRY(__put_user_1) ··· 41 43 ASM_STAC 42 44 1: movb %al,(%_ASM_CX) 43 45 xor %eax,%eax 44 - EXIT 46 + ASM_CLAC 47 + ret 45 48 ENDPROC(__put_user_1) 46 49 EXPORT_SYMBOL(__put_user_1) 47 50 ··· 55 56 ASM_STAC 56 57 2: movw %ax,(%_ASM_CX) 57 58 xor %eax,%eax 58 - EXIT 59 + ASM_CLAC 60 + ret 59 61 ENDPROC(__put_user_2) 60 62 EXPORT_SYMBOL(__put_user_2) 61 63 ··· 69 69 ASM_STAC 70 70 3: movl %eax,(%_ASM_CX) 71 71 xor %eax,%eax 72 - EXIT 72 + ASM_CLAC 73 + ret 73 74 ENDPROC(__put_user_4) 74 75 EXPORT_SYMBOL(__put_user_4) 75 76 ··· 86 85 5: movl %edx,4(%_ASM_CX) 87 86 #endif 88 87 xor %eax,%eax 89 - EXIT 88 + ASM_CLAC 89 + RET 90 90 ENDPROC(__put_user_8) 91 91 EXPORT_SYMBOL(__put_user_8) 92 92 93 + bad_put_user_clac: 94 + ASM_CLAC 93 95 bad_put_user: 94 96 movl $-EFAULT,%eax 95 - EXIT 96 - END(bad_put_user) 97 + RET 97 98 98 - _ASM_EXTABLE_UA(1b, bad_put_user) 99 - _ASM_EXTABLE_UA(2b, bad_put_user) 100 - _ASM_EXTABLE_UA(3b, bad_put_user) 101 - _ASM_EXTABLE_UA(4b, bad_put_user) 99 + _ASM_EXTABLE_UA(1b, bad_put_user_clac) 100 + _ASM_EXTABLE_UA(2b, bad_put_user_clac) 101 + _ASM_EXTABLE_UA(3b, bad_put_user_clac) 102 + _ASM_EXTABLE_UA(4b, bad_put_user_clac) 102 103 #ifdef CONFIG_X86_32 103 - _ASM_EXTABLE_UA(5b, bad_put_user) 104 + _ASM_EXTABLE_UA(5b, bad_put_user_clac) 104 105 #endif
+1 -1
arch/x86/lib/usercopy_64.c
··· 60 60 * but reuse __memcpy_mcsafe in case a new read error is encountered. 61 61 * clac() is handled in _copy_to_iter_mcsafe(). 62 62 */ 63 - __visible unsigned long 63 + __visible notrace unsigned long 64 64 mcsafe_handle_tail(char *to, char *from, unsigned len) 65 65 { 66 66 for (; len; --len, to++, from++) {
+2
include/linux/compiler-gcc.h
··· 170 170 #else 171 171 #define __diag_GCC_8(s) 172 172 #endif 173 + 174 + #define __no_fgcse __attribute__((optimize("-fno-gcse")))
+5
include/linux/compiler.h
··· 116 116 ".pushsection .discard.unreachable\n\t" \ 117 117 ".long 999b - .\n\t" \ 118 118 ".popsection\n\t" 119 + 120 + /* Annotate a C jump table to allow objtool to follow the code flow */ 121 + #define __annotate_jump_table __section(".rodata..c_jump_table") 122 + 119 123 #else 120 124 #define annotate_reachable() 121 125 #define annotate_unreachable() 126 + #define __annotate_jump_table 122 127 #endif 123 128 124 129 #ifndef ASM_UNREACHABLE
+4
include/linux/compiler_types.h
··· 189 189 #define asm_volatile_goto(x...) asm goto(x) 190 190 #endif 191 191 192 + #ifndef __no_fgcse 193 + # define __no_fgcse 194 + #endif 195 + 192 196 /* Are two types/vars the same type (ignoring qualifiers)? */ 193 197 #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) 194 198
+2 -3
kernel/bpf/core.c
··· 1295 1295 * 1296 1296 * Decode and execute eBPF instructions. 1297 1297 */ 1298 - static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, u64 *stack) 1298 + static u64 __no_fgcse ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, u64 *stack) 1299 1299 { 1300 1300 #define BPF_INSN_2_LBL(x, y) [BPF_##x | BPF_##y] = &&x##_##y 1301 1301 #define BPF_INSN_3_LBL(x, y, z) [BPF_##x | BPF_##y | BPF_##z] = &&x##_##y##_##z 1302 - static const void *jumptable[256] = { 1302 + static const void * const jumptable[256] __annotate_jump_table = { 1303 1303 [0 ... 255] = &&default_label, 1304 1304 /* Now overwrite non-defaults ... */ 1305 1305 BPF_INSN_MAP(BPF_INSN_2_LBL, BPF_INSN_3_LBL), ··· 1558 1558 BUG_ON(1); 1559 1559 return 0; 1560 1560 } 1561 - STACK_FRAME_NON_STANDARD(___bpf_prog_run); /* jump table */ 1562 1561 1563 1562 #define PROG_NAME(stack_size) __bpf_prog_run##stack_size 1564 1563 #define DEFINE_BPF_PROG_RUN(stack_size) \
+5
kernel/stacktrace.c
··· 226 226 .store = store, 227 227 .size = size, 228 228 }; 229 + mm_segment_t fs; 229 230 230 231 /* Trace user stack if not a kernel thread */ 231 232 if (current->flags & PF_KTHREAD) 232 233 return 0; 233 234 235 + fs = get_fs(); 236 + set_fs(USER_DS); 234 237 arch_stack_walk_user(consume_entry, &c, task_pt_regs(current)); 238 + set_fs(fs); 239 + 235 240 return c.len; 236 241 } 237 242 #endif
+19 -17
tools/objtool/arch.h
··· 11 11 #include "elf.h" 12 12 #include "cfi.h" 13 13 14 - #define INSN_JUMP_CONDITIONAL 1 15 - #define INSN_JUMP_UNCONDITIONAL 2 16 - #define INSN_JUMP_DYNAMIC 3 17 - #define INSN_CALL 4 18 - #define INSN_CALL_DYNAMIC 5 19 - #define INSN_RETURN 6 20 - #define INSN_CONTEXT_SWITCH 7 21 - #define INSN_STACK 8 22 - #define INSN_BUG 9 23 - #define INSN_NOP 10 24 - #define INSN_STAC 11 25 - #define INSN_CLAC 12 26 - #define INSN_STD 13 27 - #define INSN_CLD 14 28 - #define INSN_OTHER 15 29 - #define INSN_LAST INSN_OTHER 14 + enum insn_type { 15 + INSN_JUMP_CONDITIONAL, 16 + INSN_JUMP_UNCONDITIONAL, 17 + INSN_JUMP_DYNAMIC, 18 + INSN_JUMP_DYNAMIC_CONDITIONAL, 19 + INSN_CALL, 20 + INSN_CALL_DYNAMIC, 21 + INSN_RETURN, 22 + INSN_CONTEXT_SWITCH, 23 + INSN_STACK, 24 + INSN_BUG, 25 + INSN_NOP, 26 + INSN_STAC, 27 + INSN_CLAC, 28 + INSN_STD, 29 + INSN_CLD, 30 + INSN_OTHER, 31 + }; 30 32 31 33 enum op_dest_type { 32 34 OP_DEST_REG, ··· 70 68 71 69 int arch_decode_instruction(struct elf *elf, struct section *sec, 72 70 unsigned long offset, unsigned int maxlen, 73 - unsigned int *len, unsigned char *type, 71 + unsigned int *len, enum insn_type *type, 74 72 unsigned long *immediate, struct stack_op *op); 75 73 76 74 bool arch_callee_saved_reg(unsigned char reg);
+1 -1
tools/objtool/arch/x86/decode.c
··· 68 68 69 69 int arch_decode_instruction(struct elf *elf, struct section *sec, 70 70 unsigned long offset, unsigned int maxlen, 71 - unsigned int *len, unsigned char *type, 71 + unsigned int *len, enum insn_type *type, 72 72 unsigned long *immediate, struct stack_op *op) 73 73 { 74 74 struct insn insn;
+178 -157
tools/objtool/check.c
··· 18 18 19 19 #define FAKE_JUMP_OFFSET -1 20 20 21 + #define C_JUMP_TABLE_SECTION ".rodata..c_jump_table" 22 + 21 23 struct alternative { 22 24 struct list_head list; 23 25 struct instruction *insn; ··· 97 95 for (insn = next_insn_same_sec(file, insn); insn; \ 98 96 insn = next_insn_same_sec(file, insn)) 99 97 98 + static bool is_sibling_call(struct instruction *insn) 99 + { 100 + /* An indirect jump is either a sibling call or a jump to a table. */ 101 + if (insn->type == INSN_JUMP_DYNAMIC) 102 + return list_empty(&insn->alts); 103 + 104 + if (insn->type != INSN_JUMP_CONDITIONAL && 105 + insn->type != INSN_JUMP_UNCONDITIONAL) 106 + return false; 107 + 108 + /* add_jump_destinations() sets insn->call_dest for sibling calls. */ 109 + return !!insn->call_dest; 110 + } 111 + 100 112 /* 101 113 * This checks to see if the given function is a "noreturn" function. 102 114 * ··· 119 103 * 120 104 * For local functions, we have to detect them manually by simply looking for 121 105 * the lack of a return instruction. 122 - * 123 - * Returns: 124 - * -1: error 125 - * 0: no dead end 126 - * 1: dead end 127 106 */ 128 - static int __dead_end_function(struct objtool_file *file, struct symbol *func, 129 - int recursion) 107 + static bool __dead_end_function(struct objtool_file *file, struct symbol *func, 108 + int recursion) 130 109 { 131 110 int i; 132 111 struct instruction *insn; ··· 147 136 "rewind_stack_do_exit", 148 137 }; 149 138 139 + if (!func) 140 + return false; 141 + 150 142 if (func->bind == STB_WEAK) 151 - return 0; 143 + return false; 152 144 153 145 if (func->bind == STB_GLOBAL) 154 146 for (i = 0; i < ARRAY_SIZE(global_noreturns); i++) 155 147 if (!strcmp(func->name, global_noreturns[i])) 156 - return 1; 148 + return true; 157 149 158 150 if (!func->len) 159 - return 0; 151 + return false; 160 152 161 153 insn = find_insn(file, func->sec, func->offset); 162 154 if (!insn->func) 163 - return 0; 155 + return false; 164 156 165 157 func_for_each_insn_all(file, func, insn) { 166 158 empty = false; 167 159 168 160 if (insn->type == INSN_RETURN) 169 - return 0; 161 + return false; 170 162 } 171 163 172 164 if (empty) 173 - return 0; 165 + return false; 174 166 175 167 /* 176 168 * A function can have a sibling call instead of a return. In that ··· 181 167 * of the sibling call returns. 182 168 */ 183 169 func_for_each_insn_all(file, func, insn) { 184 - if (insn->type == INSN_JUMP_UNCONDITIONAL) { 170 + if (is_sibling_call(insn)) { 185 171 struct instruction *dest = insn->jump_dest; 186 172 187 173 if (!dest) 188 174 /* sibling call to another file */ 189 - return 0; 175 + return false; 190 176 191 - if (dest->func && dest->func->pfunc != insn->func->pfunc) { 192 - 193 - /* local sibling call */ 194 - if (recursion == 5) { 195 - /* 196 - * Infinite recursion: two functions 197 - * have sibling calls to each other. 198 - * This is a very rare case. It means 199 - * they aren't dead ends. 200 - */ 201 - return 0; 202 - } 203 - 204 - return __dead_end_function(file, dest->func, 205 - recursion + 1); 177 + /* local sibling call */ 178 + if (recursion == 5) { 179 + /* 180 + * Infinite recursion: two functions have 181 + * sibling calls to each other. This is a very 182 + * rare case. It means they aren't dead ends. 183 + */ 184 + return false; 206 185 } 207 - } 208 186 209 - if (insn->type == INSN_JUMP_DYNAMIC && list_empty(&insn->alts)) 210 - /* sibling call */ 211 - return 0; 187 + return __dead_end_function(file, dest->func, recursion+1); 188 + } 212 189 } 213 190 214 - return 1; 191 + return true; 215 192 } 216 193 217 - static int dead_end_function(struct objtool_file *file, struct symbol *func) 194 + static bool dead_end_function(struct objtool_file *file, struct symbol *func) 218 195 { 219 196 return __dead_end_function(file, func, 0); 220 197 } ··· 267 262 if (ret) 268 263 goto err; 269 264 270 - if (!insn->type || insn->type > INSN_LAST) { 271 - WARN_FUNC("invalid instruction type %d", 272 - insn->sec, insn->offset, insn->type); 273 - ret = -1; 274 - goto err; 275 - } 276 - 277 265 hash_add(file->insn_hash, &insn->hash, insn->offset); 278 266 list_add_tail(&insn->list, &file->insn_list); 279 267 } 280 268 281 269 list_for_each_entry(func, &sec->symbol_list, list) { 282 - if (func->type != STT_FUNC) 270 + if (func->type != STT_FUNC || func->alias != func) 283 271 continue; 284 272 285 273 if (!find_insn(file, sec, func->offset)) { ··· 282 284 } 283 285 284 286 func_for_each_insn(file, func, insn) 285 - if (!insn->func) 286 - insn->func = func; 287 + insn->func = func; 287 288 } 288 289 } 289 290 ··· 485 488 /* misc */ 486 489 "csum_partial_copy_generic", 487 490 "__memcpy_mcsafe", 491 + "mcsafe_handle_tail", 488 492 "ftrace_likely_update", /* CONFIG_TRACE_BRANCH_PROFILING */ 489 493 NULL 490 494 }; ··· 503 505 if (!func) 504 506 continue; 505 507 506 - func->alias->uaccess_safe = true; 508 + func->uaccess_safe = true; 507 509 } 508 510 } 509 511 ··· 575 577 * Retpoline jumps are really dynamic jumps in 576 578 * disguise, so convert them accordingly. 577 579 */ 578 - insn->type = INSN_JUMP_DYNAMIC; 580 + if (insn->type == INSN_JUMP_UNCONDITIONAL) 581 + insn->type = INSN_JUMP_DYNAMIC; 582 + else 583 + insn->type = INSN_JUMP_DYNAMIC_CONDITIONAL; 584 + 579 585 insn->retpoline_safe = true; 580 586 continue; 581 587 } else { 582 - /* sibling call */ 588 + /* external sibling call */ 583 589 insn->call_dest = rela->sym; 584 - insn->jump_dest = NULL; 585 590 continue; 586 591 } 587 592 ··· 624 623 * However this code can't completely replace the 625 624 * read_symbols() code because this doesn't detect the 626 625 * case where the parent function's only reference to a 627 - * subfunction is through a switch table. 626 + * subfunction is through a jump table. 628 627 */ 629 628 if (!strstr(insn->func->name, ".cold.") && 630 629 strstr(insn->jump_dest->func->name, ".cold.")) { ··· 634 633 } else if (insn->jump_dest->func->pfunc != insn->func->pfunc && 635 634 insn->jump_dest->offset == insn->jump_dest->func->offset) { 636 635 637 - /* sibling class */ 636 + /* internal sibling call */ 638 637 insn->call_dest = insn->jump_dest->func; 639 - insn->jump_dest = NULL; 640 638 } 641 639 } 642 640 } ··· 896 896 return ret; 897 897 } 898 898 899 - static int add_switch_table(struct objtool_file *file, struct instruction *insn, 900 - struct rela *table, struct rela *next_table) 899 + static int add_jump_table(struct objtool_file *file, struct instruction *insn, 900 + struct rela *table) 901 901 { 902 902 struct rela *rela = table; 903 - struct instruction *alt_insn; 903 + struct instruction *dest_insn; 904 904 struct alternative *alt; 905 905 struct symbol *pfunc = insn->func->pfunc; 906 906 unsigned int prev_offset = 0; 907 907 908 - list_for_each_entry_from(rela, &table->rela_sec->rela_list, list) { 909 - if (rela == next_table) 908 + /* 909 + * Each @rela is a switch table relocation which points to the target 910 + * instruction. 911 + */ 912 + list_for_each_entry_from(rela, &table->sec->rela_list, list) { 913 + 914 + /* Check for the end of the table: */ 915 + if (rela != table && rela->jump_table_start) 910 916 break; 911 917 912 - /* Make sure the switch table entries are consecutive: */ 918 + /* Make sure the table entries are consecutive: */ 913 919 if (prev_offset && rela->offset != prev_offset + 8) 914 920 break; 915 921 ··· 924 918 rela->addend == pfunc->offset) 925 919 break; 926 920 927 - alt_insn = find_insn(file, rela->sym->sec, rela->addend); 928 - if (!alt_insn) 921 + dest_insn = find_insn(file, rela->sym->sec, rela->addend); 922 + if (!dest_insn) 929 923 break; 930 924 931 - /* Make sure the jmp dest is in the function or subfunction: */ 932 - if (alt_insn->func->pfunc != pfunc) 925 + /* Make sure the destination is in the same function: */ 926 + if (!dest_insn->func || dest_insn->func->pfunc != pfunc) 933 927 break; 934 928 935 929 alt = malloc(sizeof(*alt)); ··· 938 932 return -1; 939 933 } 940 934 941 - alt->insn = alt_insn; 935 + alt->insn = dest_insn; 942 936 list_add_tail(&alt->list, &insn->alts); 943 937 prev_offset = rela->offset; 944 938 } ··· 953 947 } 954 948 955 949 /* 956 - * find_switch_table() - Given a dynamic jump, find the switch jump table in 950 + * find_jump_table() - Given a dynamic jump, find the switch jump table in 957 951 * .rodata associated with it. 958 952 * 959 953 * There are 3 basic patterns: ··· 995 989 * 996 990 * NOTE: RETPOLINE made it harder still to decode dynamic jumps. 997 991 */ 998 - static struct rela *find_switch_table(struct objtool_file *file, 992 + static struct rela *find_jump_table(struct objtool_file *file, 999 993 struct symbol *func, 1000 994 struct instruction *insn) 1001 995 { 1002 - struct rela *text_rela, *rodata_rela; 996 + struct rela *text_rela, *table_rela; 1003 997 struct instruction *orig_insn = insn; 1004 - struct section *rodata_sec; 998 + struct section *table_sec; 1005 999 unsigned long table_offset; 1006 1000 1007 1001 /* ··· 1034 1028 continue; 1035 1029 1036 1030 table_offset = text_rela->addend; 1037 - rodata_sec = text_rela->sym->sec; 1031 + table_sec = text_rela->sym->sec; 1038 1032 1039 1033 if (text_rela->type == R_X86_64_PC32) 1040 1034 table_offset += 4; 1041 1035 1042 1036 /* 1043 1037 * Make sure the .rodata address isn't associated with a 1044 - * symbol. gcc jump tables are anonymous data. 1038 + * symbol. GCC jump tables are anonymous data. 1039 + * 1040 + * Also support C jump tables which are in the same format as 1041 + * switch jump tables. For objtool to recognize them, they 1042 + * need to be placed in the C_JUMP_TABLE_SECTION section. They 1043 + * have symbols associated with them. 1045 1044 */ 1046 - if (find_symbol_containing(rodata_sec, table_offset)) 1045 + if (find_symbol_containing(table_sec, table_offset) && 1046 + strcmp(table_sec->name, C_JUMP_TABLE_SECTION)) 1047 1047 continue; 1048 1048 1049 - rodata_rela = find_rela_by_dest(rodata_sec, table_offset); 1050 - if (rodata_rela) { 1051 - /* 1052 - * Use of RIP-relative switch jumps is quite rare, and 1053 - * indicates a rare GCC quirk/bug which can leave dead 1054 - * code behind. 1055 - */ 1056 - if (text_rela->type == R_X86_64_PC32) 1057 - file->ignore_unreachables = true; 1049 + /* Each table entry has a rela associated with it. */ 1050 + table_rela = find_rela_by_dest(table_sec, table_offset); 1051 + if (!table_rela) 1052 + continue; 1058 1053 1059 - return rodata_rela; 1060 - } 1054 + /* 1055 + * Use of RIP-relative switch jumps is quite rare, and 1056 + * indicates a rare GCC quirk/bug which can leave dead code 1057 + * behind. 1058 + */ 1059 + if (text_rela->type == R_X86_64_PC32) 1060 + file->ignore_unreachables = true; 1061 + 1062 + return table_rela; 1061 1063 } 1062 1064 1063 1065 return NULL; 1064 1066 } 1065 1067 1066 - 1067 - static int add_func_switch_tables(struct objtool_file *file, 1068 - struct symbol *func) 1068 + /* 1069 + * First pass: Mark the head of each jump table so that in the next pass, 1070 + * we know when a given jump table ends and the next one starts. 1071 + */ 1072 + static void mark_func_jump_tables(struct objtool_file *file, 1073 + struct symbol *func) 1069 1074 { 1070 - struct instruction *insn, *last = NULL, *prev_jump = NULL; 1071 - struct rela *rela, *prev_rela = NULL; 1072 - int ret; 1075 + struct instruction *insn, *last = NULL; 1076 + struct rela *rela; 1073 1077 1074 1078 func_for_each_insn_all(file, func, insn) { 1075 1079 if (!last) ··· 1087 1071 1088 1072 /* 1089 1073 * Store back-pointers for unconditional forward jumps such 1090 - * that find_switch_table() can back-track using those and 1074 + * that find_jump_table() can back-track using those and 1091 1075 * avoid some potentially confusing code. 1092 1076 */ 1093 1077 if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest && ··· 1102 1086 if (insn->type != INSN_JUMP_DYNAMIC) 1103 1087 continue; 1104 1088 1105 - rela = find_switch_table(file, func, insn); 1106 - if (!rela) 1089 + rela = find_jump_table(file, func, insn); 1090 + if (rela) { 1091 + rela->jump_table_start = true; 1092 + insn->jump_table = rela; 1093 + } 1094 + } 1095 + } 1096 + 1097 + static int add_func_jump_tables(struct objtool_file *file, 1098 + struct symbol *func) 1099 + { 1100 + struct instruction *insn; 1101 + int ret; 1102 + 1103 + func_for_each_insn_all(file, func, insn) { 1104 + if (!insn->jump_table) 1107 1105 continue; 1108 1106 1109 - /* 1110 - * We found a switch table, but we don't know yet how big it 1111 - * is. Don't add it until we reach the end of the function or 1112 - * the beginning of another switch table in the same function. 1113 - */ 1114 - if (prev_jump) { 1115 - ret = add_switch_table(file, prev_jump, prev_rela, rela); 1116 - if (ret) 1117 - return ret; 1118 - } 1119 - 1120 - prev_jump = insn; 1121 - prev_rela = rela; 1122 - } 1123 - 1124 - if (prev_jump) { 1125 - ret = add_switch_table(file, prev_jump, prev_rela, NULL); 1107 + ret = add_jump_table(file, insn, insn->jump_table); 1126 1108 if (ret) 1127 1109 return ret; 1128 1110 } ··· 1133 1119 * section which contains a list of addresses within the function to jump to. 1134 1120 * This finds these jump tables and adds them to the insn->alts lists. 1135 1121 */ 1136 - static int add_switch_table_alts(struct objtool_file *file) 1122 + static int add_jump_table_alts(struct objtool_file *file) 1137 1123 { 1138 1124 struct section *sec; 1139 1125 struct symbol *func; ··· 1147 1133 if (func->type != STT_FUNC) 1148 1134 continue; 1149 1135 1150 - ret = add_func_switch_tables(file, func); 1136 + mark_func_jump_tables(file, func); 1137 + ret = add_func_jump_tables(file, func); 1151 1138 if (ret) 1152 1139 return ret; 1153 1140 } ··· 1292 1277 bool found = false; 1293 1278 1294 1279 /* 1295 - * This searches for the .rodata section or multiple .rodata.func_name 1296 - * sections if -fdata-sections is being used. The .str.1.1 and .str.1.8 1297 - * rodata sections are ignored as they don't contain jump tables. 1280 + * Search for the following rodata sections, each of which can 1281 + * potentially contain jump tables: 1282 + * 1283 + * - .rodata: can contain GCC switch tables 1284 + * - .rodata.<func>: same, if -fdata-sections is being used 1285 + * - .rodata..c_jump_table: contains C annotated jump tables 1286 + * 1287 + * .rodata.str1.* sections are ignored; they don't contain jump tables. 1298 1288 */ 1299 1289 for_each_sec(file, sec) { 1300 - if (!strncmp(sec->name, ".rodata", 7) && 1301 - !strstr(sec->name, ".str1.")) { 1290 + if ((!strncmp(sec->name, ".rodata", 7) && !strstr(sec->name, ".str1.")) || 1291 + !strcmp(sec->name, C_JUMP_TABLE_SECTION)) { 1302 1292 sec->rodata = true; 1303 1293 found = true; 1304 1294 } ··· 1345 1325 if (ret) 1346 1326 return ret; 1347 1327 1348 - ret = add_switch_table_alts(file); 1328 + ret = add_jump_table_alts(file); 1349 1329 if (ret) 1350 1330 return ret; 1351 1331 ··· 1893 1873 static inline bool func_uaccess_safe(struct symbol *func) 1894 1874 { 1895 1875 if (func) 1896 - return func->alias->uaccess_safe; 1876 + return func->uaccess_safe; 1897 1877 1898 1878 return false; 1899 1879 } 1900 1880 1901 - static inline const char *insn_dest_name(struct instruction *insn) 1881 + static inline const char *call_dest_name(struct instruction *insn) 1902 1882 { 1903 1883 if (insn->call_dest) 1904 1884 return insn->call_dest->name; ··· 1910 1890 { 1911 1891 if (state->uaccess && !func_uaccess_safe(insn->call_dest)) { 1912 1892 WARN_FUNC("call to %s() with UACCESS enabled", 1913 - insn->sec, insn->offset, insn_dest_name(insn)); 1893 + insn->sec, insn->offset, call_dest_name(insn)); 1914 1894 return 1; 1915 1895 } 1916 1896 1917 1897 if (state->df) { 1918 1898 WARN_FUNC("call to %s() with DF set", 1919 - insn->sec, insn->offset, insn_dest_name(insn)); 1899 + insn->sec, insn->offset, call_dest_name(insn)); 1920 1900 return 1; 1921 1901 } 1922 1902 ··· 1940 1920 * each instruction and validate all the rules described in 1941 1921 * tools/objtool/Documentation/stack-validation.txt. 1942 1922 */ 1943 - static int validate_branch(struct objtool_file *file, struct instruction *first, 1944 - struct insn_state state) 1923 + static int validate_branch(struct objtool_file *file, struct symbol *func, 1924 + struct instruction *first, struct insn_state state) 1945 1925 { 1946 1926 struct alternative *alt; 1947 1927 struct instruction *insn, *next_insn; 1948 1928 struct section *sec; 1949 - struct symbol *func = NULL; 1950 1929 int ret; 1951 1930 1952 1931 insn = first; ··· 1965 1946 func->name, insn->func->name); 1966 1947 return 1; 1967 1948 } 1968 - 1969 - if (insn->func) 1970 - func = insn->func->pfunc; 1971 1949 1972 1950 if (func && insn->ignore) { 1973 1951 WARN_FUNC("BUG: why am I validating an ignored function?", ··· 1987 1971 1988 1972 i = insn; 1989 1973 save_insn = NULL; 1990 - func_for_each_insn_continue_reverse(file, insn->func, i) { 1974 + func_for_each_insn_continue_reverse(file, func, i) { 1991 1975 if (i->save) { 1992 1976 save_insn = i; 1993 1977 break; ··· 2033 2017 if (alt->skip_orig) 2034 2018 skip_orig = true; 2035 2019 2036 - ret = validate_branch(file, alt->insn, state); 2020 + ret = validate_branch(file, func, alt->insn, state); 2037 2021 if (ret) { 2038 2022 if (backtrace) 2039 2023 BT_FUNC("(alt)", insn); ··· 2071 2055 2072 2056 if (state.bp_scratch) { 2073 2057 WARN("%s uses BP as a scratch register", 2074 - insn->func->name); 2058 + func->name); 2075 2059 return 1; 2076 2060 } 2077 2061 ··· 2083 2067 if (ret) 2084 2068 return ret; 2085 2069 2086 - if (insn->type == INSN_CALL) { 2087 - if (is_fentry_call(insn)) 2088 - break; 2089 - 2090 - ret = dead_end_function(file, insn->call_dest); 2091 - if (ret == 1) 2092 - return 0; 2093 - if (ret == -1) 2094 - return 1; 2095 - } 2096 - 2097 - if (!no_fp && func && !has_valid_stack_frame(&state)) { 2070 + if (!no_fp && func && !is_fentry_call(insn) && 2071 + !has_valid_stack_frame(&state)) { 2098 2072 WARN_FUNC("call without frame pointer save/setup", 2099 2073 sec, insn->offset); 2100 2074 return 1; 2101 2075 } 2076 + 2077 + if (dead_end_function(file, insn->call_dest)) 2078 + return 0; 2079 + 2102 2080 break; 2103 2081 2104 2082 case INSN_JUMP_CONDITIONAL: 2105 2083 case INSN_JUMP_UNCONDITIONAL: 2106 - if (func && !insn->jump_dest) { 2084 + if (func && is_sibling_call(insn)) { 2107 2085 ret = validate_sibling_call(insn, &state); 2108 2086 if (ret) 2109 2087 return ret; 2110 2088 2111 - } else if (insn->jump_dest && 2112 - (!func || !insn->jump_dest->func || 2113 - insn->jump_dest->func->pfunc == func)) { 2114 - ret = validate_branch(file, insn->jump_dest, 2115 - state); 2089 + } else if (insn->jump_dest) { 2090 + ret = validate_branch(file, func, 2091 + insn->jump_dest, state); 2116 2092 if (ret) { 2117 2093 if (backtrace) 2118 2094 BT_FUNC("(branch)", insn); ··· 2118 2110 break; 2119 2111 2120 2112 case INSN_JUMP_DYNAMIC: 2121 - if (func && list_empty(&insn->alts)) { 2113 + case INSN_JUMP_DYNAMIC_CONDITIONAL: 2114 + if (func && is_sibling_call(insn)) { 2122 2115 ret = validate_sibling_call(insn, &state); 2123 2116 if (ret) 2124 2117 return ret; 2125 2118 } 2126 2119 2127 - return 0; 2120 + if (insn->type == INSN_JUMP_DYNAMIC) 2121 + return 0; 2122 + 2123 + break; 2128 2124 2129 2125 case INSN_CONTEXT_SWITCH: 2130 2126 if (func && (!next_insn || !next_insn->hint)) { ··· 2174 2162 break; 2175 2163 2176 2164 case INSN_CLAC: 2177 - if (!state.uaccess && insn->func) { 2165 + if (!state.uaccess && func) { 2178 2166 WARN_FUNC("redundant UACCESS disable", sec, insn->offset); 2179 2167 return 1; 2180 2168 } ··· 2195 2183 break; 2196 2184 2197 2185 case INSN_CLD: 2198 - if (!state.df && insn->func) 2186 + if (!state.df && func) 2199 2187 WARN_FUNC("redundant CLD", sec, insn->offset); 2200 2188 2201 2189 state.df = false; ··· 2234 2222 2235 2223 for_each_insn(file, insn) { 2236 2224 if (insn->hint && !insn->visited) { 2237 - ret = validate_branch(file, insn, state); 2225 + ret = validate_branch(file, insn->func, insn, state); 2238 2226 if (ret && backtrace) 2239 2227 BT_FUNC("<=== (hint)", insn); 2240 2228 warnings += ret; ··· 2357 2345 2358 2346 for_each_sec(file, sec) { 2359 2347 list_for_each_entry(func, &sec->symbol_list, list) { 2360 - if (func->type != STT_FUNC || func->pfunc != func) 2348 + if (func->type != STT_FUNC) 2349 + continue; 2350 + 2351 + if (!func->len) { 2352 + WARN("%s() is missing an ELF size annotation", 2353 + func->name); 2354 + warnings++; 2355 + } 2356 + 2357 + if (func->pfunc != func || func->alias != func) 2361 2358 continue; 2362 2359 2363 2360 insn = find_insn(file, sec, func->offset); 2364 - if (!insn || insn->ignore) 2361 + if (!insn || insn->ignore || insn->visited) 2365 2362 continue; 2366 2363 2367 - state.uaccess = func->alias->uaccess_safe; 2364 + state.uaccess = func->uaccess_safe; 2368 2365 2369 - ret = validate_branch(file, insn, state); 2366 + ret = validate_branch(file, func, insn, state); 2370 2367 if (ret && backtrace) 2371 2368 BT_FUNC("<=== (func)", insn); 2372 2369 warnings += ret; ··· 2428 2407 2429 2408 objname = _objname; 2430 2409 2431 - file.elf = elf_open(objname, orc ? O_RDWR : O_RDONLY); 2410 + file.elf = elf_read(objname, orc ? O_RDWR : O_RDONLY); 2432 2411 if (!file.elf) 2433 2412 return 1; 2434 2413
+2 -1
tools/objtool/check.h
··· 31 31 struct section *sec; 32 32 unsigned long offset; 33 33 unsigned int len; 34 - unsigned char type; 34 + enum insn_type type; 35 35 unsigned long immediate; 36 36 bool alt_group, visited, dead_end, ignore, hint, save, restore, ignore_alts; 37 37 bool retpoline_safe; 38 38 struct symbol *call_dest; 39 39 struct instruction *jump_dest; 40 40 struct instruction *first_jump_src; 41 + struct rela *jump_table; 41 42 struct list_head alts; 42 43 struct symbol *func; 43 44 struct stack_op stack_op;
+4 -4
tools/objtool/elf.c
··· 278 278 } 279 279 280 280 if (sym->offset == s->offset) { 281 - if (sym->len == s->len && alias == sym) 281 + if (sym->len && sym->len == s->len && alias == sym) 282 282 alias = s; 283 283 284 284 if (sym->len >= s->len) { ··· 385 385 rela->offset = rela->rela.r_offset; 386 386 symndx = GELF_R_SYM(rela->rela.r_info); 387 387 rela->sym = find_symbol_by_index(elf, symndx); 388 - rela->rela_sec = sec; 388 + rela->sec = sec; 389 389 if (!rela->sym) { 390 390 WARN("can't find rela entry symbol %d for %s", 391 391 symndx, sec->name); ··· 401 401 return 0; 402 402 } 403 403 404 - struct elf *elf_open(const char *name, int flags) 404 + struct elf *elf_read(const char *name, int flags) 405 405 { 406 406 struct elf *elf; 407 407 Elf_Cmd cmd; ··· 463 463 { 464 464 struct section *sec, *shstrtab; 465 465 size_t size = entsize * nr; 466 - struct Elf_Scn *s; 466 + Elf_Scn *s; 467 467 Elf_Data *data; 468 468 469 469 sec = malloc(sizeof(*sec));
+3 -2
tools/objtool/elf.h
··· 57 57 struct list_head list; 58 58 struct hlist_node hash; 59 59 GElf_Rela rela; 60 - struct section *rela_sec; 60 + struct section *sec; 61 61 struct symbol *sym; 62 62 unsigned int type; 63 63 unsigned long offset; 64 64 int addend; 65 + bool jump_table_start; 65 66 }; 66 67 67 68 struct elf { ··· 75 74 }; 76 75 77 76 78 - struct elf *elf_open(const char *name, int flags); 77 + struct elf *elf_read(const char *name, int flags); 79 78 struct section *find_section_by_name(struct elf *elf, const char *name); 80 79 struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); 81 80 struct symbol *find_symbol_by_name(struct elf *elf, const char *name);