x86: Add Kconfig option to require NX bit support

This option hardens Xen by forcing it to write secure (NX-enhanced) PTEs
regardless of the runtime NX feature bit in boot_cpu_data. This prevents an
attacker with partial write support from affecting Xen's PTE generation
logic by overriding the NX feature flag. The patch asserts support for the
NX bit in PTEs at boot time and if so short-circuits the cpu_has_nx macro
to 1.

It has the nice benefit of replacing many instances of runtime checks with
folded constants. This has several knock-on effects that improve codegen,
saving 2.5KiB off the text section.

The config option defaults to OFF for compatibility with previous
behaviour.

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
This commit is contained in:
Alejandro Vallejo authored and Andrew Cooper committed 2023-06-30 14:18:28 +01:00
1 parent fc3090a47b
commit 098e27578b
5 files changed
+43 -3

No files matched your search

+16
View File
@@ -307,6 +307,22 @@ config MEM_SHARING
bool "Xen memory sharing support (UNSUPPORTED)" if UNSUPPORTED
depends on HVM
config REQUIRE_NX
bool "Require NX (No eXecute) support"
help
No-eXecute (also called XD "eXecute Disable" and DEP "Data
Execution Prevention") is a security feature designed originally
to combat buffer overflow attacks by marking regions of memory
which the CPU must not interpret as instructions.
The NX feature exists in every 64bit CPU except for some very
early Pentium 4 Prescott machines.
Enabling this option will improve Xen's security by removing
cases where Xen could be tricked into thinking that the feature
was unavailable. However, if enabled, Xen will no longer boot on
any CPU which is lacking NX support.
endmenu
source "common/Kconfig"
+14 -1
View File
@@ -123,6 +123,7 @@ multiboot2_header:
.Lbad_ldr_nih: .asciz "ERR: EFI ImageHandle is not provided by bootloader!"
.Lbad_efi_msg: .asciz "ERR: EFI IA-32 platforms are not supported!"
.Lbag_alg_msg: .asciz "ERR: Xen must be loaded at a 2Mb boundary!"
.Lno_nx_msg: .asciz "ERR: Not an NX-capable CPU!"
.section .init.data, "aw", @progbits
.align 4
@@ -153,6 +154,11 @@ early_error: /* Here to improve the disassembly. */
.Lnot_aligned:
add $sym_offs(.Lbag_alg_msg), %esi
jmp .Lget_vtb
#ifdef CONFIG_REQUIRE_NX
.Lno_nx:
add $sym_offs(.Lno_nx_msg), %esi
jmp .Lget_vtb
#endif
.Lmb2_no_st:
/*
* Here we are on EFI platform. vga_text_buffer was zapped earlier
@@ -656,7 +662,12 @@ trampoline_setup:
bt $cpufeat_bit(X86_FEATURE_LM),%edx
jnc .Lbad_cpu
/* Check for NX */
/*
* Check for NX
* - If Xen was compiled requiring it simply assert it's
* supported. The trampoline already has the right constant.
* - Otherwise, update the trampoline EFER mask accordingly.
*/
bt $cpufeat_bit(X86_FEATURE_NX), %edx
jc .Lgot_nx
@@ -695,9 +706,11 @@ trampoline_setup:
jnc .Lno_nx
.Lgot_nx:
#ifndef CONFIG_REQUIRE_NX
/* Adjust EFER given that NX is present */
orb $EFER_NXE >> 8, 1 + sym_esi(trampoline_efer)
.Lno_nx:
#endif
/* Stash TSC to calculate a good approximation of time-since-boot */
rdtsc
+2 -1
View File
@@ -147,7 +147,8 @@ GLOBAL(trampoline_misc_enable_off)
/* EFER OR-mask for boot paths. SCE conditional on PV support, NX added when available. */
GLOBAL(trampoline_efer)
.long EFER_LME | (EFER_SCE * IS_ENABLED(CONFIG_PV))
.long EFER_LME | (EFER_SCE * IS_ENABLED(CONFIG_PV)) | \
(EFER_NXE * IS_ENABLED(CONFIG_REQUIRE_NX))
GLOBAL(trampoline_xen_phys_start)
.long 0
+9
View File
@@ -751,6 +751,15 @@ static void __init efi_arch_cpu(void)
{
caps[FEATURESET_e1d] = cpuid_edx(0x80000001);
/*
* This check purposefully doesn't use cpu_has_nx because
* cpu_has_nx bypasses the boot_cpu_data read if Xen was compiled
* with CONFIG_REQUIRE_NX
*/
if ( IS_ENABLED(CONFIG_REQUIRE_NX) &&
!boot_cpu_has(X86_FEATURE_NX) )
blexit(L"This build of Xen requires NX support");
if ( cpu_has_nx )
trampoline_efer |= EFER_NXE;
}
+2 -1
View File
@@ -91,7 +91,8 @@ static inline bool boot_cpu_has(unsigned int feat)
#define cpu_has_hypervisor boot_cpu_has(X86_FEATURE_HYPERVISOR)
/* CPUID level 0x80000001.edx */
#define cpu_has_nx boot_cpu_has(X86_FEATURE_NX)
#define cpu_has_nx (IS_ENABLED(CONFIG_REQUIRE_NX) || \
boot_cpu_has(X86_FEATURE_NX))
#define cpu_has_page1gb boot_cpu_has(X86_FEATURE_PAGE1GB)
#define cpu_has_rdtscp boot_cpu_has(X86_FEATURE_RDTSCP)
#define cpu_has_3dnow_ext boot_cpu_has(X86_FEATURE_3DNOWEXT)
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.