From: Dave Hansen <dave.hansen@linux.intel.com>
To: linux-kernel@vger.kernel.org
Cc: Andy Lutomirski <luto@kernel.org>,
Peter Zijlstra <peterz@infradead.org>,
Edgecombe, Rick P <rick.p.edgecombe@intel.com>,
Andrew Cooper <andrew.cooper3@citrix.com>,
the arch/x86 maintainers <x86@kernel.org>,
Kees Cook <kees@kernel.org>,
Pawan Gupta <pawan.kumar.gupta@linux.intel.com>,
Borislav Petkov <bp@alien8.de>, Thomas Gleixner <tglx@kernel.org>,
Dave Hansen <dave.hansen@linux.intel.com>
Subject: [RFC][PATCH 12/24] x86/cea: Map and use FRED exception shadow stacks
Date: Wed, 21 Oct 2026 12:51:36 -0700 [thread overview]
Message-ID: <20261021195136.687DBEA2@davehans-spike.ostc.intel.com> (raw)
In-Reply-To: <20261021195120.E61EC737@davehans-spike.ostc.intel.com>
FRED hardware automatically switches stacks between levels on different
kinds of kernel entries. Each normal FRED "RSP" stack has a corresponding
"SSP" shadow stack.
Leverage the existing CPU Entry Area infrastructure. Add shadow stacks
for levels 1-3 right next to the existing RSP stacks. Map them with
shadow stack permissions. Last, point the FRED SSP MSRs at the exception
stacks.
Just like the task stacks, do not leave a guard page since regular and
shadow stacks have mutually exclusive permissions and serve as guards
for each other.
Nit: The "return style" of the new cea_map_stack() and wrmsr() code
looks superficially inconsistent. But each site is consistent with the
code around it, just not when looking at the two sites against each
other.
== Future Work ==
The *_stack_guard[] elements could probably be removed now. When in
use, shadow stacks serve as guard pages for the regular stacks. When
not in use, the shadow stack region could remain unmapped and also act
as a guard area. But that would take some more fancy dynamic mapping
work. The existing CEA code is dirt simple and doing anything dynamic
would add complexity. KISS. The downside is wasting three pages per
CPU when shadow stacks support is compiled in but not used at runtime.
---
b/arch/x86/include/asm/cpu_entry_area.h | 15 +++++++++++++++
b/arch/x86/kernel/fred.c | 14 ++++++++++++++
b/arch/x86/mm/cpu_entry_area.c | 5 +++++
3 files changed, 34 insertions(+)
diff -puN arch/x86/include/asm/cpu_entry_area.h~cea-estacks-shadows-1 arch/x86/include/asm/cpu_entry_area.h
--- a/arch/x86/include/asm/cpu_entry_area.h~cea-estacks-shadows-1 2026-10-21 12:36:38.292881759 -0700
+++ b/arch/x86/include/asm/cpu_entry_area.h 2026-10-21 12:36:38.320881812 -0700
@@ -10,6 +10,12 @@
#ifdef CONFIG_X86_64
+#ifdef CONFIG_X86_KERN_SHADOW_STACK
+#define EXCEPTION_SHADOW_STKSZ PAGE_SIZE
+#else
+#define EXCEPTION_SHADOW_STKSZ 0
+#endif
+
#ifdef CONFIG_AMD_MEM_ENCRYPT
#define VC_EXCEPTION_STKSZ EXCEPTION_STKSZ
#else
@@ -19,10 +25,13 @@
/* Macro to enforce the same ordering and stack sizes */
#define ESTACKS_MEMBERS(guardsize, optional_stack_size) \
char DF_stack_guard[guardsize]; \
+ char DF_shadow_stack[EXCEPTION_SHADOW_STKSZ]; \
char DF_stack[EXCEPTION_STKSZ]; \
char NMI_stack_guard[guardsize]; \
+ char NMI_shadow_stack[EXCEPTION_SHADOW_STKSZ]; \
char NMI_stack[EXCEPTION_STKSZ]; \
char DB_stack_guard[guardsize]; \
+ char DB_shadow_stack[EXCEPTION_SHADOW_STKSZ]; \
char DB_stack[EXCEPTION_STKSZ]; \
char MCE_stack_guard[guardsize]; \
char MCE_stack[EXCEPTION_STKSZ]; \
@@ -151,4 +160,10 @@ static __always_inline struct entry_stac
#define __this_cpu_ist_bottom_va(name) \
CEA_ESTACK_BOT(__this_cpu_read(cea_exception_stacks), name, stack)
+#define __this_cpu_shadow_bottom_va(name) \
+ CEA_ESTACK_BOT(__this_cpu_read(cea_exception_stacks), name, shadow_stack)
+
+#define __this_cpu_shadow_top_va(name) \
+ CEA_ESTACK_TOP(__this_cpu_read(cea_exception_stacks), name, shadow_stack)
+
#endif
diff -puN arch/x86/kernel/fred.c~cea-estacks-shadows-1 arch/x86/kernel/fred.c
--- a/arch/x86/kernel/fred.c~cea-estacks-shadows-1 2026-10-21 12:36:38.294881762 -0700
+++ b/arch/x86/kernel/fred.c 2026-10-21 12:36:38.320881812 -0700
@@ -87,4 +87,18 @@ void cpu_init_fred_rsps(void)
wrmsrq(MSR_IA32_FRED_RSP1, __this_cpu_ist_top_va(DB));
wrmsrq(MSR_IA32_FRED_RSP2, __this_cpu_ist_top_va(NMI));
wrmsrq(MSR_IA32_FRED_RSP3, __this_cpu_ist_top_va(DF));
+
+ if (!cpu_has(&boot_cpu_data, X86_FEATURE_SHSTK))
+ return;
+
+ /*
+ * ...and the FRED shadow stacks when supported by the CPU.
+ *
+ * Note that this is strictly checking CPU support, not the
+ * kernel feature flag: X86_FEATURE_KERN_SHSTK. These MSRs
+ * may get set and then never used.
+ */
+ wrmsrq(MSR_IA32_FRED_SSP1, __this_cpu_shadow_top_va(DB));
+ wrmsrq(MSR_IA32_FRED_SSP2, __this_cpu_shadow_top_va(NMI));
+ wrmsrq(MSR_IA32_FRED_SSP3, __this_cpu_shadow_top_va(DF));
}
diff -puN arch/x86/mm/cpu_entry_area.c~cea-estacks-shadows-1 arch/x86/mm/cpu_entry_area.c
--- a/arch/x86/mm/cpu_entry_area.c~cea-estacks-shadows-1 2026-10-21 12:36:38.318881808 -0700
+++ b/arch/x86/mm/cpu_entry_area.c 2026-10-21 12:36:38.321881814 -0700
@@ -162,6 +162,11 @@ static void __init percpu_setup_exceptio
cea_map_stack(VC2, stack, PAGE_KERNEL);
}
}
+
+ /* Map the per-CPU exception shadow stacks: */
+ cea_map_stack(DB, shadow_stack, PAGE_KERNEL_SHSTK);
+ cea_map_stack(NMI, shadow_stack, PAGE_KERNEL_SHSTK);
+ cea_map_stack(DF, shadow_stack, PAGE_KERNEL_SHSTK);
}
#else
static void __init percpu_setup_exception_stacks(unsigned int cpu)
_
next prev parent reply other threads:[~2026-10-21 19:51 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-21 19:51 [RFC][PATCH 00/24] x86 Kernel Shadow Stacks Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 01/24] kernel/fork: Break out vmap task allocation into helper Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 02/24] kernel/fork: Use sizeof() union instead of TASK_SIZE Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 03/24] kernel/sched: Move thread stack to its own structure Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 04/24] kernel/fork: Allow arch-specific stack initialization Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 05/24] kernel/task: Add shadow stack to thread structure Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 06/24] kernel/task: Add "runtime" check for shadow stack support Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 07/24] kernel/fork: Clear shadow stacks alongside normal stacks Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 08/24] x86/cpu: Add basic x86 kernel shadow stack infrastructure Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 09/24] x86/cea: Refactor "CEA" macros to deal with multiple stacks Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 10/24] x86/cea: Refactor stack mapping macros Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 11/24] x86/mm: Add kernel shadow stack permission macros Dave Hansen
2026-10-21 19:51 ` Dave Hansen [this message]
2026-10-21 21:40 ` [RFC][PATCH 12/24] x86/cea: Map and use FRED exception shadow stacks Peter Zijlstra
2026-10-21 22:59 ` Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 13/24] x86/task: Grow thread_union for " Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 14/24] x86/mm: Establish shadow stack permissions in thread mapping Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 15/24] x86/task: Hook up arch hook to detect shadow stack enabling Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 16/24] x86/mm: Kill shadow stack page permission warning Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 17/24] x86/task: Context switch the kernel shadow stack register value Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 18/24] kernel/task: Add a helper to get the thread_union Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 19/24] x86/process: Initialize cloned task shadow stack Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 20/24] x86/entry: Stash kernel SSP on FRED entry Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 21/24] x86/extable: Update shadow stack entry frame during RIP overwrites Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 22/24] kernel/task: Add a helper to locate the top of the shadow stack Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 23/24] x86/entry: Populate FRED register for user=>kernel transitions Dave Hansen
2026-10-21 19:51 ` [RFC][PATCH 24/24] [DO NOT MERGE] x86/shstk: Depend out everything incompatible with kernel shadow stacks Dave Hansen
2026-10-21 21:36 ` [RFC][PATCH 00/24] x86 Kernel Shadow Stacks Peter Zijlstra
2026-10-21 21:53 ` Peter Zijlstra
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261021195136.687DBEA2@davehans-spike.ostc.intel.com \
--to=dave.hansen@linux.intel.com \
--cc=andrew.cooper3@citrix.com \
--cc=bp@alien8.de \
--cc=kees@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=luto@kernel.org \
--cc=pawan.kumar.gupta@linux.intel.com \
--cc=peterz@infradead.org \
--cc=rick.p.edgecombe@intel.com \
--cc=tglx@kernel.org \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®