Skip to content

Commit a09a6e2

Browse files
Peter Zijlstrasuryasaimadhu
authored andcommitted
objtool: Add entry UNRET validation
Since entry asm is tricky, add a validation pass that ensures the retbleed mitigation has been done before the first actual RET instruction. Entry points are those that either have UNWIND_HINT_ENTRY, which acts as UNWIND_HINT_EMPTY but marks the instruction as an entry point, or those that have UWIND_HINT_IRET_REGS at +0. This is basically a variant of validate_branch() that is intra-function and it will simply follow all branches from marked entry points and ensures that all paths lead to ANNOTATE_UNRET_END. If a path hits RET or an indirection the path is a fail and will be reported. There are 3 ANNOTATE_UNRET_END instances: - UNTRAIN_RET itself - exception from-kernel; this path doesn't need UNTRAIN_RET - all early exceptions; these also don't need UNTRAIN_RET Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Borislav Petkov <bp@suse.de> Reviewed-by: Josh Poimboeuf <jpoimboe@kernel.org> Signed-off-by: Borislav Petkov <bp@suse.de>
1 parent 0fe4aee commit a09a6e2

13 files changed

Lines changed: 222 additions & 21 deletions

File tree

arch/x86/entry/entry_64.S

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@
8585
*/
8686

8787
SYM_CODE_START(entry_SYSCALL_64)
88-
UNWIND_HINT_EMPTY
88+
UNWIND_HINT_ENTRY
8989
ENDBR
9090

9191
swapgs
@@ -1095,6 +1095,7 @@ SYM_CODE_START_LOCAL(error_entry)
10951095
.Lerror_entry_done_lfence:
10961096
FENCE_SWAPGS_KERNEL_ENTRY
10971097
leaq 8(%rsp), %rax /* return pt_regs pointer */
1098+
ANNOTATE_UNRET_END
10981099
RET
10991100

11001101
.Lbstep_iret:

arch/x86/entry/entry_64_compat.S

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
* 0(%ebp) arg6
5050
*/
5151
SYM_CODE_START(entry_SYSENTER_compat)
52-
UNWIND_HINT_EMPTY
52+
UNWIND_HINT_ENTRY
5353
ENDBR
5454
/* Interrupts are off on entry. */
5555
swapgs
@@ -179,7 +179,7 @@ SYM_CODE_END(entry_SYSENTER_compat)
179179
* 0(%esp) arg6
180180
*/
181181
SYM_CODE_START(entry_SYSCALL_compat)
182-
UNWIND_HINT_EMPTY
182+
UNWIND_HINT_ENTRY
183183
ENDBR
184184
/* Interrupts are off on entry. */
185185
swapgs
@@ -305,7 +305,7 @@ SYM_CODE_END(entry_SYSCALL_compat)
305305
* ebp arg6
306306
*/
307307
SYM_CODE_START(entry_INT80_compat)
308-
UNWIND_HINT_EMPTY
308+
UNWIND_HINT_ENTRY
309309
ENDBR
310310
/*
311311
* Interrupts are off on entry.

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,17 @@
8181
*/
8282
#define ANNOTATE_UNRET_SAFE ANNOTATE_RETPOLINE_SAFE
8383

84+
/*
85+
* Abuse ANNOTATE_RETPOLINE_SAFE on a NOP to indicate UNRET_END, should
86+
* eventually turn into it's own annotation.
87+
*/
88+
.macro ANNOTATE_UNRET_END
89+
#ifdef CONFIG_DEBUG_ENTRY
90+
ANNOTATE_RETPOLINE_SAFE
91+
nop
92+
#endif
93+
.endm
94+
8495
/*
8596
* JMP_NOSPEC and CALL_NOSPEC macros can be used instead of a simple
8697
* indirect jmp/call which may be susceptible to the Spectre variant 2
@@ -131,6 +142,7 @@
131142
*/
132143
.macro UNTRAIN_RET
133144
#ifdef CONFIG_RETPOLINE
145+
ANNOTATE_UNRET_END
134146
ALTERNATIVE_2 "", \
135147
"call zen_untrain_ret", X86_FEATURE_UNRET, \
136148
"call entry_ibpb", X86_FEATURE_ENTRY_IBPB

arch/x86/include/asm/unwind_hints.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
UNWIND_HINT sp_reg=ORC_REG_UNDEFINED type=UNWIND_HINT_TYPE_CALL end=1
1212
.endm
1313

14+
.macro UNWIND_HINT_ENTRY
15+
UNWIND_HINT sp_reg=ORC_REG_UNDEFINED type=UNWIND_HINT_TYPE_ENTRY end=1
16+
.endm
17+
1418
.macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 partial=0
1519
.if \base == %rsp
1620
.if \indirect

arch/x86/kernel/head_64.S

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

392+
ANNOTATE_UNRET_END
393+
392394
/* Build pt_regs */
393395
PUSH_AND_CLEAR_REGS
394396

@@ -448,6 +450,7 @@ SYM_CODE_END(early_idt_handler_array)
448450

449451
SYM_CODE_START_LOCAL(early_idt_handler_common)
450452
UNWIND_HINT_IRET_REGS offset=16
453+
ANNOTATE_UNRET_END
451454
/*
452455
* The stack is the hardware frame, an error code or zero, and the
453456
* vector number.
@@ -497,6 +500,8 @@ SYM_CODE_START_NOALIGN(vc_no_ghcb)
497500
UNWIND_HINT_IRET_REGS offset=8
498501
ENDBR
499502

503+
ANNOTATE_UNRET_END
504+
500505
/* Build pt_regs */
501506
PUSH_AND_CLEAR_REGS
502507

