Skip to content

Commit 9c55461

Browse files
committed
x86/efistub: Remap kernel text read-only before dropping NX attribute
Currently, the EFI stub invokes the EFI memory attributes protocol to strip any NX restrictions from the entire loaded kernel, resulting in all code and data being mapped read-write-execute. The point of the EFI memory attributes protocol is to remove the need for all memory allocations to be mapped with both write and execute permissions by default, and make it the OS loader's responsibility to transition data mappings to code mappings where appropriate. Even though the UEFI specification does not appear to leave room for denying memory attribute changes based on security policy, let's be cautious and avoid relying on the ability to create read-write-execute mappings. This is trivially achievable, given that the amount of kernel code executing via the firmware's 1:1 mapping is rather small and limited to the .head.text region. So let's drop the NX restrictions only on that subregion, but not before remapping it as read-only first. Signed-off-by: Ard Biesheuvel <[email protected]>
1 parent d228814 commit 9c55461

File tree

4 files changed

+13
-2
lines changed

4 files changed

+13
-2
lines changed

arch/x86/boot/compressed/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ LDFLAGS_vmlinux += -T
8484
hostprogs := mkpiggy
8585
HOST_EXTRACFLAGS += -I$(srctree)/tools/include
8686

87-
sed-voffset := -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(_text\|__bss_start\|_end\)$$/\#define VO_\2 _AC(0x\1,UL)/p'
87+
sed-voffset := -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(_text\|__start_rodata\|__bss_start\|_end\)$$/\#define VO_\2 _AC(0x\1,UL)/p'
8888

8989
quiet_cmd_voffset = VOFFSET $@
9090
cmd_voffset = $(NM) $< | sed -n $(sed-voffset) > $@

arch/x86/boot/compressed/misc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ static size_t parse_elf(void *output)
330330
return ehdr.e_entry - LOAD_PHYSICAL_ADDR;
331331
}
332332

333+
const unsigned long kernel_text_size = VO___start_rodata - VO__text;
333334
const unsigned long kernel_total_size = VO__end - VO__text;
334335

335336
static u8 boot_heap[BOOT_HEAP_SIZE] __aligned(4);

arch/x86/include/asm/boot.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181

8282
#ifndef __ASSEMBLY__
8383
extern unsigned int output_len;
84+
extern const unsigned long kernel_text_size;
8485
extern const unsigned long kernel_total_size;
8586

8687
unsigned long decompress_kernel(unsigned char *outbuf, unsigned long virt_addr,

drivers/firmware/efi/libstub/x86-stub.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,15 @@ efi_status_t efi_adjust_memory_range_protection(unsigned long start,
236236
rounded_end = roundup(start + size, EFI_PAGE_SIZE);
237237

238238
if (memattr != NULL) {
239+
status = efi_call_proto(memattr, set_memory_attributes,
240+
rounded_start,
241+
rounded_end - rounded_start,
242+
EFI_MEMORY_RO);
243+
if (status != EFI_SUCCESS) {
244+
efi_warn("Failed to set EFI_MEMORY_RO attribute\n");
245+
return status;
246+
}
247+
239248
status = efi_call_proto(memattr, clear_memory_attributes,
240249
rounded_start,
241250
rounded_end - rounded_start,
@@ -812,7 +821,7 @@ static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry)
812821

813822
*kernel_entry = addr + entry;
814823

815-
return efi_adjust_memory_range_protection(addr, kernel_total_size);
824+
return efi_adjust_memory_range_protection(addr, kernel_text_size);
816825
}
817826

818827
static void __noreturn enter_kernel(unsigned long kernel_addr,

0 commit comments

Comments
 (0)