Skip to content

Commit c82965f

Browse files
ChangSeokBaeKAGA-KOKO
authored andcommitted
x86/entry/64: Handle FSGSBASE enabled paranoid entry/exit
Without FSGSBASE, user space cannot change GSBASE other than through a PRCTL. The kernel enforces that the user space GSBASE value is postive as negative values are used for detecting the kernel space GSBASE value in the paranoid entry code. If FSGSBASE is enabled, user space can set arbitrary GSBASE values without kernel intervention, including negative ones, which breaks the paranoid entry assumptions. To avoid this, paranoid entry needs to unconditionally save the current GSBASE value independent of the interrupted context, retrieve and write the kernel GSBASE and unconditionally restore the saved value on exit. The restore happens either in paranoid_exit or in the special exit path of the NMI low level code. All other entry code pathes which use unconditional SWAPGS are not affected as they do not depend on the actual content. [ tglx: Massaged changelogs and comments ] Suggested-by: H. Peter Anvin <[email protected]> Suggested-by: Andy Lutomirski <[email protected]> Suggested-by: Thomas Gleixner <[email protected]> Signed-off-by: Chang S. Bae <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected]
1 parent eaad981 commit c82965f

File tree

2 files changed

+91
-26
lines changed

2 files changed

+91
-26
lines changed

arch/x86/entry/calling.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,12 @@ For 32-bit we have the following conventions - kernel is built with
342342
#endif
343343
.endm
344344

345+
.macro SAVE_AND_SET_GSBASE scratch_reg:req save_reg:req
346+
rdgsbase \save_reg
347+
GET_PERCPU_BASE \scratch_reg
348+
wrgsbase \scratch_reg
349+
.endm
350+
345351
#else /* CONFIG_X86_64 */
346352
# undef UNWIND_HINT_IRET_REGS
347353
# define UNWIND_HINT_IRET_REGS

arch/x86/entry/entry_64.S

Lines changed: 85 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <asm/frame.h>
3939
#include <asm/trapnr.h>
4040
#include <asm/nospec-branch.h>
41+
#include <asm/fsgsbase.h>
4142
#include <linux/err.h>
4243

4344
#include "calling.h"
@@ -426,10 +427,7 @@ SYM_CODE_START(\asmsym)
426427
testb $3, CS-ORIG_RAX(%rsp)
427428
jnz .Lfrom_usermode_switch_stack_\@
428429

429-
/*
430-
* paranoid_entry returns SWAPGS flag for paranoid_exit in EBX.
431-
* EBX == 0 -> SWAPGS, EBX == 1 -> no SWAPGS
432-
*/
430+
/* paranoid_entry returns GS information for paranoid_exit in EBX. */
433431
call paranoid_entry
434432

435433
UNWIND_HINT_REGS
@@ -458,10 +456,7 @@ SYM_CODE_START(\asmsym)
458456
UNWIND_HINT_IRET_REGS offset=8
459457
ASM_CLAC
460458

461-
/*
462-
* paranoid_entry returns SWAPGS flag for paranoid_exit in EBX.
463-
* EBX == 0 -> SWAPGS, EBX == 1 -> no SWAPGS
464-
*/
459+
/* paranoid_entry returns GS information for paranoid_exit in EBX. */
465460
call paranoid_entry
466461
UNWIND_HINT_REGS
467462

@@ -798,17 +793,21 @@ SYM_CODE_END(xen_failsafe_callback)
798793
#endif /* CONFIG_XEN_PV */
799794

800795
/*
801-
* Save all registers in pt_regs, and switch gs if needed.
802-
* Use slow, but surefire "are we in kernel?" check.
803-
* Return: ebx=0: need swapgs on exit, ebx=1: otherwise
796+
* Save all registers in pt_regs. Return GSBASE related information
797+
* in EBX depending on the availability of the FSGSBASE instructions:
798+
*
799+
* FSGSBASE R/EBX
800+
* N 0 -> SWAPGS on exit
801+
* 1 -> no SWAPGS on exit
802+
*
803+
* Y GSBASE value at entry, must be restored in paranoid_exit
804804
*/
805805
SYM_CODE_START_LOCAL(paranoid_entry)
806806
UNWIND_HINT_FUNC
807807
cld
808808
PUSH_AND_CLEAR_REGS save_ret=1
809809
ENCODE_FRAME_POINTER 8
810810

811-
1:
812811
/*
813812
* Always stash CR3 in %r14. This value will be restored,
814813
* verbatim, at exit. Needed if paranoid_entry interrupted
@@ -826,6 +825,28 @@ SYM_CODE_START_LOCAL(paranoid_entry)
826825
*/
827826
SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg=%rax save_reg=%r14
828827

