Re: Save a WRMSR GS.base?

From: H. Peter Anvin

Date: Thu Jun 04 2026 - 22:36:54 EST


On June 4, 2026 7:24:28 PM PDT, Borislav Petkov <bp@xxxxxxxxx> wrote:
>On Thu, Jun 04, 2026 at 10:17:57AM +0100, Andrew Cooper wrote:
>> Yes, but it took me writing a "no" email to spot it.
>
>Oh, I know those situations.
>
>> 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).
>
>Gah, ofc.
>
>So we'll have to do something like this which is ugly as hell:
>
>---
>
>diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
>index b85e715ebb30..248c39da9ba0 100644
>--- a/arch/x86/kernel/process_64.c
>+++ b/arch/x86/kernel/process_64.c
>@@ -391,16 +391,23 @@ static __always_inline void x86_pkru_load(struct thread_struct *prev,
> static __always_inline void x86_fsgsbase_load(struct thread_struct *prev,
> struct thread_struct *next)
> {
>+ bool loaded_gs = false;
>+
> if (static_cpu_has(X86_FEATURE_FSGSBASE)) {
> /* Update the FS and GS selectors if they could have changed. */
> if (unlikely(prev->fsindex || next->fsindex))
> loadseg(FS, next->fsindex);
>- if (unlikely(prev->gsindex || next->gsindex))
>+
>+ if (unlikely(prev->gsindex || next->gsindex)) {
> loadseg(GS, next->gsindex);
>+ loaded_gs = true;
>+ }
>
> /* Update the bases. */
> wrfsbase(next->fsbase);
>- __wrgsbase_inactive(next->gsbase);
>+
>+ if (!(cpu_feature_enabled(X86_FEATURE_LKGS) && loaded_gs))
>+ __wrgsbase_inactive(next->gsbase);
> } else {
> load_seg_legacy(prev->fsindex, prev->fsbase,
> next->fsindex, next->fsbase, FS);
>
>
>Thx.
>

Also consider that user space might have done:

mov gs,...
wrgsbase ...

So gs.selector > 3 doesn't necessarily mean that the base is consistent with the descriptor.