|
|
b9d01e |
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
|
b9d01e |
From: Peter Jones <pjones@redhat.com>
|
|
|
b9d01e |
Date: Tue, 22 Mar 2022 10:57:07 -0400
|
|
|
b9d01e |
Subject: [PATCH] nx: set attrs in our kernel loaders
|
|
|
b9d01e |
|
|
|
b9d01e |
For NX, our kernel loaders need to set write and execute page
|
|
|
b9d01e |
permissions on allocated pages and the stack.
|
|
|
b9d01e |
|
|
|
b9d01e |
This patch adds those calls.
|
|
|
b9d01e |
|
|
|
b9d01e |
Signed-off-by: Peter Jones <pjones@redhat.com>
|
|
|
b9d01e |
[rharwood: fix aarch64 callsites]
|
|
|
b9d01e |
(cherry-picked from commit a9f79a997f01a83b36cdfa89ef2e72ac2a17c06c)
|
|
|
b9d01e |
[rharwood: double verification]
|
|
|
b9d01e |
(cherry picked from commit daba852bd3e4d7b7784b19cf7acf107dc3c0dce4)
|
|
|
b9d01e |
[rharwood: stack_attrs initialization, no risc-v, arm renames, arm age]
|
|
|
b9d01e |
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
|
|
|
b9d01e |
---
|
|
|
b9d01e |
grub-core/kern/efi/mm.c | 78 ++++++++++++++++++
|
|
|
b9d01e |
grub-core/loader/arm64/linux.c | 16 +++-
|
|
|
b9d01e |
grub-core/loader/arm64/xen_boot.c | 4 +-
|
|
|
b9d01e |
grub-core/loader/efi/chainloader.c | 11 +++
|
|
|
b9d01e |
grub-core/loader/efi/linux.c | 162 ++++++++++++++++++++++++++++++++++++-
|
|
|
b9d01e |
grub-core/loader/i386/efi/linux.c | 26 +++++-
|
|
|
b9d01e |
grub-core/loader/i386/linux.c | 5 ++
|
|
|
b9d01e |
include/grub/efi/efi.h | 6 +-
|
|
|
b9d01e |
include/grub/efi/linux.h | 17 +++-
|
|
|
b9d01e |
include/grub/efi/pe32.h | 2 +
|
|
|
b9d01e |
10 files changed, 312 insertions(+), 15 deletions(-)
|
|
|
b9d01e |
|
|
|
b9d01e |
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
|
|
|
b9d01e |
index 2cf4a4883a..8a896144df 100644
|
|
|
b9d01e |
--- a/grub-core/kern/efi/mm.c
|
|
|
b9d01e |
+++ b/grub-core/kern/efi/mm.c
|
|
|
b9d01e |
@@ -602,6 +602,82 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map,
|
|
|
b9d01e |
}
|
|
|
b9d01e |
#endif
|
|
|
b9d01e |
|
|
|
b9d01e |
+grub_addr_t grub_stack_addr = (grub_addr_t)-1ll;
|
|
|
b9d01e |
+grub_size_t grub_stack_size = 0;
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+static void
|
|
|
b9d01e |
+grub_nx_init (void)
|
|
|
b9d01e |
+{
|
|
|
b9d01e |
+ grub_uint64_t attrs, stack_attrs;
|
|
|
b9d01e |
+ grub_err_t err;
|
|
|
b9d01e |
+ grub_addr_t stack_current, stack_end;
|
|
|
b9d01e |
+ const grub_uint64_t page_size = 4096;
|
|
|
b9d01e |
+ const grub_uint64_t page_mask = ~(page_size - 1);
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ /*
|
|
|
b9d01e |
+ * These are to confirm that the flags are working as expected when
|
|
|
b9d01e |
+ * debugging.
|
|
|
b9d01e |
+ */
|
|
|
b9d01e |
+ attrs = 0;
|
|
|
b9d01e |
+ stack_current = (grub_addr_t)grub_nx_init & page_mask;
|
|
|
b9d01e |
+ err = grub_get_mem_attrs (stack_current, page_size, &attrs);
|
|
|
b9d01e |
+ if (err)
|
|
|
b9d01e |
+ {
|
|
|
b9d01e |
+ grub_dprintf ("nx",
|
|
|
b9d01e |
+ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n",
|
|
|
b9d01e |
+ stack_current, err);
|
|
|
b9d01e |
+ grub_error_pop ();
|
|
|
b9d01e |
+ }
|
|
|
b9d01e |
+ else
|
|
|
b9d01e |
+ grub_dprintf ("nx", "page attrs for grub_nx_init (%p) are %c%c%c\n",
|
|
|
b9d01e |
+ grub_dl_load_core,
|
|
|
b9d01e |
+ (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-',
|
|
|
b9d01e |
+ (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-',
|
|
|
b9d01e |
+ (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-');
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ stack_current = (grub_addr_t)&stack_current & page_mask;
|
|
|
b9d01e |
+ err = grub_get_mem_attrs (stack_current, page_size, &stack_attrs);
|
|
|
b9d01e |
+ if (err)
|
|
|
b9d01e |
+ {
|
|
|
b9d01e |
+ grub_dprintf ("nx",
|
|
|
b9d01e |
+ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n",
|
|
|
b9d01e |
+ stack_current, err);
|
|
|
b9d01e |
+ grub_error_pop ();
|
|
|
b9d01e |
+ }
|
|
|
b9d01e |
+ else
|
|
|
b9d01e |
+ {
|
|
|
b9d01e |
+ attrs = stack_attrs;
|
|
|
b9d01e |
+ grub_dprintf ("nx", "page attrs for stack (%p) are %c%c%c\n",
|
|
|
b9d01e |
+ &attrs,
|
|
|
b9d01e |
+ (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-',
|
|
|
b9d01e |
+ (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-',
|
|
|
b9d01e |
+ (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-');
|
|
|
b9d01e |
+ }
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ for (stack_end = stack_current + page_size ;
|
|
|
b9d01e |
+ !(attrs & GRUB_MEM_ATTR_R);
|
|
|
b9d01e |
+ stack_end += page_size)
|
|
|
b9d01e |
+ {
|
|
|
b9d01e |
+ err = grub_get_mem_attrs (stack_current, page_size, &attrs);
|
|
|
b9d01e |
+ if (err)
|
|
|
b9d01e |
+ {
|
|
|
b9d01e |
+ grub_dprintf ("nx",
|
|
|
b9d01e |
+ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n",
|
|
|
b9d01e |
+ stack_current, err);
|
|
|
b9d01e |
+ grub_error_pop ();
|
|
|
b9d01e |
+ break;
|
|
|
b9d01e |
+ }
|
|
|
b9d01e |
+ }
|
|
|
b9d01e |
+ if (stack_end > stack_current)
|
|
|
b9d01e |
+ {
|
|
|
b9d01e |
+ grub_stack_addr = stack_current;
|
|
|
b9d01e |
+ grub_stack_size = stack_end - stack_current;
|
|
|
b9d01e |
+ grub_dprintf ("nx",
|
|
|
b9d01e |
+ "detected stack from 0x%"PRIxGRUB_ADDR" to 0x%"PRIxGRUB_ADDR"\n",
|
|
|
b9d01e |
+ grub_stack_addr, grub_stack_addr + grub_stack_size - 1);
|
|
|
b9d01e |
+ }
|
|
|
b9d01e |
+}
|
|
|
b9d01e |
+
|
|
|
b9d01e |
void
|
|
|
b9d01e |
grub_efi_mm_init (void)
|
|
|
b9d01e |
{
|
|
|
b9d01e |
@@ -615,6 +691,8 @@ grub_efi_mm_init (void)
|
|
|
b9d01e |
grub_efi_uint64_t required_pages;
|
|
|
b9d01e |
int mm_status;
|
|
|
b9d01e |
|
|
|
b9d01e |
+ grub_nx_init ();
|
|
|
b9d01e |
+
|
|
|
b9d01e |
/* Prepare a memory region to store two memory maps. */
|
|
|
b9d01e |
memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
|
|
|
b9d01e |
if (! memory_map)
|
|
|
b9d01e |
diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
|
|
|
b9d01e |
index 24ab0f0074..37f5d0c7eb 100644
|
|
|
b9d01e |
--- a/grub-core/loader/arm64/linux.c
|
|
|
b9d01e |
+++ b/grub-core/loader/arm64/linux.c
|
|
|
b9d01e |
@@ -191,7 +191,8 @@ free_params (void)
|
|
|
b9d01e |
}
|
|
|
b9d01e |
|
|
|
b9d01e |
grub_err_t
|
|
|
b9d01e |
-grub_armxx_efi_linux_boot_image (grub_addr_t addr, char *args)
|
|
|
b9d01e |
+grub_armxx_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args,
|
|
|
b9d01e |
+ int nx_supported)
|
|
|
b9d01e |
{
|
|
|
b9d01e |
grub_err_t retval;
|
|
|
b9d01e |
|
|
|
b9d01e |
@@ -201,7 +202,8 @@ grub_armxx_efi_linux_boot_image (grub_addr_t addr, char *args)
|
|
|
b9d01e |
|
|
|
b9d01e |
grub_dprintf ("linux", "linux command line: '%s'\n", args);
|
|
|
b9d01e |
|
|
|
b9d01e |
- retval = grub_efi_linux_boot ((char *)addr, handover_offset, (void *)addr);
|
|
|
b9d01e |
+ retval = grub_efi_linux_boot (addr, size, handover_offset,
|
|
|
b9d01e |
+ (void *)addr, nx_supported);
|
|
|
b9d01e |
|
|
|
b9d01e |
/* Never reached... */
|
|
|
b9d01e |
free_params();
|
|
|
b9d01e |
@@ -211,7 +213,10 @@ grub_armxx_efi_linux_boot_image (grub_addr_t addr, char *args)
|
|
|
b9d01e |
static grub_err_t
|
|
|
b9d01e |
grub_linux_boot (void)
|
|
|
b9d01e |
{
|
|
|
b9d01e |
- return grub_armxx_efi_linux_boot_image((grub_addr_t)kernel_addr, linux_args);
|
|
|
b9d01e |
+ return grub_armxx_efi_linux_boot_image((grub_addr_t)kernel_addr,
|
|
|
b9d01e |
+ (grub_size_t)kernel_size,
|
|
|
b9d01e |
+ linux_args,
|
|
|
b9d01e |
+ 0);
|
|
|
b9d01e |
}
|
|
|
b9d01e |
|
|
|
b9d01e |
static grub_err_t
|
|
|
b9d01e |
@@ -340,6 +345,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|
|
b9d01e |
struct grub_armxx_linux_pe_header *pe;
|
|
|
b9d01e |
int rc;
|
|
|
b9d01e |
grub_err_t err;
|
|
|
b9d01e |
+ int nx_supported = 1;
|
|
|
b9d01e |
|
|
|
b9d01e |
grub_dl_ref (my_mod);
|
|
|
b9d01e |
|
|
|
b9d01e |
@@ -395,6 +401,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|
|
b9d01e |
}
|
|
|
b9d01e |
}
|
|
|
b9d01e |
|
|
|
b9d01e |
+ err = grub_efi_check_nx_image_support((grub_addr_t) kernel_addr, kernel_size, &nx_supported);
|
|
|
b9d01e |
+ if (err != GRUB_ERR_NONE)
|
|
|
b9d01e |
+ goto fail;
|
|
|
b9d01e |
+
|
|
|
b9d01e |
pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset);
|
|
|
b9d01e |
handover_offset = pe->opt.entry_addr;
|
|
|
b9d01e |
|
|
|
b9d01e |
diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c
|
|
|
b9d01e |
index 1a337866f0..1fd1bbb4bd 100644
|
|
|
b9d01e |
--- a/grub-core/loader/arm64/xen_boot.c
|
|
|
b9d01e |
+++ b/grub-core/loader/arm64/xen_boot.c
|
|
|
b9d01e |
@@ -266,7 +266,9 @@ xen_boot (void)
|
|
|
b9d01e |
return err;
|
|
|
b9d01e |
|
|
|
b9d01e |
return grub_armxx_efi_linux_boot_image (xen_hypervisor->start,
|
|
|
b9d01e |
- xen_hypervisor->cmdline);
|
|
|
b9d01e |
+ xen_hypervisor->size,
|
|
|
b9d01e |
+ xen_hypervisor->cmdline,
|
|
|
b9d01e |
+ 0);
|
|
|
b9d01e |
}
|
|
|
b9d01e |
|
|
|
b9d01e |
static void
|
|
|
b9d01e |
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
|
|
|
b9d01e |
index 8e658f713e..b72e6bd5e3 100644
|
|
|
b9d01e |
--- a/grub-core/loader/efi/chainloader.c
|
|
|
b9d01e |
+++ b/grub-core/loader/efi/chainloader.c
|
|
|
b9d01e |
@@ -1055,6 +1055,17 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
|
|
|
b9d01e |
goto fail;
|
|
|
b9d01e |
}
|
|
|
b9d01e |
|
|
|
b9d01e |
+ /*
|
|
|
b9d01e |
+ * The OS kernel is going to set its own permissions when it takes over
|
|
|
b9d01e |
+ * paging a few million instructions from now, and load_image() will set up
|
|
|
b9d01e |
+ * anything that's needed based on the section headers, so there's no point
|
|
|
b9d01e |
+ * in doing anything but clearing the protection bits here.
|
|
|
b9d01e |
+ */
|
|
|
b9d01e |
+ grub_dprintf("nx", "setting attributes for %p (%lu bytes) to %llx\n",
|
|
|
b9d01e |
+ (void *)(grub_addr_t)address, fsize, 0llu);
|
|
|
b9d01e |
+ grub_update_mem_attrs (address, fsize,
|
|
|
b9d01e |
+ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X, 0);
|
|
|
b9d01e |
+
|
|
|
b9d01e |
#if defined (__i386__) || defined (__x86_64__)
|
|
|
b9d01e |
if (fsize >= (grub_ssize_t) sizeof (struct grub_macho_fat_header))
|
|
|
b9d01e |
{
|
|
|
b9d01e |
diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
|
|
|
b9d01e |
index 927d89a90d..421502bd25 100644
|
|
|
b9d01e |
--- a/grub-core/loader/efi/linux.c
|
|
|
b9d01e |
+++ b/grub-core/loader/efi/linux.c
|
|
|
b9d01e |
@@ -66,16 +66,125 @@ grub_linuxefi_secure_validate (void *data, grub_uint32_t size)
|
|
|
b9d01e |
|
|
|
b9d01e |
#pragma GCC diagnostic push
|
|
|
b9d01e |
#pragma GCC diagnostic ignored "-Wcast-align"
|
|
|
b9d01e |
+#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+grub_err_t
|
|
|
b9d01e |
+grub_efi_check_nx_image_support (grub_addr_t kernel_addr,
|
|
|
b9d01e |
+ grub_size_t kernel_size,
|
|
|
b9d01e |
+ int *nx_supported)
|
|
|
b9d01e |
+{
|
|
|
b9d01e |
+ struct grub_dos_header *doshdr;
|
|
|
b9d01e |
+ grub_size_t sz = sizeof (*doshdr);
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ struct grub_pe32_header_32 *pe32;
|
|
|
b9d01e |
+ struct grub_pe32_header_64 *pe64;
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ int image_is_compatible = 0;
|
|
|
b9d01e |
+ int is_64_bit;
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ if (kernel_size < sz)
|
|
|
b9d01e |
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small"));
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ doshdr = (void *)kernel_addr;
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ if ((doshdr->magic & 0xffff) != GRUB_DOS_MAGIC)
|
|
|
b9d01e |
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel DOS magic is invalid"));
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ sz = doshdr->lfanew + sizeof (*pe32);
|
|
|
b9d01e |
+ if (kernel_size < sz)
|
|
|
b9d01e |
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small"));
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ pe32 = (struct grub_pe32_header_32 *)(kernel_addr + doshdr->lfanew);
|
|
|
b9d01e |
+ pe64 = (struct grub_pe32_header_64 *)pe32;
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ if (grub_memcmp (pe32->signature, GRUB_PE32_SIGNATURE,
|
|
|
b9d01e |
+ GRUB_PE32_SIGNATURE_SIZE) != 0)
|
|
|
b9d01e |
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel PE magic is invalid"));
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ switch (pe32->coff_header.machine)
|
|
|
b9d01e |
+ {
|
|
|
b9d01e |
+ case GRUB_PE32_MACHINE_ARMTHUMB_MIXED:
|
|
|
b9d01e |
+ case GRUB_PE32_MACHINE_I386:
|
|
|
b9d01e |
+ is_64_bit = 0;
|
|
|
b9d01e |
+ break;
|
|
|
b9d01e |
+ case GRUB_PE32_MACHINE_ARM64:
|
|
|
b9d01e |
+ case GRUB_PE32_MACHINE_IA64:
|
|
|
b9d01e |
+ case GRUB_PE32_MACHINE_X86_64:
|
|
|
b9d01e |
+ is_64_bit = 1;
|
|
|
b9d01e |
+ break;
|
|
|
b9d01e |
+ default:
|
|
|
b9d01e |
+ return grub_error (GRUB_ERR_BAD_OS, N_("PE machine type 0x%04hx unknown"),
|
|
|
b9d01e |
+ pe32->coff_header.machine);
|
|
|
b9d01e |
+ }
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ if (is_64_bit)
|
|
|
b9d01e |
+ {
|
|
|
b9d01e |
+ sz = doshdr->lfanew + sizeof (*pe64);
|
|
|
b9d01e |
+ if (kernel_size < sz)
|
|
|
b9d01e |
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small"));
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ if (pe64->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT)
|
|
|
b9d01e |
+ image_is_compatible = 1;
|
|
|
b9d01e |
+ }
|
|
|
b9d01e |
+ else
|
|
|
b9d01e |
+ {
|
|
|
b9d01e |
+ if (pe32->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT)
|
|
|
b9d01e |
+ image_is_compatible = 1;
|
|
|
b9d01e |
+ }
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ *nx_supported = image_is_compatible;
|
|
|
b9d01e |
+ return GRUB_ERR_NONE;
|
|
|
b9d01e |
+}
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+grub_err_t
|
|
|
b9d01e |
+grub_efi_check_nx_required (int *nx_required)
|
|
|
b9d01e |
+{
|
|
|
b9d01e |
+ grub_efi_status_t status;
|
|
|
b9d01e |
+ grub_efi_guid_t guid = GRUB_EFI_SHIM_LOCK_GUID;
|
|
|
b9d01e |
+ grub_size_t mok_policy_sz = 0;
|
|
|
b9d01e |
+ char *mok_policy = NULL;
|
|
|
b9d01e |
+ grub_uint32_t mok_policy_attrs = 0;
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ status = grub_efi_get_variable_with_attributes ("MokPolicy", &guid,
|
|
|
b9d01e |
+ &mok_policy_sz,
|
|
|
b9d01e |
+ (void **)&mok_policy,
|
|
|
b9d01e |
+ &mok_policy_attrs);
|
|
|
b9d01e |
+ if (status == GRUB_EFI_NOT_FOUND ||
|
|
|
b9d01e |
+ mok_policy_sz == 0 ||
|
|
|
b9d01e |
+ mok_policy == NULL)
|
|
|
b9d01e |
+ {
|
|
|
b9d01e |
+ *nx_required = 0;
|
|
|
b9d01e |
+ return GRUB_ERR_NONE;
|
|
|
b9d01e |
+ }
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ *nx_required = 0;
|
|
|
b9d01e |
+ if (mok_policy_sz < 1 ||
|
|
|
b9d01e |
+ mok_policy_attrs != (GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
|
|
b9d01e |
+ GRUB_EFI_VARIABLE_RUNTIME_ACCESS) ||
|
|
|
b9d01e |
+ (mok_policy[mok_policy_sz-1] & GRUB_MOK_POLICY_NX_REQUIRED))
|
|
|
b9d01e |
+ *nx_required = 1;
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ return GRUB_ERR_NONE;
|
|
|
b9d01e |
+}
|
|
|
b9d01e |
|
|
|
b9d01e |
typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *);
|
|
|
b9d01e |
|
|
|
b9d01e |
grub_err_t
|
|
|
b9d01e |
-grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset,
|
|
|
b9d01e |
- void *kernel_params)
|
|
|
b9d01e |
+grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size,
|
|
|
b9d01e |
+ grub_off_t handover_offset, void *kernel_params,
|
|
|
b9d01e |
+ int nx_supported)
|
|
|
b9d01e |
{
|
|
|
b9d01e |
grub_efi_loaded_image_t *loaded_image = NULL;
|
|
|
b9d01e |
handover_func hf;
|
|
|
b9d01e |
int offset = 0;
|
|
|
b9d01e |
+ grub_uint64_t stack_set_attrs = GRUB_MEM_ATTR_R |
|
|
|
b9d01e |
+ GRUB_MEM_ATTR_W |
|
|
|
b9d01e |
+ GRUB_MEM_ATTR_X;
|
|
|
b9d01e |
+ grub_uint64_t stack_clear_attrs = 0;
|
|
|
b9d01e |
+ grub_uint64_t kernel_set_attrs = stack_set_attrs;
|
|
|
b9d01e |
+ grub_uint64_t kernel_clear_attrs = stack_clear_attrs;
|
|
|
b9d01e |
+ grub_uint64_t attrs;
|
|
|
b9d01e |
+ int nx_required = 0;
|
|
|
b9d01e |
|
|
|
b9d01e |
#ifdef __x86_64__
|
|
|
b9d01e |
offset = 512;
|
|
|
b9d01e |
@@ -88,12 +197,57 @@ grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset,
|
|
|
b9d01e |
*/
|
|
|
b9d01e |
loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
|
|
|
b9d01e |
if (loaded_image)
|
|
|
b9d01e |
- loaded_image->image_base = kernel_addr;
|
|
|
b9d01e |
+ loaded_image->image_base = (void *)kernel_addr;
|
|
|
b9d01e |
else
|
|
|
b9d01e |
grub_dprintf ("linux", "Loaded Image base address could not be set\n");
|
|
|
b9d01e |
|
|
|
b9d01e |
grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n",
|
|
|
b9d01e |
- kernel_addr, (void *)(grub_efi_uintn_t)handover_offset, kernel_params);
|
|
|
b9d01e |
+ (void *)kernel_addr, (void *)handover_offset, kernel_params);
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ if (nx_required && !nx_supported)
|
|
|
b9d01e |
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel does not support NX loading required by policy"));
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ if (nx_supported)
|
|
|
b9d01e |
+ {
|
|
|
b9d01e |
+ kernel_set_attrs &= ~GRUB_MEM_ATTR_W;
|
|
|
b9d01e |
+ kernel_clear_attrs |= GRUB_MEM_ATTR_W;
|
|
|
b9d01e |
+ stack_set_attrs &= ~GRUB_MEM_ATTR_X;
|
|
|
b9d01e |
+ stack_clear_attrs |= GRUB_MEM_ATTR_X;
|
|
|
b9d01e |
+ }
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ grub_dprintf ("nx", "Setting attributes for 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to r%cx\n",
|
|
|
b9d01e |
+ kernel_addr, kernel_addr + kernel_size - 1,
|
|
|
b9d01e |
+ (kernel_set_attrs & GRUB_MEM_ATTR_W) ? 'w' : '-');
|
|
|
b9d01e |
+ grub_update_mem_attrs (kernel_addr, kernel_size,
|
|
|
b9d01e |
+ kernel_set_attrs, kernel_clear_attrs);
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ grub_get_mem_attrs (kernel_addr, 4096, &attrs);
|
|
|
b9d01e |
+ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n",
|
|
|
b9d01e |
+ (grub_addr_t)kernel_addr,
|
|
|
b9d01e |
+ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-",
|
|
|
b9d01e |
+ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-",
|
|
|
b9d01e |
+ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-");
|
|
|
b9d01e |
+ if (grub_stack_addr != (grub_addr_t)-1ll)
|
|
|
b9d01e |
+ {
|
|
|
b9d01e |
+ grub_dprintf ("nx", "Setting attributes for stack at 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to rw%c\n",
|
|
|
b9d01e |
+ grub_stack_addr, grub_stack_addr + grub_stack_size - 1,
|
|
|
b9d01e |
+ (stack_set_attrs & GRUB_MEM_ATTR_X) ? 'x' : '-');
|
|
|
b9d01e |
+ grub_update_mem_attrs (grub_stack_addr, grub_stack_size,
|
|
|
b9d01e |
+ stack_set_attrs, stack_clear_attrs);
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+ grub_get_mem_attrs (grub_stack_addr, 4096, &attrs);
|
|
|
b9d01e |
+ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n",
|
|
|
b9d01e |
+ grub_stack_addr,
|
|
|
b9d01e |
+ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-",
|
|
|
b9d01e |
+ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-",
|
|
|
b9d01e |
+ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-");
|
|
|
b9d01e |
+ }
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+#if defined(__i386__) || defined(__x86_64__)
|
|
|
b9d01e |
+ asm volatile ("cli");
|
|
|
b9d01e |
+#endif
|
|
|
b9d01e |
+
|
|
|
b9d01e |
hf = (handover_func)((char *)kernel_addr + handover_offset + offset);
|
|
|
b9d01e |
grub_dprintf ("linux", "handover_func() = %p\n", hf);
|
|
|
b9d01e |
hf (grub_efi_image_handle, grub_efi_system_table, kernel_params);
|
|
|
b9d01e |
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
|
|
|
b9d01e |
index 3d4069e4c6..d80d6ec312 100644
|
|
|
b9d01e |
--- a/grub-core/loader/i386/efi/linux.c
|
|
|
b9d01e |
+++ b/grub-core/loader/i386/efi/linux.c
|
|
|
b9d01e |
@@ -44,7 +44,7 @@ struct grub_linuxefi_context {
|
|
|
b9d01e |
grub_uint32_t handover_offset;
|
|
|
b9d01e |
struct linux_kernel_params *params;
|
|
|
b9d01e |
char *cmdline;
|
|
|
b9d01e |
-
|
|
|
b9d01e |
+ int nx_supported;
|
|
|
b9d01e |
void *initrd_mem;
|
|
|
b9d01e |
};
|
|
|
b9d01e |
|
|
|
b9d01e |
@@ -110,13 +110,19 @@ kernel_alloc(grub_efi_uintn_t size,
|
|
|
b9d01e |
pages = BYTES_TO_PAGES(size);
|
|
|
b9d01e |
grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n",
|
|
|
b9d01e |
pages, (void *)max);
|
|
|
b9d01e |
+ size = pages * GRUB_EFI_PAGE_SIZE;
|
|
|
b9d01e |
|
|
|
b9d01e |
prev_max = max;
|
|
|
b9d01e |
addr = grub_efi_allocate_pages_real (max, pages,
|
|
|
b9d01e |
max_addresses[i].alloc_type,
|
|
|
b9d01e |
memtype);
|
|
|
b9d01e |
if (addr)
|
|
|
b9d01e |
- grub_dprintf ("linux", "Allocated at %p\n", addr);
|
|
|
b9d01e |
+ {
|
|
|
b9d01e |
+ grub_dprintf ("linux", "Allocated at %p\n", addr);
|
|
|
b9d01e |
+ grub_update_mem_attrs ((grub_addr_t)addr, size,
|
|
|
b9d01e |
+ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W,
|
|
|
b9d01e |
+ GRUB_MEM_ATTR_X);
|
|
|
b9d01e |
+ }
|
|
|
b9d01e |
}
|
|
|
b9d01e |
|
|
|
b9d01e |
while (grub_error_pop ())
|
|
|
b9d01e |
@@ -137,9 +143,11 @@ grub_linuxefi_boot (void *data)
|
|
|
b9d01e |
|
|
|
b9d01e |
asm volatile ("cli");
|
|
|
b9d01e |
|
|
|
b9d01e |
- return grub_efi_linux_boot ((char *)context->kernel_mem,
|
|
|
b9d01e |
+ return grub_efi_linux_boot ((grub_addr_t)context->kernel_mem,
|
|
|
b9d01e |
+ context->kernel_size,
|
|
|
b9d01e |
context->handover_offset,
|
|
|
b9d01e |
- context->params);
|
|
|
b9d01e |
+ context->params,
|
|
|
b9d01e |
+ context->nx_supported);
|
|
|
b9d01e |
}
|
|
|
b9d01e |
|
|
|
b9d01e |
static grub_err_t
|
|
|
b9d01e |
@@ -308,7 +316,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|
|
b9d01e |
grub_uint32_t handover_offset;
|
|
|
b9d01e |
struct linux_kernel_params *params = 0;
|
|
|
b9d01e |
char *cmdline = 0;
|
|
|
b9d01e |
+ int nx_supported = 1;
|
|
|
b9d01e |
struct grub_linuxefi_context *context = 0;
|
|
|
b9d01e |
+ grub_err_t err;
|
|
|
b9d01e |
|
|
|
b9d01e |
grub_dl_ref (my_mod);
|
|
|
b9d01e |
|
|
|
b9d01e |
@@ -352,6 +362,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|
|
b9d01e |
}
|
|
|
b9d01e |
}
|
|
|
b9d01e |
|
|
|
b9d01e |
+ err = grub_efi_check_nx_image_support ((grub_addr_t)kernel, filelen,
|
|
|
b9d01e |
+ &nx_supported);
|
|
|
b9d01e |
+ if (err != GRUB_ERR_NONE)
|
|
|
b9d01e |
+ return err;
|
|
|
b9d01e |
+ grub_dprintf ("linux", "nx is%s supported by this kernel\n",
|
|
|
b9d01e |
+ nx_supported ? "" : " not");
|
|
|
b9d01e |
+
|
|
|
b9d01e |
lh = (struct linux_i386_kernel_header *)kernel;
|
|
|
b9d01e |
grub_dprintf ("linux", "original lh is at %p\n", kernel);
|
|
|
b9d01e |
|
|
|
b9d01e |
@@ -515,6 +532,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|
|
b9d01e |
context->handover_offset = handover_offset;
|
|
|
b9d01e |
context->params = params;
|
|
|
b9d01e |
context->cmdline = cmdline;
|
|
|
b9d01e |
+ context->nx_supported = nx_supported;
|
|
|
b9d01e |
|
|
|
b9d01e |
grub_loader_set_ex (grub_linuxefi_boot, grub_linuxefi_unload, context, 0);
|
|
|
b9d01e |
|
|
|
b9d01e |
diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
|
|
|
b9d01e |
index ef8fcb9e1b..c160ddb0ea 100644
|
|
|
b9d01e |
--- a/grub-core/loader/i386/linux.c
|
|
|
b9d01e |
+++ b/grub-core/loader/i386/linux.c
|
|
|
b9d01e |
@@ -831,6 +831,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|
|
b9d01e |
grub_memset (&linux_params, 0, sizeof (linux_params));
|
|
|
b9d01e |
grub_memcpy (&linux_params.setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1);
|
|
|
b9d01e |
|
|
|
b9d01e |
+ grub_dprintf("efi", "setting attributes for %p (%zu bytes) to +rw-x\n",
|
|
|
b9d01e |
+ &linux_params, sizeof (lh) + len);
|
|
|
b9d01e |
+ grub_update_mem_attrs ((grub_addr_t)&linux_params, sizeof (lh) + len,
|
|
|
b9d01e |
+ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W, GRUB_MEM_ATTR_X);
|
|
|
b9d01e |
+
|
|
|
b9d01e |
linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR;
|
|
|
b9d01e |
linux_params.kernel_alignment = (1 << align);
|
|
|
b9d01e |
linux_params.ps_mouse = linux_params.padding10 = 0;
|
|
|
b9d01e |
diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
|
|
|
b9d01e |
index a635bcb0a9..8ca8c38f9a 100644
|
|
|
b9d01e |
--- a/include/grub/efi/efi.h
|
|
|
b9d01e |
+++ b/include/grub/efi/efi.h
|
|
|
b9d01e |
@@ -135,12 +135,16 @@ extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd,
|
|
|
b9d01e |
char **device,
|
|
|
b9d01e |
char **path);
|
|
|
b9d01e |
|
|
|
b9d01e |
+extern grub_addr_t EXPORT_VAR(grub_stack_addr);
|
|
|
b9d01e |
+extern grub_size_t EXPORT_VAR(grub_stack_size);
|
|
|
b9d01e |
+
|
|
|
b9d01e |
#if defined(__arm__) || defined(__aarch64__)
|
|
|
b9d01e |
void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void);
|
|
|
b9d01e |
grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *);
|
|
|
b9d01e |
#include <grub/cpu/linux.h>
|
|
|
b9d01e |
grub_err_t grub_armxx_efi_linux_check_image(struct linux_armxx_kernel_header *lh);
|
|
|
b9d01e |
-grub_err_t grub_armxx_efi_linux_boot_image(grub_addr_t addr, char *args);
|
|
|
b9d01e |
+grub_err_t grub_armxx_efi_linux_boot_image(grub_addr_t addr, grub_size_t size,
|
|
|
b9d01e |
+ char *args, int nx_enabled);
|
|
|
b9d01e |
#endif
|
|
|
b9d01e |
|
|
|
b9d01e |
grub_addr_t grub_efi_section_addr (const char *section);
|
|
|
b9d01e |
diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h
|
|
|
b9d01e |
index 0033d9305a..8130b19590 100644
|
|
|
b9d01e |
--- a/include/grub/efi/linux.h
|
|
|
b9d01e |
+++ b/include/grub/efi/linux.h
|
|
|
b9d01e |
@@ -22,10 +22,23 @@
|
|
|
b9d01e |
#include <grub/err.h>
|
|
|
b9d01e |
#include <grub/symbol.h>
|
|
|
b9d01e |
|
|
|
b9d01e |
+#define GRUB_MOK_POLICY_NX_REQUIRED 0x1
|
|
|
b9d01e |
+
|
|
|
b9d01e |
int
|
|
|
b9d01e |
EXPORT_FUNC(grub_linuxefi_secure_validate) (void *data, grub_uint32_t size);
|
|
|
b9d01e |
+
|
|
|
b9d01e |
grub_err_t
|
|
|
b9d01e |
-EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset,
|
|
|
b9d01e |
- void *kernel_param);
|
|
|
b9d01e |
+EXPORT_FUNC(grub_efi_linux_boot) (grub_addr_t kernel_address,
|
|
|
b9d01e |
+ grub_size_t kernel_size,
|
|
|
b9d01e |
+ grub_off_t handover_offset,
|
|
|
b9d01e |
+ void *kernel_param, int nx_enabled);
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+grub_err_t
|
|
|
b9d01e |
+EXPORT_FUNC(grub_efi_check_nx_image_support) (grub_addr_t kernel_addr,
|
|
|
b9d01e |
+ grub_size_t kernel_size,
|
|
|
b9d01e |
+ int *nx_supported);
|
|
|
b9d01e |
+
|
|
|
b9d01e |
+grub_err_t
|
|
|
b9d01e |
+EXPORT_FUNC(grub_efi_check_nx_required) (int *nx_required);
|
|
|
b9d01e |
|
|
|
b9d01e |
#endif /* ! GRUB_EFI_LINUX_HEADER */
|
|
|
b9d01e |
diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
|
|
|
b9d01e |
index 2241f6317b..45c9f8b756 100644
|
|
|
b9d01e |
--- a/include/grub/efi/pe32.h
|
|
|
b9d01e |
+++ b/include/grub/efi/pe32.h
|
|
|
b9d01e |
@@ -172,6 +172,8 @@ struct grub_pe32_optional_header
|
|
|
b9d01e |
struct grub_pe32_data_directory reserved_entry;
|
|
|
b9d01e |
};
|
|
|
b9d01e |
|
|
|
b9d01e |
+#define GRUB_PE32_NX_COMPAT 0x0100
|
|
|
b9d01e |
+
|
|
|
b9d01e |
struct grub_pe64_optional_header
|
|
|
b9d01e |
{
|
|
|
b9d01e |
grub_uint16_t magic;
|