]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
x86/apic: Don't disable x2APIC if locked
authorDaniel Sneddon <daniel.sneddon@linux.intel.com>
Tue, 16 Aug 2022 23:19:42 +0000 (16:19 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 24 Oct 2022 07:58:12 +0000 (09:58 +0200)
[ Upstream commit b8d1d163604bd1e600b062fb00de5dc42baa355f ]

The APIC supports two modes, legacy APIC (or xAPIC), and Extended APIC
(or x2APIC).  X2APIC mode is mostly compatible with legacy APIC, but
it disables the memory-mapped APIC interface in favor of one that uses
MSRs.  The APIC mode is controlled by the EXT bit in the APIC MSR.

The MMIO/xAPIC interface has some problems, most notably the APIC LEAK
[1].  This bug allows an attacker to use the APIC MMIO interface to
extract data from the SGX enclave.

Introduce support for a new feature that will allow the BIOS to lock
the APIC in x2APIC mode.  If the APIC is locked in x2APIC mode and the
kernel tries to disable the APIC or revert to legacy APIC mode a GP
fault will occur.

Introduce support for a new MSR (IA32_XAPIC_DISABLE_STATUS) and handle
the new locked mode when the LEGACY_XAPIC_DISABLED bit is set by
preventing the kernel from trying to disable the x2APIC.

On platforms with the IA32_XAPIC_DISABLE_STATUS MSR, if SGX or TDX are
enabled the LEGACY_XAPIC_DISABLED will be set by the BIOS.  If
legacy APIC is required, then it SGX and TDX need to be disabled in the
BIOS.

[1]: https://aepicleak.com/aepicleak.pdf

Signed-off-by: Daniel Sneddon <daniel.sneddon@linux.intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Acked-by: Dave Hansen <dave.hansen@linux.intel.com>
Tested-by: Neelima Krishnan <neelima.krishnan@intel.com>
Link: https://lkml.kernel.org/r/20220816231943.1152579-1-daniel.sneddon@linux.intel.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
Documentation/admin-guide/kernel-parameters.txt
arch/x86/Kconfig
arch/x86/include/asm/cpu.h
arch/x86/include/asm/msr-index.h
arch/x86/kernel/apic/apic.c

index 1b38d0f70677e280446822fd004379a6b8c6665c..5ef5d727ca3431086492378c3fd050a9d65274a2 100644 (file)
 
        nox2apic        [X86-64,APIC] Do not enable x2APIC mode.
 
+                       NOTE: this parameter will be ignored on systems with the
+                       LEGACY_XAPIC_DISABLED bit set in the
+                       IA32_XAPIC_DISABLE_STATUS MSR.
+
        nps_mtm_hs_ctr= [KNL,ARC]
                        This parameter sets the maximum duration, in
                        cycles, each HW thread of the CTOP can run
index 25e2b8b75e40cdae9e324b55a32d84cb41ff64fc..1cccedfc2a486b62a2af5f6856519a03597a8800 100644 (file)
@@ -450,6 +450,11 @@ config X86_X2APIC
          This allows 32-bit apic IDs (so it can support very large systems),
          and accesses the local apic via MSRs not via mmio.
 
+         Some Intel systems circa 2022 and later are locked into x2APIC mode
+         and can not fall back to the legacy APIC modes if SGX or TDX are
+         enabled in the BIOS.  They will be unable to boot without enabling
+         this option.
+
          If you don't know what to do here, say N.
 
 config X86_MPPARSE
@@ -1930,7 +1935,7 @@ endchoice
 
 config X86_SGX
        bool "Software Guard eXtensions (SGX)"
-       depends on X86_64 && CPU_SUP_INTEL
+       depends on X86_64 && CPU_SUP_INTEL && X86_X2APIC
        depends on CRYPTO=y
        depends on CRYPTO_SHA256=y
        select SRCU
index 8cbf623f0ecfb6aec905ac8e376c7b0fe75933dc..b472ef76826ad93033128dd8198f32f83a9d584c 100644 (file)
@@ -94,4 +94,6 @@ static inline bool intel_cpu_signatures_match(unsigned int s1, unsigned int p1,
        return p1 & p2;
 }
 
+extern u64 x86_read_arch_cap_msr(void);
+
 #endif /* _ASM_X86_CPU_H */
index e057e039173cb627baeb133052b4a4991b44e382..9267bfe3c33f180b1b8eee77d781d4faf1be7765 100644 (file)
                                                 * Return Stack Buffer Predictions.
                                                 */
 
+#define ARCH_CAP_XAPIC_DISABLE         BIT(21) /*
+                                                * IA32_XAPIC_DISABLE_STATUS MSR
+                                                * supported
+                                                */
+
 #define MSR_IA32_FLUSH_CMD             0x0000010b
 #define L1D_FLUSH                      BIT(0)  /*
                                                 * Writeback and invalidate the
 #define MSR_IA32_HW_FEEDBACK_PTR        0x17d0
 #define MSR_IA32_HW_FEEDBACK_CONFIG     0x17d1
 
+/* x2APIC locked status */
+#define MSR_IA32_XAPIC_DISABLE_STATUS  0xBD
+#define LEGACY_XAPIC_DISABLED          BIT(0) /*
+                                               * x2APIC mode is locked and
+                                               * disabling x2APIC will cause
+                                               * a #GP
+                                               */
+
 #endif /* _ASM_X86_MSR_INDEX_H */
index 189d3a5e471adc43c44b7d6aa8d2805a0a9a475b..665993b2e80d2ac30f690a2a3ddf70cc387b6cc8 100644 (file)
@@ -61,6 +61,7 @@
 #include <asm/cpu_device_id.h>
 #include <asm/intel-family.h>
 #include <asm/irq_regs.h>
+#include <asm/cpu.h>
 
 unsigned int num_processors;
 
@@ -1756,11 +1757,26 @@ EXPORT_SYMBOL_GPL(x2apic_mode);
 
 enum {
        X2APIC_OFF,
-       X2APIC_ON,
        X2APIC_DISABLED,
+       /* All states below here have X2APIC enabled */
+       X2APIC_ON,
+       X2APIC_ON_LOCKED
 };
 static int x2apic_state;
 
+static bool x2apic_hw_locked(void)
+{
+       u64 ia32_cap;
+       u64 msr;
+
+       ia32_cap = x86_read_arch_cap_msr();
+       if (ia32_cap & ARCH_CAP_XAPIC_DISABLE) {
+               rdmsrl(MSR_IA32_XAPIC_DISABLE_STATUS, msr);
+               return (msr & LEGACY_XAPIC_DISABLED);
+       }
+       return false;
+}
+
 static void __x2apic_disable(void)
 {
        u64 msr;
@@ -1798,6 +1814,10 @@ static int __init setup_nox2apic(char *str)
                                apicid);
                        return 0;
                }
