[PATCH v11 9/9] x86/cpu: Enable LASS by default during CPU initialization

Sohil Mehta
2025-10-29T21:06:17Z

Linear Address Space Separation (LASS) mitigates a class of side-channel
attacks that rely on speculative access across the user/kernel boundary.

Enable LASS by default if the platform supports it. While at it, remove
the comment above the SMAP/SMEP/UMIP/LASS setup instead of updating it,
as the whole sequence is quite self-explanatory.

The legacy vsyscall page is mapped at 0xffffffffff60?000. Prior to LASS,
vsyscall page accesses would always generate a #PF. The kernel emulates
the accesses in the #PF handler and returns the appropriate values to
userspace.

With LASS, these accesses are intercepted before the paging structures
are traversed triggering a #GP instead of a #PF. To avoid breaking user
applications, equivalent emulation support is required in the #GP
handler. However, the #GP provides limited error information compared to
the #PF, making the emulation more complex.

For now, keep it simple and disable LASS if vsyscall emulation is
compiled in. This restricts LASS usability to newer environments where
legacy vsyscalls are absolutely not needed. In future, LASS support can
be expanded by enhancing the #GP handler.

Signed-off-by: Sohil Mehta <sohil.mehta@intel.com>
---
v11:
- Disable LASS if vsyscall emulation support is compiled in.
- Drop Rick's review tag because of the new changes.

v10
- No change.
---
arch/x86/kernel/cpu/common.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index c7d3512914ca..71e89859dfb4 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -401,6 +401,25 @@ static __always_inline void setup_umip(struct cpuinfo_x86 *c)
cr4_clear_bits(X86_CR4_UMIP);
}

+static __always_inline void setup_lass(struct cpuinfo_x86 *c)
+{
+ if (cpu_feature_enabled(X86_FEATURE_LASS)) {
+ /*
+ * Legacy vsyscall page access causes a #GP when LASS is
+ * active. However, vsyscall emulation isn't supported
+ * with #GP. To avoid breaking userspace, disable LASS
+ * if the emulation code is compiled in.
+ */
+ if (IS_ENABLED(CONFIG_X86_VSYSCALL_EMULATION)) {
+ pr_info_once("x86/cpu: Disabling LASS due to CONFIG_X86_VSYSCALL_EMULATION=y\n");
+ setup_clear_cpu_cap(X86_FEATURE_LASS);
+ return;
+ }
+
+ cr4_set_bits(X86_CR4_LASS);
+ }
+}
+
/* 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;
@@ -2011,10 +2030,10 @@ static void identify_cpu(struct cpuinfo_x86 *c)
/* Disable the PN if appropriate */
squash_the_stupid_serial_number(c);

- /* Set up SMEP/SMAP/UMIP */
setup_smep(c);
setup_smap(c);
setup_umip(c);
+ setup_lass(c);

/* Enable FSGSBASE instructions if available. */
if (cpu_has(c, X86_FEATURE_FSGSBASE)) {
--
2.43.0