Re: [PATCH 25/24] x86/traps: Rewrite native_load_gs_index in C code

From: H. Peter Anvin
Date: Thu Sep 09 2021 - 19:17:26 EST


Come to think about it, I think it would be better if we were to incorporate the X86_BUG_NULL_SEG null segment load in into the main native_load_gs_index() code while we are swapgs'd anyway. This simplifies the code further, and should avoid calling native_load_gs_index() twice if this bug is enabled.

(This is the traps.c code only; removing the now unnecessary instances is left as an exercise for the reader...)

-hpa
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index a58800973aed..5de423a24777 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -671,6 +671,48 @@ DEFINE_IDTENTRY_RAW(exc_int3)
}

#ifdef CONFIG_X86_64
+
+/*
+ * Reload the %gs selector for user space (setting GS_BASE) with
+ * exception handling: if the selector is invalid, set %gs to NULL.
+ *
+ * selector: new selector
+ *
+ * This function is noinstr as it must not be instrumented.
+ */
+noinstr void native_load_gs_index(unsigned int selector)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+again:
+ native_swapgs();
+
+ if (static_cpu_has_bug(X86_BUG_NULL_SEG)) {
+ if (likely(selector <= 3))
+ asm volatile("mov %[seg],%%gs"
+ : : [seg] "rm" (__USER_DS));
+ }
+
+ asm_volatile_goto("1: mov %[seg],%%gs\n"
+ _ASM_EXTABLE(1b, %l[bad_seg])
+ : : [seg] "rm" (selector)
+ : : bad_seg);
+
+ alternative("", "mfence", X86_BUG_SWAPGS_FENCE);
+ native_swapgs();
+ local_irq_restore(flags);
+ return;
+
+bad_seg:
+ /*
+ * Invalid selector, set %gs to null (0).
+ */
+ selector = 0;
+ goto again;
+}
+
/*
* Help handler running on a per-cpu (IST or entry trampoline) stack
* to switch to the normal thread stack if the interrupted code was in