+               if (x2apic_hw_locked()) {
+                       pr_warn("APIC locked in x2apic mode, can't disable\n");
+                       return 0;
+               }
                pr_warn("x2apic already enabled.\n");
                __x2apic_disable();
        }
@@ -1812,10 +1832,18 @@ early_param("nox2apic", setup_nox2apic);
 void x2apic_setup(void)
 {
        /*
-        * If x2apic is not in ON state, disable it if already enabled
+        * Try to make the AP's APIC state match that of the BSP,  but if the
+        * BSP is unlocked and the AP is locked then there is a state mismatch.
+        * Warn about the mismatch in case a GP fault occurs due to a locked AP
+        * trying to be turned off.
+        */
+       if (x2apic_state != X2APIC_ON_LOCKED && x2apic_hw_locked())
+               pr_warn("x2apic lock mismatch between BSP and AP.\n");
+       /*
+        * If x2apic is not in ON or LOCKED state, disable it if already enabled
         * from BIOS.
         */
-       if (x2apic_state != X2APIC_ON) {
+       if (x2apic_state < X2APIC_ON) {
                __x2apic_disable();
                return;
        }
@@ -1836,6 +1864,11 @@ static __init void x2apic_disable(void)
        if (x2apic_id >= 255)
                panic("Cannot disable x2apic, id: %08x\n", x2apic_id);
 
+       if (x2apic_hw_locked()) {
+               pr_warn("Cannot disable locked x2apic, id: %08x\n", x2apic_id);
+               return;
+       }
+
        __x2apic_disable();
        register_lapic_address(mp_lapic_addr);
 }
@@ -1894,7 +1927,10 @@ void __init check_x2apic(void)
        if (x2apic_enabled()) {
                pr_info("x2apic: enabled by BIOS, switching to x2apic ops\n");
                x2apic_mode = 1;
-               x2apic_state = X2APIC_ON;
+               if (x2apic_hw_locked())
+                       x2apic_state = X2APIC_ON_LOCKED;
+               else
+                       x2apic_state = X2APIC_ON;
        } else if (!boot_cpu_has(X86_FEATURE_X2APIC)) {
                x2apic_state = X2APIC_DISABLED;
        }