828+
/*
829+
* Handling GSBASE depends on the availability of FSGSBASE.
830+
*
831+
* Without FSGSBASE the kernel enforces that negative GSBASE
832+
* values indicate kernel GSBASE. With FSGSBASE no assumptions
833+
* can be made about the GSBASE value when entering from user
834+
* space.
835+
*/
836+
ALTERNATIVE "jmp .Lparanoid_entry_checkgs", "", X86_FEATURE_FSGSBASE
837+
838+
/*
839+
* Read the current GSBASE and store it in %rbx unconditionally,
840+
* retrieve and set the current CPUs kernel GSBASE. The stored value
841+
* has to be restored in paranoid_exit unconditionally.
842+
*
843+
* The MSR write ensures that no subsequent load is based on a
844+
* mispredicted GSBASE. No extra FENCE required.
845+
*/
846+
SAVE_AND_SET_GSBASE scratch_reg=%rax save_reg=%rbx
847+
ret
848+
849+
.Lparanoid_entry_checkgs:
829850
/* EBX = 1 -> kernel GSBASE active, no restore required */
830851
movl $1, %ebx
831852
/*
@@ -860,24 +881,45 @@ SYM_CODE_END(paranoid_entry)
860881
*
861882
* We may be returning to very strange contexts (e.g. very early
862883
* in syscall entry), so checking for preemption here would
863-
* be complicated. Fortunately, we there's no good reason
864-
* to try to handle preemption here.
884+
* be complicated. Fortunately, there's no good reason to try
885+
* to handle preemption here.
886+
*
887+
* R/EBX contains the GSBASE related information depending on the
888+
* availability of the FSGSBASE instructions:
889+
*
890+
* FSGSBASE R/EBX
891+
* N 0 -> SWAPGS on exit
892+
* 1 -> no SWAPGS on exit
865893
*
866-
* On entry, ebx is "no swapgs" flag (1: don't need swapgs, 0: need it)
894+
* Y User space GSBASE, must be restored unconditionally
867895
*/
868896
SYM_CODE_START_LOCAL(paranoid_exit)
869897
UNWIND_HINT_REGS
870-
/* If EBX is 0, SWAPGS is required */
871-
testl %ebx, %ebx
872-
jnz .Lparanoid_exit_no_swapgs
873-
/* Always restore stashed CR3 value (see paranoid_entry) */
874-
RESTORE_CR3 scratch_reg=%rbx save_reg=%r14
898+
/*
899+
* The order of operations is important. RESTORE_CR3 requires
900+
* kernel GSBASE.
901+
*
902+
* NB to anyone to try to optimize this code: this code does
903+
* not execute at all for exceptions from user mode. Those
904+
* exceptions go through error_exit instead.
905+
*/
906+
RESTORE_CR3 scratch_reg=%rax save_reg=%r14
907+
908+
/* Handle the three GSBASE cases */
909+
ALTERNATIVE "jmp .Lparanoid_exit_checkgs", "", X86_FEATURE_FSGSBASE
910+
911+
/* With FSGSBASE enabled, unconditionally restore GSBASE */
912+
wrgsbase %rbx
913+
jmp restore_regs_and_return_to_kernel
914+
915+
.Lparanoid_exit_checkgs:
916+
/* On non-FSGSBASE systems, conditionally do SWAPGS */
917+
testl %ebx, %ebx
918+
jnz restore_regs_and_return_to_kernel
919+
920+
/* We are returning to a context with user GSBASE */
875921
SWAPGS_UNSAFE_STACK
876-
jmp restore_regs_and_return_to_kernel
877-
.Lparanoid_exit_no_swapgs:
878-
/* Always restore stashed CR3 value (see paranoid_entry) */
879-
RESTORE_CR3 scratch_reg=%rbx save_reg=%r14
880-
jmp restore_regs_and_return_to_kernel
922+
jmp restore_regs_and_return_to_kernel
881923
SYM_CODE_END(paranoid_exit)
882924

883925
/*
@@ -1282,10 +1324,27 @@ end_repeat_nmi:
12821324
/* Always restore stashed CR3 value (see paranoid_entry) */
12831325
RESTORE_CR3 scratch_reg=%r15 save_reg=%r14
12841326

1285-
testl %ebx, %ebx /* swapgs needed? */
1327+
/*
1328+
* The above invocation of paranoid_entry stored the GSBASE
1329+
* related information in R/EBX depending on the availability
1330+
* of FSGSBASE.
1331+
*
1332+
* If FSGSBASE is enabled, restore the saved GSBASE value
1333+
* unconditionally, otherwise take the conditional SWAPGS path.
1334+
*/
1335+
ALTERNATIVE "jmp nmi_no_fsgsbase", "", X86_FEATURE_FSGSBASE
1336+
1337+
wrgsbase %rbx
1338+
jmp nmi_restore
1339+
1340+
nmi_no_fsgsbase:
1341+
/* EBX == 0 -> invoke SWAPGS */
1342+
testl %ebx, %ebx
12861343
jnz nmi_restore
1344+
12871345
nmi_swapgs:
12881346
SWAPGS_UNSAFE_STACK
1347+
12891348
nmi_restore:
12901349
POP_REGS
12911350

0 commit comments

Comments
 (0)