* [PATCH 0/4] x86/CPU: Fix CR4 pinning and FRED in CoCo guests
@ 2026-03-20 11:54 Borislav Petkov
2026-03-20 11:54 ` [PATCH 1/4] x86/cpu: Enable FSGSBASE early in cpu_init_exception_handling() Borislav Petkov
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Borislav Petkov @ 2026-03-20 11:54 UTC (permalink / raw)
To: X86 ML; +Cc: Nikunj A Dadhania, LKML, Borislav Petkov (AMD)
From: "Borislav Petkov (AMD)" <bp@alien8.de>
Hi,
the respective patches have very detailed explanations about what this is
addressing but basically, there's a window in time during boot when FRED is
not setup properly yet and if a CoCo guest generates an exception, it would
explode.
So this shuffles things a bit so that that doesn't happen.
Thx.
Borislav Petkov (AMD) (1):
x86/cpu: Remove X86_CR4_FRED from the CR4 pinned bits mask
Nikunj A Dadhania (2):
x86/cpu: Enable FSGSBASE early in cpu_init_exception_handling()
x86/fred: Fix early boot failures on SEV-ES/SNP guests
Peter Zijlstra (1):
x86/cpu: Add comment clarifying CRn pinning
arch/x86/coco/sev/noinstr.c | 6 ++++++
arch/x86/entry/entry_fred.c | 14 ++++++++++++++
arch/x86/kernel/cpu/common.c | 33 ++++++++++++++++++++++++++-------
3 files changed, 46 insertions(+), 7 deletions(-)
--
2.51.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/4] x86/cpu: Enable FSGSBASE early in cpu_init_exception_handling()
2026-03-20 11:54 [PATCH 0/4] x86/CPU: Fix CR4 pinning and FRED in CoCo guests Borislav Petkov
@ 2026-03-20 11:54 ` Borislav Petkov
2026-03-20 11:54 ` [PATCH 2/4] x86/cpu: Remove X86_CR4_FRED from the CR4 pinned bits mask Borislav Petkov
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Borislav Petkov @ 2026-03-20 11:54 UTC (permalink / raw)
To: X86 ML; +Cc: Nikunj A Dadhania, LKML, Borislav Petkov, Sohil Mehta, stable
From: Nikunj A Dadhania <nikunj@amd.com>
Move FSGSBASE enablement from identify_cpu() to cpu_init_exception_handling()
to ensure it is enabled before any exceptions can occur on both boot and
secondary CPUs.
== Background ==
Exception entry code (paranoid_entry()) uses ALTERNATIVE patching based on
X86_FEATURE_FSGSBASE to decide whether to use RDGSBASE/WRGSBASE instructions
or the slower RDMSR/SWAPGS sequence for saving/restoring GSBASE.
On boot CPU, ALTERNATIVE patching happens after enabling FSGSBASE in CR4.
When the feature is available, the code is permanently patched to use
RDGSBASE/WRGSBASE, which require CR4.FSGSBASE=1 to execute without triggering
== Boot Sequence ==
Boot CPU (with CR pinning enabled):
trap_init()
cpu_init() <- Uses unpatched code (RDMSR/SWAPGS)
x2apic_setup()
...
arch_cpu_finalize_init()
identify_boot_cpu()
identify_cpu()
cr4_set_bits(X86_CR4_FSGSBASE) # Enables the feature
# This becomes part of cr4_pinned_bits
...
alternative_instructions() <- Patches code to use RDGSBASE/WRGSBASE
Secondary CPUs (with CR pinning enabled):
start_secondary()
cr4_init() <- Code already patched, CR4.FSGSBASE=1
set implicitly via cr4_pinned_bits
cpu_init() <- exceptions work because FSGSBASE is
already enabled
Secondary CPU (with CR pinning disabled):
start_secondary()
cr4_init() <- Code already patched, CR4.FSGSBASE=0
cpu_init()
x2apic_setup()
rdmsrq(MSR_IA32_APICBASE) <- Triggers #VC in SNP guests
exc_vmm_communication()
paranoid_entry() <- Uses RDGSBASE with CR4.FSGSBASE=0
(patched code)
...
ap_starting()
identify_secondary_cpu()
identify_cpu()
cr4_set_bits(X86_CR4_FSGSBASE) <- Enables the feature, which is
too late
== CR Pinning ==
Currently, for secondary CPUs, CR4.FSGSBASE is set implicitly through
CR-pinning: the boot CPU sets it during identify_cpu(), it becomes part of
cr4_pinned_bits, and cr4_init() applies those pinned bits to secondary CPUs.
This works but creates an undocumented dependency between cr4_init() and the
pinning mechanism.
== Problem ==
Secondary CPUs boot after alternatives have been applied globally. They
execute already-patched paranoid_entry() code that uses RDGSBASE/WRGSBASE
instructions, which require CR4.FSGSBASE=1. Upcoming changes to CR pinning
behavior will break the implicit dependency, causing secondary CPUs to
generate #UD.
This issue manifests itself on AMD SEV-SNP guests, where the rdmsrq() in
x2apic_setup() triggers a #VC exception early during cpu_init(). The #VC
handler (exc_vmm_communication()) executes the patched paranoid_entry() path.
Without CR4.FSGSBASE enabled, RDGSBASE instructions trigger #UD.
== Fix ==
Enable FSGSBASE explicitly in cpu_init_exception_handling() before loading
exception handlers. This makes the dependency explicit and ensures both
boot and secondary CPUs have FSGSBASE enabled before paranoid_entry()
executes.
Fixes: c82965f9e530 ("x86/entry/64: Handle FSGSBASE enabled paranoid entry/exit")
Reported-by: Borislav Petkov <bp@alien8.de>
Suggested-by: Sohil Mehta <sohil.mehta@intel.com>
Signed-off-by: Nikunj A Dadhania <nikunj@amd.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Reviewed-by: Sohil Mehta <sohil.mehta@intel.com>
Cc: <stable@kernel.org>
Link: https://patch.msgid.link/20260318075654.1792916-2-nikunj@amd.com
---
arch/x86/kernel/cpu/common.c | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index a8ff4376c286..7840b224d6a7 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -2050,12 +2050,6 @@ static void identify_cpu(struct cpuinfo_x86 *c)
setup_umip(c);
setup_lass(c);
- /* Enable FSGSBASE instructions if available. */
- if (cpu_has(c, X86_FEATURE_FSGSBASE)) {
- cr4_set_bits(X86_CR4_FSGSBASE);
- elf_hwcap2 |= HWCAP2_FSGSBASE;
- }
-
/*
* The vendor-specific functions might have changed features.
* Now we do "generic changes."
@@ -2416,6 +2410,18 @@ void cpu_init_exception_handling(bool boot_cpu)
/* GHCB needs to be setup to handle #VC. */
setup_ghcb();
+ /*
+ * On CPUs with FSGSBASE support, paranoid_entry() uses
+ * ALTERNATIVE-patched RDGSBASE/WRGSBASE instructions. Secondary CPUs
+ * boot after alternatives are patched globally, so early exceptions
+ * execute patched code that depends on FSGSBASE. Enable the feature
+ * before any exceptions occur.
+ */
+ if (cpu_feature_enabled(X86_FEATURE_FSGSBASE)) {
+ cr4_set_bits(X86_CR4_FSGSBASE);
+ elf_hwcap2 |= HWCAP2_FSGSBASE;
+ }
+
if (cpu_feature_enabled(X86_FEATURE_FRED)) {
/* The boot CPU has enabled FRED during early boot */
if (!boot_cpu)
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/4] x86/cpu: Remove X86_CR4_FRED from the CR4 pinned bits mask
2026-03-20 11:54 [PATCH 0/4] x86/CPU: Fix CR4 pinning and FRED in CoCo guests Borislav Petkov
2026-03-20 11:54 ` [PATCH 1/4] x86/cpu: Enable FSGSBASE early in cpu_init_exception_handling() Borislav Petkov
@ 2026-03-20 11:54 ` Borislav Petkov
2026-03-20 17:49 ` Sohil Mehta
2026-03-20 11:54 ` [PATCH 3/4] x86/fred: Fix early boot failures on SEV-ES/SNP guests Borislav Petkov
2026-03-20 11:54 ` [PATCH 4/4] x86/cpu: Add comment clarifying CRn pinning Borislav Petkov
3 siblings, 1 reply; 6+ messages in thread
From: Borislav Petkov @ 2026-03-20 11:54 UTC (permalink / raw)
To: X86 ML
Cc: Nikunj A Dadhania, LKML, Borislav Petkov (AMD), Dave Hansen,
Peter Zijlstra, stable
From: "Borislav Petkov (AMD)" <bp@alien8.de>
Commit in Fixes added the FRED CR4 bit to the CR4 pinned bits mask so
that whenever something else modifies CR4, that bit remains set. Which
in itself is a perfectly fine idea.
However, there's an issue when during boot FRED is initialized: first on
the BSP and later on the APs. Thus, there's a window in time when
exceptions cannot be handled.
This becomes particularly nasty when running as SEV-{ES,SNP} or TDX
guests which, when they manage to trigger exceptions during that short
window described above, triple fault due to FRED MSRs not being set up
yet.
See Link tag below for a much more detailed explanation of the
situation.
So, as a result, the commit in that Link URL tried to address this
shortcoming by temporarily disabling CR4 pinning when an AP is not
online yet.
However, that is a problem in itself because in this case, an attack on
the kernel needs to only modify the online bit - a single bit in RW
memory - and then disable CR4 pinning and then disable SM*P, leading to
more and worse things to happen to the system.
So, instead, remove the FRED bit from the CR4 pinning mask, thus
obviating the need to temporarily disable CR4 pinning.
If someone manages to disable FRED when poking at CR4, then
idt_invalidate() would make sure the system would crash'n'burn on the
first exception triggered, which is a much better outcome security-wise.
Fixes: ff45746fbf00 ("x86/cpu: Add X86_CR4_FRED macro")
Suggested-by: Dave Hansen <dave.hansen@linux.intel.com>
Suggested-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Cc: <stable@kernel.org> # 6.12+
Link: https://lore.kernel.org/r/177385987098.1647592.3381141860481415647.tip-bot2@tip-bot2
---
arch/x86/kernel/cpu/common.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 7840b224d6a7..c57e8972d30f 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -433,7 +433,7 @@ static __always_inline void setup_lass(struct cpuinfo_x86 *c)
/* These bits should not change their value after CPU init is finished. */
static const unsigned long cr4_pinned_mask = X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_UMIP |
- X86_CR4_FSGSBASE | X86_CR4_CET | X86_CR4_FRED;
+ X86_CR4_FSGSBASE | X86_CR4_CET;
static DEFINE_STATIC_KEY_FALSE_RO(cr_pinning);
static unsigned long cr4_pinned_bits __ro_after_init;
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/4] x86/fred: Fix early boot failures on SEV-ES/SNP guests
2026-03-20 11:54 [PATCH 0/4] x86/CPU: Fix CR4 pinning and FRED in CoCo guests Borislav Petkov
2026-03-20 11:54 ` [PATCH 1/4] x86/cpu: Enable FSGSBASE early in cpu_init_exception_handling() Borislav Petkov
2026-03-20 11:54 ` [PATCH 2/4] x86/cpu: Remove X86_CR4_FRED from the CR4 pinned bits mask Borislav Petkov
@ 2026-03-20 11:54 ` Borislav Petkov
2026-03-20 11:54 ` [PATCH 4/4] x86/cpu: Add comment clarifying CRn pinning Borislav Petkov
3 siblings, 0 replies; 6+ messages in thread
From: Borislav Petkov @ 2026-03-20 11:54 UTC (permalink / raw)
To: X86 ML; +Cc: Nikunj A Dadhania, LKML, Borislav Petkov (AMD), Tom Lendacky,
stable
From: Nikunj A Dadhania <nikunj@amd.com>
FRED-enabled SEV-(ES,SNP) guests fail to boot due to the following issues
in the early boot sequence:
* FRED does not have a #VC exception handler in the dispatch logic
* Early FRED #VC exceptions attempt to use uninitialized per-CPU GHCBs
instead of boot_ghcb
Add X86_TRAP_VC case to fred_hwexc() with a new exc_vmm_communication()
function that provides the unified entry point FRED requires, dispatching
to existing user/kernel handlers based on privilege level. The function is
already declared via DECLARE_IDTENTRY_VC().
Fix early GHCB access by falling back to boot_ghcb in
__sev_{get,put}_ghcb() when per-CPU GHCBs are not yet initialized.
Fixes: 14619d912b65 ("x86/fred: FRED entry/exit and dispatch code")
Signed-off-by: Nikunj A Dadhania <nikunj@amd.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
Cc: <stable@kernel.org> # 6.12+
Link: https://patch.msgid.link/20260318075654.1792916-4-nikunj@amd.com
---
arch/x86/coco/sev/noinstr.c | 6 ++++++
arch/x86/entry/entry_fred.c | 14 ++++++++++++++
2 files changed, 20 insertions(+)
diff --git a/arch/x86/coco/sev/noinstr.c b/arch/x86/coco/sev/noinstr.c
index 9d94aca4a698..5afd663a1c21 100644
--- a/arch/x86/coco/sev/noinstr.c
+++ b/arch/x86/coco/sev/noinstr.c
@@ -121,6 +121,9 @@ noinstr struct ghcb *__sev_get_ghcb(struct ghcb_state *state)
WARN_ON(!irqs_disabled());
+ if (!sev_cfg.ghcbs_initialized)
+ return boot_ghcb;
+
data = this_cpu_read(runtime_data);
ghcb = &data->ghcb_page;
@@ -164,6 +167,9 @@ noinstr void __sev_put_ghcb(struct ghcb_state *state)
WARN_ON(!irqs_disabled());
+ if (!sev_cfg.ghcbs_initialized)
+ return;
+
data = this_cpu_read(runtime_data);
ghcb = &data->ghcb_page;
diff --git a/arch/x86/entry/entry_fred.c b/arch/x86/entry/entry_fred.c
index 88c757ac8ccd..fbe2d10dd737 100644
--- a/arch/x86/entry/entry_fred.c
+++ b/arch/x86/entry/entry_fred.c
@@ -177,6 +177,16 @@ static noinstr void fred_extint(struct pt_regs *regs)
}
}
+#ifdef CONFIG_AMD_MEM_ENCRYPT
+noinstr void exc_vmm_communication(struct pt_regs *regs, unsigned long error_code)
+{
+ if (user_mode(regs))
+ return user_exc_vmm_communication(regs, error_code);
+ else
+ return kernel_exc_vmm_communication(regs, error_code);
+}
+#endif
+
static noinstr void fred_hwexc(struct pt_regs *regs, unsigned long error_code)
{
/* Optimize for #PF. That's the only exception which matters performance wise */
@@ -207,6 +217,10 @@ static noinstr void fred_hwexc(struct pt_regs *regs, unsigned long error_code)
#ifdef CONFIG_X86_CET
case X86_TRAP_CP: return exc_control_protection(regs, error_code);
#endif
+#ifdef CONFIG_AMD_MEM_ENCRYPT
+ case X86_TRAP_VC: return exc_vmm_communication(regs, error_code);
+#endif
+
default: return fred_bad_type(regs, error_code);
}
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 4/4] x86/cpu: Add comment clarifying CRn pinning
2026-03-20 11:54 [PATCH 0/4] x86/CPU: Fix CR4 pinning and FRED in CoCo guests Borislav Petkov
` (2 preceding siblings ...)
2026-03-20 11:54 ` [PATCH 3/4] x86/fred: Fix early boot failures on SEV-ES/SNP guests Borislav Petkov
@ 2026-03-20 11:54 ` Borislav Petkov
3 siblings, 0 replies; 6+ messages in thread
From: Borislav Petkov @ 2026-03-20 11:54 UTC (permalink / raw)
To: X86 ML; +Cc: Nikunj A Dadhania, LKML, Peter Zijlstra, Borislav Petkov (AMD)
From: Peter Zijlstra <peterz@infradead.org>
To avoid future confusion on the purpose and design of the CRn pinning code.
Also note that if the attacker controls page-tables, the CRn bits lose much of
the attraction anyway.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://patch.msgid.link/20260320092521.GG3739106@noisy.programming.kicks-ass.net
---
arch/x86/kernel/cpu/common.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index c57e8972d30f..ec0670114efa 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -434,6 +434,19 @@ static __always_inline void setup_lass(struct cpuinfo_x86 *c)
/* These bits should not change their value after CPU init is finished. */
static const unsigned long cr4_pinned_mask = X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_UMIP |
X86_CR4_FSGSBASE | X86_CR4_CET;
+
+/*
+ * The CR pinning protects against ROP on the 'mov %reg, %CRn' instruction(s).
+ * Since you can ROP directly to these instructions (barring shadow stack),
+ * any protection must follow immediately and unconditionally after that.
+ *
+ * Specifically, the CR[04] write functions below will have the value
+ * validation controlled by the @cr_pinning static_branch which is
+ * __ro_after_init, just like the cr4_pinned_bits value.
+ *
+ * Once set, an attacker will have to defeat page-tables to get around these
+ * restrictions. Which is a much bigger ask than 'simple' ROP.
+ */
static DEFINE_STATIC_KEY_FALSE_RO(cr_pinning);
static unsigned long cr4_pinned_bits __ro_after_init;
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 2/4] x86/cpu: Remove X86_CR4_FRED from the CR4 pinned bits mask
2026-03-20 11:54 ` [PATCH 2/4] x86/cpu: Remove X86_CR4_FRED from the CR4 pinned bits mask Borislav Petkov
@ 2026-03-20 17:49 ` Sohil Mehta
0 siblings, 0 replies; 6+ messages in thread
From: Sohil Mehta @ 2026-03-20 17:49 UTC (permalink / raw)
To: Borislav Petkov, X86 ML
Cc: Nikunj A Dadhania, LKML, Borislav Petkov (AMD), Dave Hansen,
Peter Zijlstra, stable
On 3/20/2026 4:54 AM, Borislav Petkov wrote:
> So, instead, remove the FRED bit from the CR4 pinning mask, thus
> obviating the need to temporarily disable CR4 pinning.
>
> If someone manages to disable FRED when poking at CR4, then
> idt_invalidate() would make sure the system would crash'n'burn on the
> first exception triggered, which is a much better outcome security-wise.
>
> Fixes: ff45746fbf00 ("x86/cpu: Add X86_CR4_FRED macro")
> Suggested-by: Dave Hansen <dave.hansen@linux.intel.com>
> Suggested-by: Peter Zijlstra <peterz@infradead.org>
> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
> Cc: <stable@kernel.org> # 6.12+
> Link: https://lore.kernel.org/r/177385987098.1647592.3381141860481415647.tip-bot2@tip-bot2
> ---
> arch/x86/kernel/cpu/common.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
Reviewed-by: Sohil Mehta <sohil.mehta@intel.com>
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-03-20 17:49 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-20 11:54 [PATCH 0/4] x86/CPU: Fix CR4 pinning and FRED in CoCo guests Borislav Petkov
2026-03-20 11:54 ` [PATCH 1/4] x86/cpu: Enable FSGSBASE early in cpu_init_exception_handling() Borislav Petkov
2026-03-20 11:54 ` [PATCH 2/4] x86/cpu: Remove X86_CR4_FRED from the CR4 pinned bits mask Borislav Petkov
2026-03-20 17:49 ` Sohil Mehta
2026-03-20 11:54 ` [PATCH 3/4] x86/fred: Fix early boot failures on SEV-ES/SNP guests Borislav Petkov
2026-03-20 11:54 ` [PATCH 4/4] x86/cpu: Add comment clarifying CRn pinning Borislav Petkov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox