Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4708ea1

Browse files
jpoimboePeter Zijlstra
authored andcommitted
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 <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Acked-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lore.kernel.org/r/ff7448d492ea21b86d8a90264b105fbd0d751077.1677683419.git.jpoimboe@kernel.org
1 parent f902cfd commit 4708ea1

File tree

9 files changed

+85
-45
lines changed

9 files changed

+85
-45
lines changed

arch/x86/entry/entry_64.S

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -388,9 +388,9 @@ SYM_CODE_START(\asmsym)
388388

389389
.if \vector == X86_TRAP_BP
390390
/* #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
392392
.else
393-
UNWIND_HINT_IRET_REGS offset=\has_error_code*8
393+
UNWIND_HINT_IRET_ENTRY offset=\has_error_code*8
394394
.endif
395395

396396
ENDBR
@@ -461,7 +461,7 @@ SYM_CODE_END(\asmsym)
461461
*/
462462
.macro idtentry_mce_db vector asmsym cfunc
463463
SYM_CODE_START(\asmsym)
464-
UNWIND_HINT_IRET_REGS
464+
UNWIND_HINT_IRET_ENTRY
465465
ENDBR
466466
ASM_CLAC
467467
cld
@@ -518,7 +518,7 @@ SYM_CODE_END(\asmsym)
518518
*/
519519
.macro idtentry_vc vector asmsym cfunc
520520
SYM_CODE_START(\asmsym)
521-
UNWIND_HINT_IRET_REGS
521+
UNWIND_HINT_IRET_ENTRY
522522
ENDBR
523523
ASM_CLAC
524524
cld
@@ -582,7 +582,7 @@ SYM_CODE_END(\asmsym)
582582
*/
583583
.macro idtentry_df vector asmsym cfunc
584584
SYM_CODE_START(\asmsym)
585-
UNWIND_HINT_IRET_REGS offset=8
585+
UNWIND_HINT_IRET_ENTRY offset=8
586586
ENDBR
587587
ASM_CLAC
588588
cld
@@ -1107,7 +1107,7 @@ SYM_CODE_START(error_entry)
11071107
FENCE_SWAPGS_KERNEL_ENTRY
11081108
CALL_DEPTH_ACCOUNT
11091109
leaq 8(%rsp), %rax /* return pt_regs pointer */
1110-
ANNOTATE_UNRET_END
1110+
VALIDATE_UNRET_END
11111111
RET
11121112

11131113
.Lbstep_iret:
@@ -1153,7 +1153,7 @@ SYM_CODE_END(error_return)
11531153
* when PAGE_TABLE_ISOLATION is in use. Do not clobber.
11541154
*/
11551155
SYM_CODE_START(asm_exc_nmi)
1156-
UNWIND_HINT_IRET_REGS
1156+
UNWIND_HINT_IRET_ENTRY
11571157
ENDBR
11581158

11591159
/*

arch/x86/include/asm/nospec-branch.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,8 @@
210210
* Abuse ANNOTATE_RETPOLINE_SAFE on a NOP to indicate UNRET_END, should
211211
* eventually turn into it's own annotation.
212212
*/
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)
215215
ANNOTATE_RETPOLINE_SAFE
216216
nop
217217
#endif
@@ -286,7 +286,7 @@
286286
.macro UNTRAIN_RET
287287
#if defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_IBPB_ENTRY) || \
288288
defined(CONFIG_CALL_DEPTH_TRACKING)
289-
ANNOTATE_UNRET_END
289+
VALIDATE_UNRET_END
290290
ALTERNATIVE_3 "", \
291291
CALL_ZEN_UNTRAIN_RET, X86_FEATURE_UNRET, \
292292
"call entry_ibpb", X86_FEATURE_ENTRY_IBPB, \
@@ -297,7 +297,7 @@
297297
.macro UNTRAIN_RET_FROM_CALL
298298
#if defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_IBPB_ENTRY) || \
299299
defined(CONFIG_CALL_DEPTH_TRACKING)
300-
ANNOTATE_UNRET_END
300+
VALIDATE_UNRET_END
301301
ALTERNATIVE_3 "", \
302302
CALL_ZEN_UNTRAIN_RET, X86_FEATURE_UNRET, \
303303
"call entry_ibpb", X86_FEATURE_ENTRY_IBPB, \

arch/x86/include/asm/unwind_hints.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
.endm
1313

1414
.macro UNWIND_HINT_ENTRY
15-
UNWIND_HINT type=UNWIND_HINT_TYPE_ENTRY end=1
15+
VALIDATE_UNRET_BEGIN
16+
UNWIND_HINT_EMPTY
1617
.endm
1718

