Skip to content

Commit b8d1d16

Browse files
Daniel Sneddonhansendc
authored andcommitted
x86/apic: Don't disable x2APIC if locked
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 <[email protected]> Signed-off-by: Dave Hansen <[email protected]> Acked-by: Dave Hansen <[email protected]> Tested-by: Neelima Krishnan <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent b90cb10 commit b8d1d16

File tree

5 files changed

+65
-5
lines changed

5 files changed

+65
-5
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3805,6 +3805,10 @@
38053805

38063806
nox2apic [X86-64,APIC] Do not enable x2APIC mode.
38073807

3808+
NOTE: this parameter will be ignored on systems with the
3809+
LEGACY_XAPIC_DISABLED bit set in the
3810+
IA32_XAPIC_DISABLE_STATUS MSR.
3811+
38083812
nps_mtm_hs_ctr= [KNL,ARC]
38093813
This parameter sets the maximum duration, in
38103814
cycles, each HW thread of the CTOP can run

arch/x86/Kconfig

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,11 @@ config X86_X2APIC
448448
This allows 32-bit apic IDs (so it can support very large systems),
449449
and accesses the local apic via MSRs not via mmio.
450450

451+
Some Intel systems circa 2022 and later are locked into x2APIC mode
452+
and can not fall back to the legacy APIC modes if SGX or TDX are
453+
enabled in the BIOS. They will be unable to boot without enabling
454+
this option.
455+
451456
If you don't know what to do here, say N.
452457

453458
config X86_MPPARSE
@@ -1919,7 +1924,7 @@ endchoice
19191924

19201925
config X86_SGX
19211926
bool "Software Guard eXtensions (SGX)"
1922-
depends on X86_64 && CPU_SUP_INTEL
1927+
depends on X86_64 && CPU_SUP_INTEL && X86_X2APIC
19231928
depends on CRYPTO=y
19241929
depends on CRYPTO_SHA256=y
19251930
select SRCU

arch/x86/include/asm/cpu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,6 @@ static inline bool intel_cpu_signatures_match(unsigned int s1, unsigned int p1,
9494
return p1 & p2;
9595
}
9696

97+
extern u64 x86_read_arch_cap_msr(void);
98+
9799
#endif /* _ASM_X86_CPU_H */

arch/x86/include/asm/msr-index.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,11 @@
155155
* Return Stack Buffer Predictions.
156156
*/
157157

158+
#define ARCH_CAP_XAPIC_DISABLE BIT(21) /*
159+
* IA32_XAPIC_DISABLE_STATUS MSR
160+
* supported
161+
*/
162+
158163
#define MSR_IA32_FLUSH_CMD 0x0000010b
159164
#define L1D_FLUSH BIT(0) /*
160165
* Writeback and invalidate the
@@ -1054,4 +1059,12 @@
10541059
#define MSR_IA32_HW_FEEDBACK_PTR 0x17d0
10551060
#define MSR_IA32_HW_FEEDBACK_CONFIG 0x17d1
10561061

1062+
/* x2APIC locked status */
1063+
#define MSR_IA32_XAPIC_DISABLE_STATUS 0xBD
1064+
#define LEGACY_XAPIC_DISABLED BIT(0) /*
1065+
* x2APIC mode is locked and
1066+
* disabling x2APIC will cause
1067+
* a #GP
1068+
*/
1069+
10571070
#endif /* _ASM_X86_MSR_INDEX_H */

arch/x86/kernel/apic/apic.c

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
#include <asm/cpu_device_id.h>
6262
#include <asm/intel-family.h>
6363
#include <asm/irq_regs.h>
64+
#include <asm/cpu.h>
6465

6566
unsigned int num_processors;
6667

@@ -1751,11 +1752,26 @@ EXPORT_SYMBOL_GPL(x2apic_mode);
17511752

17521753
enum {
17531754
X2APIC_OFF,
1754-
X2APIC_ON,
17551755
X2APIC_DISABLED,
1756+
/* All states below here have X2APIC enabled */
1757+
X2APIC_ON,
1758+
X2APIC_ON_LOCKED
17561759
};
17571760
static int x2apic_state;
17581761

1762+
static bool x2apic_hw_locked(void)
1763+
{
1764+
u64 ia32_cap;
1765+
u64 msr;
1766+
1767+
ia32_cap = x86_read_arch_cap_msr();
1768+
if (ia32_cap & ARCH_CAP_XAPIC_DISABLE) {
1769+
rdmsrl(MSR_IA32_XAPIC_DISABLE_STATUS, msr);
1770+
return (msr & LEGACY_XAPIC_DISABLED);
1771+
}
1772+
return false;
1773+
}
1774+
17591775
static void __x2apic_disable(void)
17601776
{
17611777
u64 msr;
@@ -1793,6 +1809,10 @@ static int __init setup_nox2apic(char *str)
17931809
apicid);
17941810
return 0;
17951811
}
1812+
if (x2apic_hw_locked()) {
1813+
pr_warn("APIC locked in x2apic mode, can't disable\n");
1814+
return 0;
1815+
}
17961816
pr_warn("x2apic already enabled.\n");
17971817
__x2apic_disable();
17981818
}
@@ -1807,10 +1827,18 @@ early_param("nox2apic", setup_nox2apic);
18071827
void x2apic_setup(void)
18081828
{
18091829
/*
1810-
* If x2apic is not in ON state, disable it if already enabled
1830+
* Try to make the AP's APIC state match that of the BSP, but if the
1831+
* BSP is unlocked and the AP is locked then there is a state mismatch.
1832+
* Warn about the mismatch in case a GP fault occurs due to a locked AP
1833+
* trying to be turned off.
1834+
*/
1835+
if (x2apic_state != X2APIC_ON_LOCKED && x2apic_hw_locked())
1836+
pr_warn("x2apic lock mismatch between BSP and AP.\n");
1837+
/*
1838+
* If x2apic is not in ON or LOCKED state, disable it if already enabled
18111839
* from BIOS.
18121840
*/
1813-
if (x2apic_state != X2APIC_ON) {
1841+
if (x2apic_state < X2APIC_ON) {
18141842
__x2apic_disable();
18151843
return;
18161844
}
@@ -1831,6 +1859,11 @@ static __init void x2apic_disable(void)
18311859
if (x2apic_id >= 255)
18321860
panic("Cannot disable x2apic, id: %08x\n", x2apic_id);
18331861

1862+
if (x2apic_hw_locked()) {
1863+
pr_warn("Cannot disable locked x2apic, id: %08x\n", x2apic_id);
1864+
return;
1865+
}
1866+
18341867
__x2apic_disable();
18351868
register_lapic_address(mp_lapic_addr);
18361869
}
@@ -1889,7 +1922,10 @@ void __init check_x2apic(void)
18891922
if (x2apic_enabled()) {
18901923
pr_info("x2apic: enabled by BIOS, switching to x2apic ops\n");
18911924
x2apic_mode = 1;
1892-
x2apic_state = X2APIC_ON;
1925+
if (x2apic_hw_locked())
1926+
x2apic_state = X2APIC_ON_LOCKED;
1927+
else
1928+
x2apic_state = X2APIC_ON;
18931929
} else if (!boot_cpu_has(X86_FEATURE_X2APIC)) {
18941930
x2apic_state = X2APIC_DISABLED;
18951931
}

0 commit comments

Comments
 (0)