566 lines
19 KiB
Diff
566 lines
19 KiB
Diff
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
|
From: Peter Jones <pjones@redhat.com>
|
||
|
Date: Tue, 22 Mar 2022 10:57:07 -0400
|
||
|
Subject: [PATCH] nx: set attrs in our kernel loaders
|
||
|
|
||
|
For NX, our kernel loaders need to set write and execute page
|
||
|
permissions on allocated pages and the stack.
|
||
|
|
||
|
This patch adds those calls.
|
||
|
|
||
|
Signed-off-by: Peter Jones <pjones@redhat.com>
|
||
|
[rharwood: fix stack_attrs undefined, fix aarch64 callsites]
|
||
|
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
|
||
|
---
|
||
|
grub-core/kern/efi/mm.c | 77 +++++++++++++++++
|
||
|
grub-core/loader/arm64/linux.c | 16 +++-
|
||
|
grub-core/loader/arm64/xen_boot.c | 4 +-
|
||
|
grub-core/loader/efi/chainloader.c | 11 +++
|
||
|
grub-core/loader/efi/linux.c | 164 ++++++++++++++++++++++++++++++++++++-
|
||
|
grub-core/loader/i386/efi/linux.c | 26 +++++-
|
||
|
grub-core/loader/i386/linux.c | 5 ++
|
||
|
include/grub/efi/efi.h | 6 +-
|
||
|
include/grub/efi/linux.h | 16 +++-
|
||
|
include/grub/efi/pe32.h | 2 +
|
||
|
10 files changed, 312 insertions(+), 15 deletions(-)
|
||
|
|
||
|
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
|
||
|
index 2c33758ed7..e460b072e6 100644
|
||
|
--- a/grub-core/kern/efi/mm.c
|
||
|
+++ b/grub-core/kern/efi/mm.c
|
||
|
@@ -610,6 +610,81 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map,
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
+grub_addr_t grub_stack_addr = (grub_addr_t)-1ll;
|
||
|
+grub_size_t grub_stack_size = 0;
|
||
|
+
|
||
|
+static void
|
||
|
+grub_nx_init (void)
|
||
|
+{
|
||
|
+ grub_uint64_t attrs, stack_attrs;
|
||
|
+ grub_err_t err;
|
||
|
+ grub_addr_t stack_current, stack_end;
|
||
|
+ const grub_uint64_t page_size = 4096;
|
||
|
+ const grub_uint64_t page_mask = ~(page_size - 1);
|
||
|
+
|
||
|
+ /*
|
||
|
+ * These are to confirm that the flags are working as expected when
|
||
|
+ * debugging.
|
||
|
+ */
|
||
|
+ attrs = 0;
|
||
|
+ stack_current = (grub_addr_t)grub_nx_init & page_mask;
|
||
|
+ err = grub_get_mem_attrs (stack_current, page_size, &attrs);
|
||
|
+ if (err)
|
||
|
+ {
|
||
|
+ grub_dprintf ("nx",
|
||
|
+ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n",
|
||
|
+ stack_current, err);
|
||
|
+ grub_error_pop ();
|
||
|
+ }
|
||
|
+ else
|
||
|
+ grub_dprintf ("nx", "page attrs for grub_nx_init (%p) are %c%c%c\n",
|
||
|
+ grub_dl_load_core,
|
||
|
+ (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-',
|
||
|
+ (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-',
|
||
|
+ (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-');
|
||
|
+
|
||
|
+ stack_current = (grub_addr_t)&stack_current & page_mask;
|
||
|
+ err = grub_get_mem_attrs (stack_current, page_size, &stack_attrs);
|
||
|
+ if (err)
|
||
|
+ {
|
||
|
+ grub_dprintf ("nx",
|
||
|
+ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n",
|
||
|
+ stack_current, err);
|
||
|
+ grub_error_pop ();
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ attrs = stack_attrs;
|
||
|
+ grub_dprintf ("nx", "page attrs for stack (%p) are %c%c%c\n",
|
||
|
+ &attrs,
|
||
|
+ (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-',
|
||
|
+ (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-',
|
||
|
+ (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-');
|
||
|
+ }
|
||
|
+ for (stack_end = stack_current + page_size ;
|
||
|
+ !(attrs & GRUB_MEM_ATTR_R);
|
||
|
+ stack_end += page_size)
|
||
|
+ {
|
||
|
+ err = grub_get_mem_attrs (stack_current, page_size, &attrs);
|
||
|
+ if (err)
|
||
|
+ {
|
||
|
+ grub_dprintf ("nx",
|
||
|
+ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n",
|
||
|
+ stack_current, err);
|
||
|
+ grub_error_pop ();
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ if (stack_end > stack_current)
|
||
|
+ {
|
||
|
+ grub_stack_addr = stack_current;
|
||
|
+ grub_stack_size = stack_end - stack_current;
|
||
|
+ grub_dprintf ("nx",
|
||
|
+ "detected stack from 0x%"PRIxGRUB_ADDR" to 0x%"PRIxGRUB_ADDR"\n",
|
||
|
+ grub_stack_addr, grub_stack_addr + grub_stack_size - 1);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
void
|
||
|
grub_efi_mm_init (void)
|
||
|
{
|
||
|
@@ -623,6 +698,8 @@ grub_efi_mm_init (void)
|
||
|
grub_efi_uint64_t required_pages;
|
||
|
int mm_status;
|
||
|
|
||
|
+ grub_nx_init ();
|
||
|
+
|
||
|
/* Prepare a memory region to store two memory maps. */
|
||
|
memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
|
||
|
if (! memory_map)
|
||
|
diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
|
||
|
index cc67f43906..de85583487 100644
|
||
|
--- a/grub-core/loader/arm64/linux.c
|
||
|
+++ b/grub-core/loader/arm64/linux.c
|
||
|
@@ -172,7 +172,8 @@ free_params (void)
|
||
|
}
|
||
|
|
||
|
grub_err_t
|
||
|
-grub_arch_efi_linux_boot_image (grub_addr_t addr, char *args)
|
||
|
+grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args,
|
||
|
+ int nx_supported)
|
||
|
{
|
||
|
grub_err_t retval;
|
||
|
|
||
|
@@ -182,7 +183,8 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, char *args)
|
||
|
|
||
|
grub_dprintf ("linux", "linux command line: '%s'\n", args);
|
||
|
|
||
|
- retval = grub_efi_linux_boot ((char *)addr, handover_offset, (void *)addr);
|
||
|
+ retval = grub_efi_linux_boot (addr, size, handover_offset,
|
||
|
+ (void *)addr, nx_supported);
|
||
|
|
||
|
/* Never reached... */
|
||
|
free_params();
|
||
|
@@ -192,7 +194,10 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, char *args)
|
||
|
static grub_err_t
|
||
|
grub_linux_boot (void)
|
||
|
{
|
||
|
- return (grub_arch_efi_linux_boot_image((grub_addr_t)kernel_addr, linux_args));
|
||
|
+ return grub_arch_efi_linux_boot_image((grub_addr_t)kernel_addr,
|
||
|
+ (grub_size_t)kernel_size,
|
||
|
+ linux_args,
|
||
|
+ 0);
|
||
|
}
|
||
|
|
||
|
static grub_err_t
|
||
|
@@ -340,6 +345,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
||
|
grub_off_t filelen;
|
||
|
grub_uint32_t align;
|
||
|
void *kernel = NULL;
|
||
|
+ int nx_supported = 1;
|
||
|
|
||
|
grub_dl_ref (my_mod);
|
||
|
|
||
|
@@ -376,6 +382,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
||
|
grub_dprintf ("linux", "kernel entry offset : %d\n", handover_offset);
|
||
|
grub_dprintf ("linux", "kernel alignment : 0x%x\n", align);
|
||
|
|
||
|
+ err = grub_efi_check_nx_image_support((grub_addr_t)kernel, filelen, &nx_supported);
|
||
|
+ if (err != GRUB_ERR_NONE)
|
||
|
+ goto fail;
|
||
|
+
|
||
|
grub_loader_unset();
|
||
|
|
||
|
kernel_alloc_pages = GRUB_EFI_BYTES_TO_PAGES (kernel_size + align - 1);
|
||
|
diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c
|
||
|
index d9b7a9ba40..6e7e920416 100644
|
||
|
--- a/grub-core/loader/arm64/xen_boot.c
|
||
|
+++ b/grub-core/loader/arm64/xen_boot.c
|
||
|
@@ -266,7 +266,9 @@ xen_boot (void)
|
||
|
return err;
|
||
|
|
||
|
return grub_arch_efi_linux_boot_image (xen_hypervisor->start,
|
||
|
- xen_hypervisor->cmdline);
|
||
|
+ xen_hypervisor->size,
|
||
|
+ xen_hypervisor->cmdline,
|
||
|
+ 0);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
|
||
|
index fb874f1855..dd31ac9bb3 100644
|
||
|
--- a/grub-core/loader/efi/chainloader.c
|
||
|
+++ b/grub-core/loader/efi/chainloader.c
|
||
|
@@ -1070,6 +1070,17 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
|
||
|
goto fail;
|
||
|
}
|
||
|
|
||
|
+ /*
|
||
|
+ * The OS kernel is going to set its own permissions when it takes over
|
||
|
+ * paging a few million instructions from now, and load_image() will set up
|
||
|
+ * anything that's needed based on the section headers, so there's no point
|
||
|
+ * in doing anything but clearing the protection bits here.
|
||
|
+ */
|
||
|
+ grub_dprintf("nx", "setting attributes for %p (%lu bytes) to %llx\n",
|
||
|
+ (void *)(grub_addr_t)address, fsize, 0llu);
|
||
|
+ grub_update_mem_attrs (address, fsize,
|
||
|
+ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X, 0);
|
||
|
+
|
||
|
#if defined (__i386__) || defined (__x86_64__)
|
||
|
if (fsize >= (grub_ssize_t) sizeof (struct grub_macho_fat_header))
|
||
|
{
|
||
|
diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
|
||
|
index 9265cf4200..277f352e0c 100644
|
||
|
--- a/grub-core/loader/efi/linux.c
|
||
|
+++ b/grub-core/loader/efi/linux.c
|
||
|
@@ -26,16 +26,127 @@
|
||
|
|
||
|
#pragma GCC diagnostic push
|
||
|
#pragma GCC diagnostic ignored "-Wcast-align"
|
||
|
+#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
|
||
|
+
|
||
|
+grub_err_t
|
||
|
+grub_efi_check_nx_image_support (grub_addr_t kernel_addr,
|
||
|
+ grub_size_t kernel_size,
|
||
|
+ int *nx_supported)
|
||
|
+{
|
||
|
+ struct grub_dos_header *doshdr;
|
||
|
+ grub_size_t sz = sizeof (*doshdr);
|
||
|
+
|
||
|
+ struct grub_pe32_header_32 *pe32;
|
||
|
+ struct grub_pe32_header_64 *pe64;
|
||
|
+
|
||
|
+ int image_is_compatible = 0;
|
||
|
+ int is_64_bit;
|
||
|
+
|
||
|
+ if (kernel_size < sz)
|
||
|
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small"));
|
||
|
+
|
||
|
+ doshdr = (void *)kernel_addr;
|
||
|
+
|
||
|
+ if ((doshdr->magic & 0xffff) != GRUB_DOS_MAGIC)
|
||
|
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel DOS magic is invalid"));
|
||
|
+
|
||
|
+ sz = doshdr->lfanew + sizeof (*pe32);
|
||
|
+ if (kernel_size < sz)
|
||
|
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small"));
|
||
|
+
|
||
|
+ pe32 = (struct grub_pe32_header_32 *)(kernel_addr + doshdr->lfanew);
|
||
|
+ pe64 = (struct grub_pe32_header_64 *)pe32;
|
||
|
+
|
||
|
+ if (grub_memcmp (pe32->signature, GRUB_PE32_SIGNATURE,
|
||
|
+ GRUB_PE32_SIGNATURE_SIZE) != 0)
|
||
|
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel PE magic is invalid"));
|
||
|
+
|
||
|
+ switch (pe32->coff_header.machine)
|
||
|
+ {
|
||
|
+ case GRUB_PE32_MACHINE_ARMTHUMB_MIXED:
|
||
|
+ case GRUB_PE32_MACHINE_I386:
|
||
|
+ case GRUB_PE32_MACHINE_RISCV32:
|
||
|
+ is_64_bit = 0;
|
||
|
+ break;
|
||
|
+ case GRUB_PE32_MACHINE_ARM64:
|
||
|
+ case GRUB_PE32_MACHINE_IA64:
|
||
|
+ case GRUB_PE32_MACHINE_RISCV64:
|
||
|
+ case GRUB_PE32_MACHINE_X86_64:
|
||
|
+ is_64_bit = 1;
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ return grub_error (GRUB_ERR_BAD_OS, N_("PE machine type 0x%04hx unknown"),
|
||
|
+ pe32->coff_header.machine);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (is_64_bit)
|
||
|
+ {
|
||
|
+ sz = doshdr->lfanew + sizeof (*pe64);
|
||
|
+ if (kernel_size < sz)
|
||
|
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small"));
|
||
|
+
|
||
|
+ if (pe64->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT)
|
||
|
+ image_is_compatible = 1;
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ if (pe32->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT)
|
||
|
+ image_is_compatible = 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ *nx_supported = image_is_compatible;
|
||
|
+ return GRUB_ERR_NONE;
|
||
|
+}
|
||
|
+
|
||
|
+grub_err_t
|
||
|
+grub_efi_check_nx_required (int *nx_required)
|
||
|
+{
|
||
|
+ grub_efi_status_t status;
|
||
|
+ grub_efi_guid_t guid = GRUB_EFI_SHIM_LOCK_GUID;
|
||
|
+ grub_size_t mok_policy_sz = 0;
|
||
|
+ char *mok_policy = NULL;
|
||
|
+ grub_uint32_t mok_policy_attrs = 0;
|
||
|
+
|
||
|
+ status = grub_efi_get_variable_with_attributes ("MokPolicy", &guid,
|
||
|
+ &mok_policy_sz,
|
||
|
+ (void **)&mok_policy,
|
||
|
+ &mok_policy_attrs);
|
||
|
+ if (status == GRUB_EFI_NOT_FOUND ||
|
||
|
+ mok_policy_sz == 0 ||
|
||
|
+ mok_policy == NULL)
|
||
|
+ {
|
||
|
+ *nx_required = 0;
|
||
|
+ return GRUB_ERR_NONE;
|
||
|
+ }
|
||
|
+
|
||
|
+ *nx_required = 0;
|
||
|
+ if (mok_policy_sz < 1 ||
|
||
|
+ mok_policy_attrs != (GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||
|
+ GRUB_EFI_VARIABLE_RUNTIME_ACCESS) ||
|
||
|
+ (mok_policy[mok_policy_sz-1] & GRUB_MOK_POLICY_NX_REQUIRED))
|
||
|
+ *nx_required = 1;
|
||
|
+
|
||
|
+ return GRUB_ERR_NONE;
|
||
|
+}
|
||
|
|
||
|
typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *);
|
||
|
|
||
|
grub_err_t
|
||
|
-grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset,
|
||
|
- void *kernel_params)
|
||
|
+grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size,
|
||
|
+ grub_off_t handover_offset, void *kernel_params,
|
||
|
+ int nx_supported)
|
||
|
{
|
||
|
grub_efi_loaded_image_t *loaded_image = NULL;
|
||
|
handover_func hf;
|
||
|
int offset = 0;
|
||
|
+ grub_uint64_t stack_set_attrs = GRUB_MEM_ATTR_R |
|
||
|
+ GRUB_MEM_ATTR_W |
|
||
|
+ GRUB_MEM_ATTR_X;
|
||
|
+ grub_uint64_t stack_clear_attrs = 0;
|
||
|
+ grub_uint64_t kernel_set_attrs = stack_set_attrs;
|
||
|
+ grub_uint64_t kernel_clear_attrs = stack_clear_attrs;
|
||
|
+ grub_uint64_t attrs;
|
||
|
+ int nx_required = 0;
|
||
|
|
||
|
#ifdef __x86_64__
|
||
|
offset = 512;
|
||
|
@@ -48,12 +159,57 @@ grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset,
|
||
|
*/
|
||
|
loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
|
||
|
if (loaded_image)
|
||
|
- loaded_image->image_base = kernel_addr;
|
||
|
+ loaded_image->image_base = (void *)kernel_addr;
|
||
|
else
|
||
|
grub_dprintf ("linux", "Loaded Image base address could not be set\n");
|
||
|
|
||
|
grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n",
|
||
|
- kernel_addr, (void *)(grub_efi_uintn_t)handover_offset, kernel_params);
|
||
|
+ (void *)kernel_addr, (void *)handover_offset, kernel_params);
|
||
|
+
|
||
|
+
|
||
|
+ if (nx_required && !nx_supported)
|
||
|
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel does not support NX loading required by policy"));
|
||
|
+
|
||
|
+ if (nx_supported)
|
||
|
+ {
|
||
|
+ kernel_set_attrs &= ~GRUB_MEM_ATTR_W;
|
||
|
+ kernel_clear_attrs |= GRUB_MEM_ATTR_W;
|
||
|
+ stack_set_attrs &= ~GRUB_MEM_ATTR_X;
|
||
|
+ stack_clear_attrs |= GRUB_MEM_ATTR_X;
|
||
|
+ }
|
||
|
+
|
||
|
+ grub_dprintf ("nx", "Setting attributes for 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to r%cx\n",
|
||
|
+ kernel_addr, kernel_addr + kernel_size - 1,
|
||
|
+ (kernel_set_attrs & GRUB_MEM_ATTR_W) ? 'w' : '-');
|
||
|
+ grub_update_mem_attrs (kernel_addr, kernel_size,
|
||
|
+ kernel_set_attrs, kernel_clear_attrs);
|
||
|
+
|
||
|
+ grub_get_mem_attrs (kernel_addr, 4096, &attrs);
|
||
|
+ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n",
|
||
|
+ (grub_addr_t)kernel_addr,
|
||
|
+ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-",
|
||
|
+ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-",
|
||
|
+ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-");
|
||
|
+ if (grub_stack_addr != (grub_addr_t)-1ll)
|
||
|
+ {
|
||
|
+ grub_dprintf ("nx", "Setting attributes for stack at 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to rw%c\n",
|
||
|
+ grub_stack_addr, grub_stack_addr + grub_stack_size - 1,
|
||
|
+ (stack_set_attrs & GRUB_MEM_ATTR_X) ? 'x' : '-');
|
||
|
+ grub_update_mem_attrs (grub_stack_addr, grub_stack_size,
|
||
|
+ stack_set_attrs, stack_clear_attrs);
|
||
|
+
|
||
|
+ grub_get_mem_attrs (grub_stack_addr, 4096, &attrs);
|
||
|
+ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n",
|
||
|
+ grub_stack_addr,
|
||
|
+ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-",
|
||
|
+ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-",
|
||
|
+ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-");
|
||
|
+ }
|
||
|
+
|
||
|
+#if defined(__i386__) || defined(__x86_64__)
|
||
|
+ asm volatile ("cli");
|
||
|
+#endif
|
||
|
+
|
||
|
hf = (handover_func)((char *)kernel_addr + handover_offset + offset);
|
||
|
hf (grub_efi_image_handle, grub_efi_system_table, kernel_params);
|
||
|
|
||
|
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
|
||
|
index 92b2fb5091..91ae274299 100644
|
||
|
--- a/grub-core/loader/i386/efi/linux.c
|
||
|
+++ b/grub-core/loader/i386/efi/linux.c
|
||
|
@@ -44,7 +44,7 @@ struct grub_linuxefi_context {
|
||
|
grub_uint32_t handover_offset;
|
||
|
struct linux_kernel_params *params;
|
||
|
char *cmdline;
|
||
|
-
|
||
|
+ int nx_supported;
|
||
|
void *initrd_mem;
|
||
|
};
|
||
|
|
||
|
@@ -110,13 +110,19 @@ kernel_alloc(grub_efi_uintn_t size,
|
||
|
pages = BYTES_TO_PAGES(size);
|
||
|
grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n",
|
||
|
(unsigned long)pages, (void *)(unsigned long)max);
|
||
|
+ size = pages * GRUB_EFI_PAGE_SIZE;
|
||
|
|
||
|
prev_max = max;
|
||
|
addr = grub_efi_allocate_pages_real (max, pages,
|
||
|
max_addresses[i].alloc_type,
|
||
|
memtype);
|
||
|
if (addr)
|
||
|
- grub_dprintf ("linux", "Allocated at %p\n", addr);
|
||
|
+ {
|
||
|
+ grub_dprintf ("linux", "Allocated at %p\n", addr);
|
||
|
+ grub_update_mem_attrs ((grub_addr_t)addr, size,
|
||
|
+ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W,
|
||
|
+ GRUB_MEM_ATTR_X);
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
while (grub_error_pop ())
|
||
|
@@ -137,9 +143,11 @@ grub_linuxefi_boot (void *data)
|
||
|
|
||
|
asm volatile ("cli");
|
||
|
|
||
|
- return grub_efi_linux_boot ((char *)context->kernel_mem,
|
||
|
+ return grub_efi_linux_boot ((grub_addr_t)context->kernel_mem,
|
||
|
+ context->kernel_size,
|
||
|
context->handover_offset,
|
||
|
- context->params);
|
||
|
+ context->params,
|
||
|
+ context->nx_supported);
|
||
|
}
|
||
|
|
||
|
static grub_err_t
|
||
|
@@ -304,7 +312,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
||
|
grub_uint32_t handover_offset;
|
||
|
struct linux_kernel_params *params = 0;
|
||
|
char *cmdline = 0;
|
||
|
+ int nx_supported = 1;
|
||
|
struct grub_linuxefi_context *context = 0;
|
||
|
+ grub_err_t err;
|
||
|
|
||
|
grub_dl_ref (my_mod);
|
||
|
|
||
|
@@ -334,6 +344,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
||
|
goto fail;
|
||
|
}
|
||
|
|
||
|
+ err = grub_efi_check_nx_image_support ((grub_addr_t)kernel, filelen,
|
||
|
+ &nx_supported);
|
||
|
+ if (err != GRUB_ERR_NONE)
|
||
|
+ return err;
|
||
|
+ grub_dprintf ("linux", "nx is%s supported by this kernel\n",
|
||
|
+ nx_supported ? "" : " not");
|
||
|
+
|
||
|
lh = (struct linux_i386_kernel_header *)kernel;
|
||
|
grub_dprintf ("linux", "original lh is at %p\n", kernel);
|
||
|
|
||
|
@@ -498,6 +515,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
||
|
context->handover_offset = handover_offset;
|
||
|
context->params = params;
|
||
|
context->cmdline = cmdline;
|
||
|
+ context->nx_supported = nx_supported;
|
||
|
|
||
|
grub_loader_set_ex (grub_linuxefi_boot, grub_linuxefi_unload, context, 0);
|
||
|
|
||
|
diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
|
||
|
index 4aeb0e4b9a..3c1ff64763 100644
|
||
|
--- a/grub-core/loader/i386/linux.c
|
||
|
+++ b/grub-core/loader/i386/linux.c
|
||
|
@@ -805,6 +805,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
||
|
kernel_offset += len;
|
||
|
}
|
||
|
|
||
|
+ grub_dprintf("efi", "setting attributes for %p (%zu bytes) to +rw-x\n",
|
||
|
+ &linux_params, sizeof (lh) + len);
|
||
|
+ grub_update_mem_attrs ((grub_addr_t)&linux_params, sizeof (lh) + len,
|
||
|
+ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W, GRUB_MEM_ATTR_X);
|
||
|
+
|
||
|
linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR;
|
||
|
linux_params.kernel_alignment = (1 << align);
|
||
|
linux_params.ps_mouse = linux_params.padding11 = 0;
|
||
|
diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
|
||
|
index 34825c4adc..449e55269f 100644
|
||
|
--- a/include/grub/efi/efi.h
|
||
|
+++ b/include/grub/efi/efi.h
|
||
|
@@ -140,12 +140,16 @@ extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd,
|
||
|
char **device,
|
||
|
char **path);
|
||
|
|
||
|
+extern grub_addr_t EXPORT_VAR(grub_stack_addr);
|
||
|
+extern grub_size_t EXPORT_VAR(grub_stack_size);
|
||
|
+
|
||
|
#if defined(__arm__) || defined(__aarch64__) || defined(__riscv)
|
||
|
void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void);
|
||
|
grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *);
|
||
|
#include <grub/cpu/linux.h>
|
||
|
grub_err_t grub_arch_efi_linux_check_image(struct linux_arch_kernel_header *lh);
|
||
|
-grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, char *args);
|
||
|
+grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, grub_size_t size,
|
||
|
+ char *args, int nx_enabled);
|
||
|
#endif
|
||
|
|
||
|
grub_addr_t grub_efi_section_addr (const char *section);
|
||
|
diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h
|
||
|
index 887b02fd9f..b82f71006a 100644
|
||
|
--- a/include/grub/efi/linux.h
|
||
|
+++ b/include/grub/efi/linux.h
|
||
|
@@ -22,8 +22,20 @@
|
||
|
#include <grub/err.h>
|
||
|
#include <grub/symbol.h>
|
||
|
|
||
|
+#define GRUB_MOK_POLICY_NX_REQUIRED 0x1
|
||
|
+
|
||
|
grub_err_t
|
||
|
-EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset,
|
||
|
- void *kernel_param);
|
||
|
+EXPORT_FUNC(grub_efi_linux_boot) (grub_addr_t kernel_address,
|
||
|
+ grub_size_t kernel_size,
|
||
|
+ grub_off_t handover_offset,
|
||
|
+ void *kernel_param, int nx_enabled);
|
||
|
+
|
||
|
+grub_err_t
|
||
|
+EXPORT_FUNC(grub_efi_check_nx_image_support) (grub_addr_t kernel_addr,
|
||
|
+ grub_size_t kernel_size,
|
||
|
+ int *nx_supported);
|
||
|
+
|
||
|
+grub_err_t
|
||
|
+EXPORT_FUNC(grub_efi_check_nx_required) (int *nx_required);
|
||
|
|
||
|
#endif /* ! GRUB_EFI_LINUX_HEADER */
|
||
|
diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
|
||
|
index 2a5e1ee003..a5e623eb04 100644
|
||
|
--- a/include/grub/efi/pe32.h
|
||
|
+++ b/include/grub/efi/pe32.h
|
||
|
@@ -181,6 +181,8 @@ struct grub_pe32_optional_header
|
||
|
struct grub_pe32_data_directory reserved_entry;
|
||
|
};
|
||
|
|
||
|
+#define GRUB_PE32_NX_COMPAT 0x0100
|
||
|
+
|
||
|
struct grub_pe64_optional_header
|
||
|
{
|
||
|
grub_uint16_t magic;
|