Skip to content

Commit 2354000

Browse files
committed
objtool: Add entry UNRET validation
JIRA: https://issues.redhat.com/browse/RHEL-255 Conflicts: arch/x86/include/asm/nospec-branch.h - cs-9 already has upstream f43b987 ("x86/retbleed: Add fine grained Kconfig knobs"), check for CONFIG_CPU_UNRET_ENTRY or CONFIG_CPU_IBPB_ENTRY instead of CONFIG_RETPOLINE tools/objtool/builtin-check.c tools/objtool/include/objtool/builtin.h - c9-9 already has upstream f43b987 ("x86/retbleed: Add fine grained Kconfig knobs") include/linux/objtool.h tools/include/linux/objtool.h - cs-9 already has upstream 8faea26 ("objtool: Re-add UNWIND_HINT_{SAVE_RESTORE}"), insert UNWIND_HINT_TYPE_ENTRY into the available 4th enum tools/objtool/check.c - cs-9 already has upstream 8faea26 ("objtool: Re-add UNWIND_HINT_{SAVE_RESTORE}"), apply UNWIND_HINT_TYPE_REGS_PARTIAL hunk in read_unwind_hints() manually tools/objtool/include/objtool/check.h - cs-9 already has upstream 8faea26 ("objtool: Re-add UNWIND_HINT_{SAVE_RESTORE}"), which added save and restore values to struct instruction. While we're here, fix the alignment of the bitfields that said omitted. scripts/Makefile.vmlinux_o - cs-9 doesn't have upstream 5d45950 ("kbuild: move vmlinux.o link to scripts/Makefile.vmlinux_o") or b42d230 ("kbuild: factor out the common objtool arguments"), so add objtool --unret option in scripts/link-vmlinux.sh commit a09a6e2 Author: Peter Zijlstra <peterz@infradead.org> Date: Tue Jun 14 23:16:03 2022 +0200 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> Signed-off-by: Joe Lawrence <joe.lawrence@redhat.com>
1 parent 39a2041 commit 2354000

File tree

13 files changed

+230
-26
lines changed

13 files changed

+230
-26
lines changed

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
@@ -1092,6 +1092,7 @@ SYM_CODE_START_LOCAL(error_entry)
10921092
.Lerror_entry_done_lfence:
10931093
FENCE_SWAPGS_KERNEL_ENTRY
10941094
leaq 8(%rsp), %rax /* return pt_regs pointer */
1095+
ANNOTATE_UNRET_END
10951096
RET
10961097

10971098
.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
@@ -302,7 +302,7 @@ SYM_CODE_END(entry_SYSCALL_compat)
302302
* ebp arg6
303303
*/
304304
SYM_CODE_START(entry_INT80_compat)
305-
UNWIND_HINT_EMPTY
305+
UNWIND_HINT_ENTRY
306306
ENDBR
307307
/*
308308
* 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
@@ -84,6 +84,17 @@
8484
*/
8585
#define ANNOTATE_UNRET_SAFE ANNOTATE_RETPOLINE_SAFE
8686

87+
/*
88+
* Abuse ANNOTATE_RETPOLINE_SAFE on a NOP to indicate UNRET_END, should
89+
* eventually turn into it's own annotation.
90+
*/
91+
.macro ANNOTATE_UNRET_END
92+
#ifdef CONFIG_DEBUG_ENTRY
93+
ANNOTATE_RETPOLINE_SAFE
94+
nop
95+
#endif
96+
.endm
97+
8798
/*
8899
* JMP_NOSPEC and CALL_NOSPEC macros can be used instead of a simple
89100
* indirect jmp/call which may be susceptible to the Spectre variant 2
@@ -153,6 +164,7 @@
153164
*/
154165
.macro UNTRAIN_RET
155166
#if defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_IBPB_ENTRY)
167+
ANNOTATE_UNRET_END
156168
ALTERNATIVE_2 "", \
157169
CALL_ZEN_UNTRAIN_RET, X86_FEATURE_UNRET, \
158170
"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 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
#define UNWIND_HINT_TYPE_SAVE 5
4144
#define UNWIND_HINT_TYPE_RESTORE 6
4245

scripts/link-vmlinux.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ objtool_link()
160160

161161
if is_enabled CONFIG_NOINSTR_VALIDATION; then
162162
objtoolopt="${objtoolopt} --noinstr"
163+
if is_enabled CONFIG_RETPOLINE; then
164+
objtoolopt="${objtoolopt} --unret"
165+
fi
163166
fi
164167

165168
if [ -n "${objtoolopt}" ]; then

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
#define UNWIND_HINT_TYPE_SAVE 5
4144
#define UNWIND_HINT_TYPE_RESTORE 6
4245

tools/objtool/builtin-check.c

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

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

0 commit comments

Comments
 (0)