arch/x86/xen/xen-asm.S

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ SYM_FUNC_END(xen_read_cr2_direct);
121121

122122
.macro xen_pv_trap name
123123
SYM_CODE_START(xen_\name)
124-
UNWIND_HINT_EMPTY
124+
UNWIND_HINT_ENTRY
125125
ENDBR
126126
pop %rcx
127127
pop %r11
@@ -235,7 +235,7 @@ SYM_CODE_END(xenpv_restore_regs_and_return_to_usermode)
235235

236236
/* Normal 64-bit system call target */
237237
SYM_CODE_START(xen_entry_SYSCALL_64)
238-
UNWIND_HINT_EMPTY
238+
UNWIND_HINT_ENTRY
239239
ENDBR
240240
popq %rcx
241241
popq %r11
@@ -255,7 +255,7 @@ SYM_CODE_END(xen_entry_SYSCALL_64)
255255

256256
/* 32-bit compat syscall target */
257257
SYM_CODE_START(xen_entry_SYSCALL_compat)
258-
UNWIND_HINT_EMPTY
258+
UNWIND_HINT_ENTRY
259259
ENDBR
260260
popq %rcx
261261
popq %r11
@@ -273,7 +273,7 @@ SYM_CODE_END(xen_entry_SYSCALL_compat)
273273

274274
/* 32-bit compat sysenter target */
275275
SYM_CODE_START(xen_entry_SYSENTER_compat)
276-
UNWIND_HINT_EMPTY
276+
UNWIND_HINT_ENTRY
277277
ENDBR
278278
/*
279279
* NB: Xen is polite and clears TF from EFLAGS for us. This means
@@ -297,7 +297,7 @@ SYM_CODE_END(xen_entry_SYSENTER_compat)
297297

298298
SYM_CODE_START(xen_entry_SYSCALL_compat)
299299
SYM_CODE_START(xen_entry_SYSENTER_compat)
300-
UNWIND_HINT_EMPTY
300+
UNWIND_HINT_ENTRY
301301
ENDBR
302302
lea 16(%rsp), %rsp /* strip %rcx, %r11 */
303303
mov $-ENOSYS, %rax

include/linux/objtool.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,14 @@ struct unwind_hint {
3232
*
3333
* UNWIND_HINT_FUNC: Generate the unwind metadata of a callable function.
3434
* Useful for code which doesn't have an ELF function annotation.
35+
*
36+
* UNWIND_HINT_ENTRY: machine entry without stack, SYSCALL/SYSENTER etc.
3537
*/
3638
#define UNWIND_HINT_TYPE_CALL 0
3739
#define UNWIND_HINT_TYPE_REGS 1
3840
#define UNWIND_HINT_TYPE_REGS_PARTIAL 2
3941
#define UNWIND_HINT_TYPE_FUNC 3
42+
#define UNWIND_HINT_TYPE_ENTRY 4
4043

4144
#ifdef CONFIG_OBJTOOL
4245

scripts/Makefile.vmlinux_o

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ objtool-enabled := $(or $(delay-objtool),$(CONFIG_NOINSTR_VALIDATION))
4444

4545
objtool_args := \
4646
$(if $(delay-objtool),$(objtool_args)) \
47-
$(if $(CONFIG_NOINSTR_VALIDATION), --noinstr) \
47+
$(if $(CONFIG_NOINSTR_VALIDATION), --noinstr $(if $(CONFIG_RETPOLINE), --unret)) \
4848
$(if $(CONFIG_GCOV_KERNEL), --no-unreachable) \
4949
--link
5050

tools/include/linux/objtool.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,14 @@ struct unwind_hint {
3232
*
3333
* UNWIND_HINT_FUNC: Generate the unwind metadata of a callable function.
3434
* Useful for code which doesn't have an ELF function annotation.
35+
*
36+
* UNWIND_HINT_ENTRY: machine entry without stack, SYSCALL/SYSENTER etc.
3537
*/
3638
#define UNWIND_HINT_TYPE_CALL 0
3739
#define UNWIND_HINT_TYPE_REGS 1
3840
#define UNWIND_HINT_TYPE_REGS_PARTIAL 2
3941
#define UNWIND_HINT_TYPE_FUNC 3
42+
#define UNWIND_HINT_TYPE_ENTRY 4
4043

4144
#ifdef CONFIG_OBJTOOL
4245

tools/objtool/builtin-check.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ const struct option check_options[] = {
6868
OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"),
6969
OPT_BOOLEAN('o', "orc", &opts.orc, "generate ORC metadata"),
7070
OPT_BOOLEAN('r', "retpoline", &opts.retpoline, "validate and annotate retpoline usage"),
71+
OPT_BOOLEAN(0, "unret", &opts.unret, "validate entry unret placement"),
7172
OPT_BOOLEAN('l', "sls", &opts.sls, "validate straight-line-speculation mitigations"),
7273
OPT_BOOLEAN('s', "stackval", &opts.stackval, "validate frame pointer rules"),
7374
OPT_BOOLEAN('t', "static-call", &opts.static_call, "annotate static calls"),
@@ -163,6 +164,11 @@ static bool link_opts_valid(struct objtool_file *file)
163164
return false;
164165
}
165166

167+
if (opts.unret) {
168+
ERROR("--unret requires --link");
169+
return false;
170+
}
171+
166172
return true;
167173
}
168174

0 commit comments

Comments
 (0)