1819
.macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 partial=0 signal=1
@@ -52,6 +53,11 @@
5253
UNWIND_HINT_REGS base=\base offset=\offset partial=1 signal=\signal
5354
.endm
5455

56+
.macro UNWIND_HINT_IRET_ENTRY base=%rsp offset=0 signal=1
57+
VALIDATE_UNRET_BEGIN
58+
UNWIND_HINT_IRET_REGS base=\base offset=\offset signal=\signal
59+
.endm
60+
5561
.macro UNWIND_HINT_FUNC
5662
UNWIND_HINT sp_reg=ORC_REG_SP sp_offset=8 type=UNWIND_HINT_TYPE_FUNC
5763
.endm

arch/x86/kernel/head_64.S

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -390,8 +390,6 @@ SYM_CODE_START_NOALIGN(vc_boot_ghcb)
390390
UNWIND_HINT_IRET_REGS offset=8
391391
ENDBR
392392

393-
ANNOTATE_UNRET_END
394-
395393
/* Build pt_regs */
396394
PUSH_AND_CLEAR_REGS
397395

@@ -451,7 +449,6 @@ SYM_CODE_END(early_idt_handler_array)
451449

452450
SYM_CODE_START_LOCAL(early_idt_handler_common)
453451
UNWIND_HINT_IRET_REGS offset=16
454-
ANNOTATE_UNRET_END
455452
/*
456453
* The stack is the hardware frame, an error code or zero, and the
457454
* vector number.
@@ -501,8 +498,6 @@ SYM_CODE_START_NOALIGN(vc_no_ghcb)
501498
UNWIND_HINT_IRET_REGS offset=8
502499
ENDBR
503500

504-
ANNOTATE_UNRET_END
505-
506501
/* Build pt_regs */
507502
PUSH_AND_CLEAR_REGS
508503

include/linux/objtool.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,22 @@
124124
.popsection
125125
.endm
126126

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+
127143
.macro REACHABLE
128144
.Lhere_\@:
129145
.pushsection .discard.reachable

include/linux/objtool_types.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ struct unwind_hint {
4242
#define UNWIND_HINT_TYPE_REGS_PARTIAL 2
4343
/* The below hint types don't have corresponding ORC types */
4444
#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
4847

4948
#endif /* _LINUX_OBJTOOL_TYPES_H */

tools/include/linux/objtool_types.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ struct unwind_hint {
4242
#define UNWIND_HINT_TYPE_REGS_PARTIAL 2
4343
/* The below hint types don't have corresponding ORC types */
4444
#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
4847

4948
#endif /* _LINUX_OBJTOOL_TYPES_H */

tools/objtool/check.c

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2307,16 +2307,9 @@ static int read_unwind_hints(struct objtool_file *file)
23072307
WARN_FUNC("UNWIND_HINT_IRET_REGS without ENDBR",
23082308
insn->sec, insn->offset);
23092309
}
2310-
2311-
insn->entry = 1;
23122310
}
23132311
}
23142312

2315-
if (hint->type == UNWIND_HINT_TYPE_ENTRY) {
2316-
hint->type = UNWIND_HINT_TYPE_CALL;
2317-
insn->entry = 1;
2318-
}
2319-
23202313
if (hint->type == UNWIND_HINT_TYPE_FUNC) {
23212314
insn->cfi = &func_cfi;
23222315
continue;
@@ -2449,6 +2442,34 @@ static int read_instr_hints(struct objtool_file *file)
24492442
return 0;
24502443
}
24512444

2445+
static int read_validate_unret_hints(struct objtool_file *file)
2446+
{
2447+
struct section *sec;
2448+
struct instruction *insn;
2449+
struct reloc *reloc;
2450+
2451+
sec = find_section_by_name(file->elf, ".rela.discard.validate_unret");
2452+
if (!sec)
2453+
return 0;
2454+
2455+
list_for_each_entry(reloc, &sec->reloc_list, list) {
2456+
if (reloc->sym->type != STT_SECTION) {
2457+
WARN("unexpected relocation symbol type in %s", sec->name);
2458+
return -1;
2459+
}
2460+
2461+
insn = find_insn(file, reloc->sym->sec, reloc->addend);
2462+
if (!insn) {
2463+
WARN("bad .discard.instr_end entry");
2464+
return -1;
2465+
}
2466+
insn->unret = 1;
2467+
}
2468+
2469+
return 0;
2470+
}
2471+
2472+
24522473
static int read_intra_function_calls(struct objtool_file *file)
24532474
{
24542475
struct instruction *insn;
@@ -2667,6 +2688,10 @@ static int decode_sections(struct objtool_file *file)
26672688
if (ret)
26682689
return ret;
26692690

2691+
ret = read_validate_unret_hints(file);
2692+
if (ret)
2693+
return ret;
2694+
26702695
return 0;
26712696
}
26722697

