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.

x86,objtool: Separate unret validation from unwind hints

The ENTRY unwind hint type is serving double duty as both an empty
unwind hint and an unret validation annotation.

Unret validation is unrelated to unwinding. Separate it out into its own
annotation.

Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/ff7448d492ea21b86d8a90264b105fbd0d751077.1677683419.git.jpoimboe@kernel.org

authored by

Josh Poimboeuf and committed by
Peter Zijlstra
4708ea14 f902cfdd

+85 -45
+7 -7
arch/x86/entry/entry_64.S
··· 388 388 389 389 .if \vector == X86_TRAP_BP 390 390 /* #BP advances %rip to the next instruction */ 391 - UNWIND_HINT_IRET_REGS offset=\has_error_code*8 signal=0 391 + UNWIND_HINT_IRET_ENTRY offset=\has_error_code*8 signal=0 392 392 .else 393 - UNWIND_HINT_IRET_REGS offset=\has_error_code*8 393 + UNWIND_HINT_IRET_ENTRY offset=\has_error_code*8 394 394 .endif 395 395 396 396 ENDBR ··· 461 461 */ 462 462 .macro idtentry_mce_db vector asmsym cfunc 463 463 SYM_CODE_START(\asmsym) 464 - UNWIND_HINT_IRET_REGS 464 + UNWIND_HINT_IRET_ENTRY 465 465 ENDBR 466 466 ASM_CLAC 467 467 cld ··· 518 518 */ 519 519 .macro idtentry_vc vector asmsym cfunc 520 520 SYM_CODE_START(\asmsym) 521 - UNWIND_HINT_IRET_REGS 521 + UNWIND_HINT_IRET_ENTRY 522 522 ENDBR 523 523 ASM_CLAC 524 524 cld ··· 582 582 */ 583 583 .macro idtentry_df vector asmsym cfunc 584 584 SYM_CODE_START(\asmsym) 585 - UNWIND_HINT_IRET_REGS offset=8 585 + UNWIND_HINT_IRET_ENTRY offset=8 586 586 ENDBR 587 587 ASM_CLAC 588 588 cld ··· 1107 1107 FENCE_SWAPGS_KERNEL_ENTRY 1108 1108 CALL_DEPTH_ACCOUNT 1109 1109 leaq 8(%rsp), %rax /* return pt_regs pointer */ 1110 - ANNOTATE_UNRET_END 1110 + VALIDATE_UNRET_END 1111 1111 RET 1112 1112 1113 1113 .Lbstep_iret: ··· 1153 1153 * when PAGE_TABLE_ISOLATION is in use. Do not clobber. 1154 1154 */ 1155 1155 SYM_CODE_START(asm_exc_nmi) 1156 - UNWIND_HINT_IRET_REGS 1156 + UNWIND_HINT_IRET_ENTRY 1157 1157 ENDBR 1158 1158 1159 1159 /*
+4 -4
arch/x86/include/asm/nospec-branch.h
··· 210 210 * Abuse ANNOTATE_RETPOLINE_SAFE on a NOP to indicate UNRET_END, should 211 211 * eventually turn into it's own annotation. 212 212 */ 213 - .macro ANNOTATE_UNRET_END 214 - #ifdef CONFIG_DEBUG_ENTRY 213 + .macro VALIDATE_UNRET_END 214 + #if defined(CONFIG_NOINSTR_VALIDATION) && defined(CONFIG_CPU_UNRET_ENTRY) 215 215 ANNOTATE_RETPOLINE_SAFE 216 216 nop 217 217 #endif ··· 286 286 .macro UNTRAIN_RET 287 287 #if defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_IBPB_ENTRY) || \ 288 288 defined(CONFIG_CALL_DEPTH_TRACKING) 289 - ANNOTATE_UNRET_END 289 + VALIDATE_UNRET_END 290 290 ALTERNATIVE_3 "", \ 291 291 CALL_ZEN_UNTRAIN_RET, X86_FEATURE_UNRET, \ 292 292 "call entry_ibpb", X86_FEATURE_ENTRY_IBPB, \ ··· 297 297 .macro UNTRAIN_RET_FROM_CALL 298 298 #if defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_IBPB_ENTRY) || \ 299 299 defined(CONFIG_CALL_DEPTH_TRACKING) 300 - ANNOTATE_UNRET_END 300 + VALIDATE_UNRET_END 301 301 ALTERNATIVE_3 "", \ 302 302 CALL_ZEN_UNTRAIN_RET, X86_FEATURE_UNRET, \ 303 303 "call entry_ibpb", X86_FEATURE_ENTRY_IBPB, \
+7 -1
arch/x86/include/asm/unwind_hints.h
··· 12 12 .endm 13 13 14 14 .macro UNWIND_HINT_ENTRY 15 - UNWIND_HINT type=UNWIND_HINT_TYPE_ENTRY end=1 15 + VALIDATE_UNRET_BEGIN 16 + UNWIND_HINT_EMPTY 16 17 .endm 17 18 18 19 .macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 partial=0 signal=1 ··· 51 50 52 51 .macro UNWIND_HINT_IRET_REGS base=%rsp offset=0 signal=1 53 52 UNWIND_HINT_REGS base=\base offset=\offset partial=1 signal=\signal 53 + .endm 54 + 55 + .macro UNWIND_HINT_IRET_ENTRY base=%rsp offset=0 signal=1 56 + VALIDATE_UNRET_BEGIN 57 + UNWIND_HINT_IRET_REGS base=\base offset=\offset signal=\signal 54 58 .endm 55 59 56 60 .macro UNWIND_HINT_FUNC
-5
arch/x86/kernel/head_64.S
··· 390 390 UNWIND_HINT_IRET_REGS offset=8 391 391 ENDBR 392 392 393 - ANNOTATE_UNRET_END 394 - 395 393 /* Build pt_regs */ 396 394 PUSH_AND_CLEAR_REGS 397 395 ··· 449 451 450 452 SYM_CODE_START_LOCAL(early_idt_handler_common) 451 453 UNWIND_HINT_IRET_REGS offset=16 452 - ANNOTATE_UNRET_END 453 454 /* 454 455 * The stack is the hardware frame, an error code or zero, and the 455 456 * vector number. ··· 497 500 SYM_CODE_START_NOALIGN(vc_no_ghcb) 498 501 UNWIND_HINT_IRET_REGS offset=8 499 502 ENDBR 500 - 501 - ANNOTATE_UNRET_END 502 503 503 504 /* Build pt_regs */ 504 505 PUSH_AND_CLEAR_REGS
+16
include/linux/objtool.h
··· 124 124 .popsection 125 125 .endm 126 126 127 + /* 128 + * Use objtool to validate the entry requirement that all code paths do 129 + * VALIDATE_UNRET_END before RET. 130 + * 131 + * NOTE: The macro must be used at the beginning of a global symbol, otherwise 132 + * it will be ignored. 133 + */ 134 + .macro VALIDATE_UNRET_BEGIN 135 + #if defined(CONFIG_NOINSTR_VALIDATION) && defined(CONFIG_CPU_UNRET_ENTRY) 136 + .Lhere_\@: 137 + .pushsection .discard.validate_unret 138 + .long .Lhere_\@ - . 139 + .popsection 140 + #endif 141 + .endm 142 + 127 143 .macro REACHABLE 128 144 .Lhere_\@: 129 145 .pushsection .discard.reachable
+2 -3
include/linux/objtool_types.h
··· 42 42 #define UNWIND_HINT_TYPE_REGS_PARTIAL 2 43 43 /* The below hint types don't have corresponding ORC types */ 44 44 #define UNWIND_HINT_TYPE_FUNC 3 45 - #define UNWIND_HINT_TYPE_ENTRY 4 46 - #define UNWIND_HINT_TYPE_SAVE 5 47 - #define UNWIND_HINT_TYPE_RESTORE 6 45 + #define UNWIND_HINT_TYPE_SAVE 4 46 + #define UNWIND_HINT_TYPE_RESTORE 5 48 47 49 48 #endif /* _LINUX_OBJTOOL_TYPES_H */
+2 -3
tools/include/linux/objtool_types.h
··· 42 42 #define UNWIND_HINT_TYPE_REGS_PARTIAL 2 43 43 /* The below hint types don't have corresponding ORC types */ 44 44 #define UNWIND_HINT_TYPE_FUNC 3 45 - #define UNWIND_HINT_TYPE_ENTRY 4 46 - #define UNWIND_HINT_TYPE_SAVE 5 47 - #define UNWIND_HINT_TYPE_RESTORE 6 45 + #define UNWIND_HINT_TYPE_SAVE 4 46 + #define UNWIND_HINT_TYPE_RESTORE 5 48 47 49 48 #endif /* _LINUX_OBJTOOL_TYPES_H */
+45 -20
tools/objtool/check.c
··· 2307 2307 WARN_FUNC("UNWIND_HINT_IRET_REGS without ENDBR", 2308 2308 insn->sec, insn->offset); 2309 2309 } 2310 - 2311 - insn->entry = 1; 2312 2310 } 2313 - } 2314 - 2315 - if (hint->type == UNWIND_HINT_TYPE_ENTRY) { 2316 - hint->type = UNWIND_HINT_TYPE_CALL; 2317 - insn->entry = 1; 2318 2311 } 2319 2312 2320 2313 if (hint->type == UNWIND_HINT_TYPE_FUNC) { ··· 2441 2448 2442 2449 return 0; 2443 2450 } 2451 + 2452 + static int read_validate_unret_hints(struct objtool_file *file) 2453 + { 2454 + struct section *sec; 2455 + struct instruction *insn; 2456 + struct reloc *reloc; 2457 + 2458 + sec = find_section_by_name(file->elf, ".rela.discard.validate_unret"); 2459 + if (!sec) 2460 + return 0; 2461 + 2462 + list_for_each_entry(reloc, &sec->reloc_list, list) { 2463 + if (reloc->sym->type != STT_SECTION) { 2464 + WARN("unexpected relocation symbol type in %s", sec->name); 2465 + return -1; 2466 + } 2467 + 2468 + insn = find_insn(file, reloc->sym->sec, reloc->addend); 2469 + if (!insn) { 2470 + WARN("bad .discard.instr_end entry"); 2471 + return -1; 2472 + } 2473 + insn->unret = 1; 2474 + } 2475 + 2476 + return 0; 2477 + } 2478 + 2444 2479 2445 2480 static int read_intra_function_calls(struct objtool_file *file) 2446 2481 { ··· 2685 2664 return ret; 2686 2665 2687 2666 ret = read_instr_hints(file); 2667 + if (ret) 2668 + return ret; 2669 + 2670 + ret = read_validate_unret_hints(file); 2688 2671 if (ret) 2689 2672 return ret; 2690 2673 ··· 3888 3863 /* 3889 3864 * Validate rethunk entry constraint: must untrain RET before the first RET. 3890 3865 * 3891 - * Follow every branch (intra-function) and ensure ANNOTATE_UNRET_END comes 3866 + * Follow every branch (intra-function) and ensure VALIDATE_UNRET_END comes 3892 3867 * before an actual RET instruction. 3893 3868 */ 3894 - static int validate_entry(struct objtool_file *file, struct instruction *insn) 3869 + static int validate_unret(struct objtool_file *file, struct instruction *insn) 3895 3870 { 3896 3871 struct instruction *next, *dest; 3897 3872 int ret, warnings = 0; ··· 3899 3874 for (;;) { 3900 3875 next = next_insn_to_validate(file, insn); 3901 3876 3902 - if (insn->visited & VISITED_ENTRY) 3877 + if (insn->visited & VISITED_UNRET) 3903 3878 return 0; 3904 3879 3905 - insn->visited |= VISITED_ENTRY; 3880 + insn->visited |= VISITED_UNRET; 3906 3881 3907 3882 if (!insn->ignore_alts && insn->alts) { 3908 3883 struct alternative *alt; ··· 3912 3887 if (alt->skip_orig) 3913 3888 skip_orig = true; 3914 3889 3915 - ret = validate_entry(file, alt->insn); 3890 + ret = validate_unret(file, alt->insn); 3916 3891 if (ret) { 3917 3892 if (opts.backtrace) 3918 3893 BT_FUNC("(alt)", insn); ··· 3940 3915 insn->sec, insn->offset); 3941 3916 return -1; 3942 3917 } 3943 - ret = validate_entry(file, insn->jump_dest); 3918 + ret = validate_unret(file, insn->jump_dest); 3944 3919 if (ret) { 3945 3920 if (opts.backtrace) { 3946 3921 BT_FUNC("(branch%s)", insn, ··· 3965 3940 return -1; 3966 3941 } 3967 3942 3968 - ret = validate_entry(file, dest); 3943 + ret = validate_unret(file, dest); 3969 3944 if (ret) { 3970 3945 if (opts.backtrace) 3971 3946 BT_FUNC("(call)", insn); ··· 4001 3976 } 4002 3977 4003 3978 /* 4004 - * Validate that all branches starting at 'insn->entry' encounter UNRET_END 4005 - * before RET. 3979 + * Validate that all branches starting at VALIDATE_UNRET_BEGIN encounter 3980 + * VALIDATE_UNRET_END before RET. 4006 3981 */ 4007 - static int validate_unret(struct objtool_file *file) 3982 + static int validate_unrets(struct objtool_file *file) 4008 3983 { 4009 3984 struct instruction *insn; 4010 3985 int ret, warnings = 0; 4011 3986 4012 3987 for_each_insn(file, insn) { 4013 - if (!insn->entry) 3988 + if (!insn->unret) 4014 3989 continue; 4015 3990 4016 - ret = validate_entry(file, insn); 3991 + ret = validate_unret(file, insn); 4017 3992 if (ret < 0) { 4018 3993 WARN_FUNC("Failed UNRET validation", insn->sec, insn->offset); 4019 3994 return ret; ··· 4632 4607 * Must be after validate_branch() and friends, it plays 4633 4608 * further games with insn->visited. 4634 4609 */ 4635 - ret = validate_unret(file); 4610 + ret = validate_unrets(file); 4636 4611 if (ret < 0) 4637 4612 return ret; 4638 4613 warnings += ret;
+2 -2
tools/objtool/include/objtool/check.h
··· 61 61 restore : 1, 62 62 retpoline_safe : 1, 63 63 noendbr : 1, 64 - entry : 1, 64 + unret : 1, 65 65 visited : 4, 66 66 no_reloc : 1; 67 67 /* 10 bit hole */ ··· 92 92 #define VISITED_BRANCH 0x01 93 93 #define VISITED_BRANCH_UACCESS 0x02 94 94 #define VISITED_BRANCH_MASK 0x03 95 - #define VISITED_ENTRY 0x04 95 + #define VISITED_UNRET 0x04 96 96 97 97 static inline bool is_static_jump(struct instruction *insn) 98 98 {