Commit 53c9d924 authored by Juergen Gross's avatar Juergen Gross Committed by Borislav Petkov
Browse files

x86/pv: Switch SWAPGS to ALTERNATIVE



SWAPGS is used only for interrupts coming from user mode or for
returning to user mode. So there is no reason to use the PARAVIRT
framework, as it can easily be replaced by an ALTERNATIVE depending
on X86_FEATURE_XENPV.

There are several instances using the PV-aware SWAPGS macro in paths
which are never executed in a Xen PV guest. Replace those with the
plain swapgs instruction. For SWAPGS_UNSAFE_STACK the same applies.

Signed-off-by: default avatarJuergen Gross <jgross@suse.com>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Reviewed-by: default avatarBorislav Petkov <bp@suse.de>
Reviewed-by: default avatarThomas Gleixner <tglx@linutronix.de>
Acked-by: default avatarAndy Lutomirski <luto@kernel.org>
Acked-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lkml.kernel.org/r/20210120135555.32594-5-jgross@suse.com
parent 5b4c6d65
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -669,7 +669,7 @@ native_irq_return_ldt:
	 */

	pushq	%rdi				/* Stash user RDI */
	SWAPGS					/* to kernel GS */
	swapgs					/* to kernel GS */
	SWITCH_TO_KERNEL_CR3 scratch_reg=%rdi	/* to kernel CR3 */

	movq	PER_CPU_VAR(espfix_waddr), %rdi
@@ -699,7 +699,7 @@ native_irq_return_ldt:
	orq	PER_CPU_VAR(espfix_stack), %rax

	SWITCH_TO_USER_CR3_STACK scratch_reg=%rdi
	SWAPGS					/* to user GS */
	swapgs					/* to user GS */
	popq	%rdi				/* Restore user RDI */

	movq	%rax, %rsp
@@ -943,7 +943,7 @@ SYM_CODE_START_LOCAL(paranoid_entry)
	ret

.Lparanoid_entry_swapgs:
	SWAPGS
	swapgs

	/*
	 * The above SAVE_AND_SWITCH_TO_KERNEL_CR3 macro doesn't do an
@@ -1001,7 +1001,7 @@ SYM_CODE_START_LOCAL(paranoid_exit)
	jnz		restore_regs_and_return_to_kernel

	/* We are returning to a context with user GSBASE */
	SWAPGS_UNSAFE_STACK
	swapgs
	jmp		restore_regs_and_return_to_kernel
SYM_CODE_END(paranoid_exit)

@@ -1426,7 +1426,7 @@ nmi_no_fsgsbase:
	jnz	nmi_restore

nmi_swapgs:
	SWAPGS_UNSAFE_STACK
	swapgs

nmi_restore:
	POP_REGS
+8 −12
Original line number Diff line number Diff line
@@ -131,18 +131,6 @@ static __always_inline unsigned long arch_local_irq_save(void)
#define SAVE_FLAGS(x)		pushfq; popq %rax
#endif

#define SWAPGS	swapgs
/*
 * Currently paravirt can't handle swapgs nicely when we
 * don't have a stack we can rely on (such as a user space
 * stack).  So we either find a way around these or just fault
 * and emulate if a guest tries to call swapgs directly.
 *
 * Either way, this is a good way to document that we don't
 * have a reliable stack. x86_64 only.
 */
#define SWAPGS_UNSAFE_STACK	swapgs

#define INTERRUPT_RETURN	jmp native_iret
#define USERGS_SYSRET64				\
	swapgs;					\
@@ -170,6 +158,14 @@ static __always_inline int arch_irqs_disabled(void)

	return arch_irqs_disabled_flags(flags);
}
#else
#ifdef CONFIG_X86_64
#ifdef CONFIG_XEN_PV
#define SWAPGS	ALTERNATIVE "swapgs", "", X86_FEATURE_XENPV
#else
#define SWAPGS	swapgs
#endif
#endif
#endif /* !__ASSEMBLY__ */

#endif
+0 −20
Original line number Diff line number Diff line
@@ -776,26 +776,6 @@ extern void default_banner(void);

#ifdef CONFIG_X86_64
#ifdef CONFIG_PARAVIRT_XXL
/*
 * If swapgs is used while the userspace stack is still current,
 * there's no way to call a pvop.  The PV replacement *must* be
 * inlined, or the swapgs instruction must be trapped and emulated.
 */
#define SWAPGS_UNSAFE_STACK						\
	PARA_SITE(PARA_PATCH(PV_CPU_swapgs), swapgs)

/*
 * Note: swapgs is very special, and in practise is either going to be
 * implemented with a single "swapgs" instruction or something very
 * special.  Either way, we don't need to save any registers for
 * it.
 */
#define SWAPGS								\
	PARA_SITE(PARA_PATCH(PV_CPU_swapgs),				\
		  ANNOTATE_RETPOLINE_SAFE;				\
		  call PARA_INDIRECT(pv_ops+PV_CPU_swapgs);		\
		 )

#define USERGS_SYSRET64							\
	PARA_SITE(PARA_PATCH(PV_CPU_usergs_sysret64),			\
		  ANNOTATE_RETPOLINE_SAFE;				\
+0 −2
Original line number Diff line number Diff line
@@ -168,8 +168,6 @@ struct pv_cpu_ops {
	   frame set up. */
	void (*iret)(void);

	void (*swapgs)(void);

	void (*start_context_switch)(struct task_struct *prev);
	void (*end_context_switch)(struct task_struct *next);
#endif
+0 −1
Original line number Diff line number Diff line
@@ -15,7 +15,6 @@ int main(void)
#ifdef CONFIG_PARAVIRT_XXL
	OFFSET(PV_CPU_usergs_sysret64, paravirt_patch_template,
	       cpu.usergs_sysret64);
	OFFSET(PV_CPU_swapgs, paravirt_patch_template, cpu.swapgs);
#ifdef CONFIG_DEBUG_ENTRY
	OFFSET(PV_IRQ_save_fl, paravirt_patch_template, irq.save_fl);
#endif
Loading