@@ -3863,21 +3888,21 @@ static int validate_unwind_hints(struct objtool_file *file, struct section *sec)
38633888
/*
38643889
* Validate rethunk entry constraint: must untrain RET before the first RET.
38653890
*
3866-
* Follow every branch (intra-function) and ensure ANNOTATE_UNRET_END comes
3891+
* Follow every branch (intra-function) and ensure VALIDATE_UNRET_END comes
38673892
* before an actual RET instruction.
38683893
*/
3869-
static int validate_entry(struct objtool_file *file, struct instruction *insn)
3894+
static int validate_unret(struct objtool_file *file, struct instruction *insn)
38703895
{
38713896
struct instruction *next, *dest;
38723897
int ret, warnings = 0;
38733898

38743899
for (;;) {
38753900
next = next_insn_to_validate(file, insn);
38763901

3877-
if (insn->visited & VISITED_ENTRY)
3902+
if (insn->visited & VISITED_UNRET)
38783903
return 0;
38793904

3880-
insn->visited |= VISITED_ENTRY;
3905+
insn->visited |= VISITED_UNRET;
38813906

38823907
if (!insn->ignore_alts && insn->alts) {
38833908
struct alternative *alt;
@@ -3887,7 +3912,7 @@ static int validate_entry(struct objtool_file *file, struct instruction *insn)
38873912
if (alt->skip_orig)
38883913
skip_orig = true;
38893914

3890-
ret = validate_entry(file, alt->insn);
3915+
ret = validate_unret(file, alt->insn);
38913916
if (ret) {
38923917
if (opts.backtrace)
38933918
BT_FUNC("(alt)", insn);
@@ -3915,7 +3940,7 @@ static int validate_entry(struct objtool_file *file, struct instruction *insn)
39153940
insn->sec, insn->offset);
39163941
return -1;
39173942
}
3918-
ret = validate_entry(file, insn->jump_dest);
3943+
ret = validate_unret(file, insn->jump_dest);
39193944
if (ret) {
39203945
if (opts.backtrace) {
39213946
BT_FUNC("(branch%s)", insn,
@@ -3940,7 +3965,7 @@ static int validate_entry(struct objtool_file *file, struct instruction *insn)
39403965
return -1;
39413966
}
39423967

3943-
ret = validate_entry(file, dest);
3968+
ret = validate_unret(file, dest);
39443969
if (ret) {
39453970
if (opts.backtrace)
39463971
BT_FUNC("(call)", insn);
@@ -3976,19 +4001,19 @@ static int validate_entry(struct objtool_file *file, struct instruction *insn)
39764001
}
39774002

39784003
/*
3979-
* Validate that all branches starting at 'insn->entry' encounter UNRET_END
3980-
* before RET.
4004+
* Validate that all branches starting at VALIDATE_UNRET_BEGIN encounter
4005+
* VALIDATE_UNRET_END before RET.
39814006
*/
3982-
static int validate_unret(struct objtool_file *file)
4007+
static int validate_unrets(struct objtool_file *file)
39834008
{
39844009
struct instruction *insn;
39854010
int ret, warnings = 0;
39864011

39874012
for_each_insn(file, insn) {
3988-
if (!insn->entry)
4013+
if (!insn->unret)
39894014
continue;
39904015

3991-
ret = validate_entry(file, insn);
4016+
ret = validate_unret(file, insn);
39924017
if (ret < 0) {
39934018
WARN_FUNC("Failed UNRET validation", insn->sec, insn->offset);
39944019
return ret;
@@ -4607,7 +4632,7 @@ int check(struct objtool_file *file)
46074632
* Must be after validate_branch() and friends, it plays
46084633
* further games with insn->visited.
46094634
*/
4610-
ret = validate_unret(file);
4635+
ret = validate_unrets(file);
46114636
if (ret < 0)
46124637
return ret;
46134638
warnings += ret;

tools/objtool/include/objtool/check.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ struct instruction {
6161
restore : 1,
6262
retpoline_safe : 1,
6363
noendbr : 1,
64-
entry : 1,
64+
unret : 1,
6565
visited : 4,
6666
no_reloc : 1;
6767
/* 10 bit hole */
@@ -92,7 +92,7 @@ static inline struct symbol *insn_func(struct instruction *insn)
9292
#define VISITED_BRANCH 0x01
9393
#define VISITED_BRANCH_UACCESS 0x02
9494
#define VISITED_BRANCH_MASK 0x03
95-
#define VISITED_ENTRY 0x04
95+
#define VISITED_UNRET 0x04
9696

9797
static inline bool is_static_jump(struct instruction *insn)
9898
{

0 commit comments

Comments
 (0)