Skip to content

Commit

Permalink
x86/efistub: Remap kernel text read-only before dropping NX attribute
Browse files Browse the repository at this point in the history
commit 9c55461 upstream.

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 <ardb@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
ardbiesheuvel authored and gregkh committed Apr 10, 2024
1 parent 4947db8 commit 70a2425
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 2 deletions.
2 changes: 1 addition & 1 deletion arch/x86/boot/compressed/Makefile
Expand Up @@ -84,7 +84,7 @@ LDFLAGS_vmlinux += -T
hostprogs := mkpiggy
HOST_EXTRACFLAGS += -I$(srctree)/tools/include

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

quiet_cmd_voffset = VOFFSET $@
cmd_voffset = $(NM) $< | sed -n $(sed-voffset) > $@
Expand Down
1 change: 1 addition & 0 deletions arch/x86/boot/compressed/misc.c
Expand Up @@ -330,6 +330,7 @@ static size_t parse_elf(void *output)
return ehdr.e_entry - LOAD_PHYSICAL_ADDR;
}

const unsigned long kernel_text_size = VO___start_rodata - VO__text;
const unsigned long kernel_total_size = VO__end - VO__text;

static u8 boot_heap[BOOT_HEAP_SIZE] __aligned(4);
Expand Down
1 change: 1 addition & 0 deletions arch/x86/include/asm/boot.h
Expand Up @@ -81,6 +81,7 @@

#ifndef __ASSEMBLY__
extern unsigned int output_len;
extern const unsigned long kernel_text_size;
extern const unsigned long kernel_total_size;

unsigned long decompress_kernel(unsigned char *outbuf, unsigned long virt_addr,
Expand Down
11 changes: 10 additions & 1 deletion drivers/firmware/efi/libstub/x86-stub.c
Expand Up @@ -238,6 +238,15 @@ efi_status_t efi_adjust_memory_range_protection(unsigned long start,
rounded_end = roundup(start + size, EFI_PAGE_SIZE);

if (memattr != NULL) {
status = efi_call_proto(memattr, set_memory_attributes,
rounded_start,
rounded_end - rounded_start,
EFI_MEMORY_RO);
if (status != EFI_SUCCESS) {
efi_warn("Failed to set EFI_MEMORY_RO attribute\n");
return status;
}

status = efi_call_proto(memattr, clear_memory_attributes,
rounded_start,
rounded_end - rounded_start,
Expand Down Expand Up @@ -818,7 +827,7 @@ static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry)

*kernel_entry = addr + entry;

return efi_adjust_memory_range_protection(addr, kernel_total_size);
return efi_adjust_memory_range_protection(addr, kernel_text_size);
}

static void __noreturn enter_kernel(unsigned long kernel_addr,
Expand Down

0 comments on commit 70a2425

Please sign in to comment.