Re: Save a WRMSR GS.base?

From: Andrew Cooper

Date: Thu Jun 04 2026 - 05:30:11 EST


On 04/06/2026 2:53 am, Borislav Petkov wrote:
> Hi,
>
> so here:
>
> diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
> index b85e715ebb30..ffa894bdb4ee 100644
> --- a/arch/x86/kernel/process_64.c
> +++ b/arch/x86/kernel/process_64.c
> @@ -400,7 +400,9 @@ static __always_inline void x86_fsgsbase_load(struct thread_struct *prev,
>
> /* Update the bases. */
> wrfsbase(next->fsbase);
> - __wrgsbase_inactive(next->gsbase);
> +
> + if (!cpu_feature_enabled(X86_FEATURE_LKGS))
> + __wrgsbase_inactive(next->gsbase);
> } else {
> load_seg_legacy(prev->fsindex, prev->fsbase,
> next->fsindex, next->fsbase, FS);
>
> a couple of lines above in that function we have:
>
> if (unlikely(prev->gsindex || next->gsindex))
> loadseg(GS, next->gsindex);
>
> which, on a FRED machine, would do LKGS. Now that insn does:
>
> GS.selector := SRC;
> GS.attributes := descriptor.attributes;
> IA32_KERNEL_GS_BASE := descriptor.base; // bits 63:32 cleared
>
> so I can save myself the __wrgsbase_inactive() which ends up doing WRMSR
> GS.base.
>
> Right? I.e., the diff above.
>
> We're also not doing the optimization of checking whether prev.GS.base and
> next.GS.base are equal. I see them both 0 in a trace here but I guess
> luserpace can change them so I guess we wanna overwrite GS.base on context
> switch unconditionally.
>
> But LKGS does that for us so we don't need the WRMSR GS.base there, right?
>
> Or am I missing something?

Yes, but it took me writing a "no" email to spot it.

If the LKGS (in load seg) was called unconditionally, then yes it would
be safe to drop the __wrgsbase_inactive(), but it's not.

Consider a prev and next which both have the same ->gsindex (so skips
loadseg()), but have different ->gsbase (still need to update KERN_GS_BASE).

~Andrew