grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 06/15] nx: add memory attribute get/set API


From: Mate Kukri
Subject: [PATCH 06/15] nx: add memory attribute get/set API
Date: Fri, 24 May 2024 12:03:53 +0100

From: Peter Jones <pjones@redhat.com>

For NX, we need to set the page access permission attributes for write
and execute permissions.

This patch adds two new primitives, grub_set_mem_attrs() and
grub_clear_mem_attrs(), and associated constant definitions, to be used
for that purpose.

For most platforms, it adds a dummy implementation that returns
GRUB_ERR_NONE.  On EFI platforms, it adds a common helper function,
grub_efi_status_to_err(), which translates EFI error codes to grub error
codes, adds headers for the EFI Memory Attribute Protocol (still pending
standardization), and an implementation of the grub nx primitives using
it.

Signed-off-by: Peter Jones <pjones@redhat.com>
[rharwood: add pjones's none/nyi fixup]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
(cherry picked from commit 45bfb1cc8316096a5ce1e58850ce5f8a6e0e100c)
Signed-off-by: Jan Setje-Eilers <jan.setjeeilers@oracle.com>
Signed-off-by: Mate Kukri <mate.kukri@canonical.com>

Conflicts:
        grub-core/kern/efi/mm.c (fixup)
        include/grub/efi/api.h  (fixup)
---
 grub-core/kern/efi/efi.c |  36 +++++++++++
 grub-core/kern/efi/mm.c  | 128 +++++++++++++++++++++++++++++++++++++++
 include/grub/efi/api.h   |  25 ++++++++
 include/grub/efi/efi.h   |   2 +
 include/grub/mm.h        |  32 ++++++++++
 5 files changed, 223 insertions(+)

diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
index b93ae3aba..f34c1ef54 100644
--- a/grub-core/kern/efi/efi.c
+++ b/grub-core/kern/efi/efi.c
@@ -1049,3 +1049,39 @@ grub_efi_find_configuration_table (const grub_guid_t 
*target_guid)
 
   return 0;
 }
+
+grub_err_t
+grub_efi_status_to_err (grub_efi_status_t status)
+{
+  grub_err_t err;
+  switch (status)
+    {
+    case GRUB_EFI_SUCCESS:
+      err = GRUB_ERR_NONE;
+      break;
+    case GRUB_EFI_INVALID_PARAMETER:
+    default:
+      err = GRUB_ERR_BAD_ARGUMENT;
+      break;
+    case GRUB_EFI_OUT_OF_RESOURCES:
+      err = GRUB_ERR_OUT_OF_MEMORY;
+      break;
+    case GRUB_EFI_DEVICE_ERROR:
+      err = GRUB_ERR_IO;
+      break;
+    case GRUB_EFI_WRITE_PROTECTED:
+      err = GRUB_ERR_WRITE_ERROR;
+      break;
+    case GRUB_EFI_SECURITY_VIOLATION:
+      err = GRUB_ERR_ACCESS_DENIED;
+      break;
+    case GRUB_EFI_NOT_FOUND:
+      err = GRUB_ERR_FILE_NOT_FOUND;
+      break;
+    case GRUB_EFI_ABORTED:
+      err = GRUB_ERR_WAIT;
+      break;
+    }
+
+  return err;
+}
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
index 6a6fba891..46f2266e1 100644
--- a/grub-core/kern/efi/mm.c
+++ b/grub-core/kern/efi/mm.c
@@ -687,3 +687,131 @@ grub_efi_get_ram_base(grub_addr_t *base_addr)
   return GRUB_ERR_NONE;
 }
 #endif
+
+static inline grub_uint64_t
+grub_mem_attrs_to_uefi_mem_attrs (grub_uint64_t attrs)
+{
+  grub_uint64_t ret = GRUB_EFI_MEMORY_RP |
+                     GRUB_EFI_MEMORY_RO |
+                     GRUB_EFI_MEMORY_XP;
+
+  if (attrs & GRUB_MEM_ATTR_R)
+    ret &= ~GRUB_EFI_MEMORY_RP;
+
+  if (attrs & GRUB_MEM_ATTR_W)
+    ret &= ~GRUB_EFI_MEMORY_RO;
+
+  if (attrs & GRUB_MEM_ATTR_X)
+    ret &= ~GRUB_EFI_MEMORY_XP;
+
+  return ret;
+}
+
+static inline grub_uint64_t
+uefi_mem_attrs_to_grub_mem_attrs (grub_uint64_t attrs)
+{
+  grub_uint64_t ret = GRUB_MEM_ATTR_R |
+                     GRUB_MEM_ATTR_W |
+                     GRUB_MEM_ATTR_X;
+
+  if (attrs & GRUB_EFI_MEMORY_RP)
+    ret &= ~GRUB_MEM_ATTR_R;
+
+  if (attrs & GRUB_EFI_MEMORY_RO)
+    ret &= ~GRUB_MEM_ATTR_W;
+
+  if (attrs & GRUB_EFI_MEMORY_XP)
+    ret &= ~GRUB_MEM_ATTR_X;
+
+  return ret;
+}
+
+grub_err_t
+grub_get_mem_attrs (grub_addr_t addr, grub_size_t size, grub_uint64_t *attrs)
+{
+  grub_efi_memory_attribute_protocol_t *proto;
+  grub_efi_physical_address_t physaddr = addr;
+  grub_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
+  grub_efi_status_t efi_status;
+
+  proto = grub_efi_locate_protocol (&protocol_guid, 0);
+  if (!proto)
+    return GRUB_ERR_NOT_IMPLEMENTED_YET;
+
+  if (physaddr & 0xfff || size & 0xfff || size == 0 || attrs == NULL)
+    {
+      grub_dprintf ("nx", "%s called on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" 
and attrs %p\n",
+                   __func__, physaddr, physaddr+size-1, attrs);
+      return 0;
+    }
+
+  efi_status = proto->get_memory_attributes(proto, physaddr, size, attrs);
+  *attrs = uefi_mem_attrs_to_grub_mem_attrs (*attrs);
+
+  return grub_efi_status_to_err (efi_status);
+}
+
+grub_err_t
+grub_update_mem_attrs (grub_addr_t addr, grub_size_t size,
+                      grub_uint64_t set_attrs, grub_uint64_t clear_attrs)
+{
+  grub_efi_memory_attribute_protocol_t *proto;
+  grub_efi_physical_address_t physaddr = addr;
+  grub_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
+  grub_efi_status_t efi_status = GRUB_EFI_SUCCESS;
+  grub_uint64_t before = 0, after = 0, uefi_set_attrs, uefi_clear_attrs;
+  grub_err_t err;
+
+  proto = grub_efi_locate_protocol (&protocol_guid, 0);
+  if (!proto)
+    return GRUB_ERR_NONE;
+
+  err = grub_get_mem_attrs (addr, size, &before);
+  if (err)
+    grub_dprintf ("nx", "grub_get_mem_attrs(0x%"PRIxGRUB_ADDR", 
%"PRIuGRUB_SIZE", %p) -> 0x%x\n",
+                 addr, size, &before, err);
+
+  if (physaddr & 0xfff || size & 0xfff || size == 0)
+    {
+      grub_dprintf ("nx", "%s called on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" 
+%s%s%s -%s%s%s\n",
+                   __func__, physaddr, physaddr + size - 1,
+                   (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
+                   (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
+                   (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
+                   (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
+                   (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
+                   (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "");
+      return 0;
+    }
+
+  uefi_set_attrs = grub_mem_attrs_to_uefi_mem_attrs (set_attrs);
+  grub_dprintf ("nx", "translating set_attrs from 0x%lx to 0x%lx\n", 
set_attrs, uefi_set_attrs);
+  uefi_clear_attrs = grub_mem_attrs_to_uefi_mem_attrs (clear_attrs);
+  grub_dprintf ("nx", "translating clear_attrs from 0x%lx to 0x%lx\n", 
clear_attrs, uefi_clear_attrs);
+  if (uefi_set_attrs)
+    efi_status = proto->set_memory_attributes(proto, physaddr, size, 
uefi_set_attrs);
+  if (efi_status == GRUB_EFI_SUCCESS && uefi_clear_attrs)
+    efi_status = proto->clear_memory_attributes(proto, physaddr, size, 
uefi_clear_attrs);
+
+  err = grub_get_mem_attrs (addr, size, &after);
+  if (err)
+    grub_dprintf ("nx", "grub_get_mem_attrs(0x%"PRIxGRUB_ADDR", 
%"PRIuGRUB_SIZE", %p) -> 0x%x\n",
+                 addr, size, &after, err);
+
+  grub_dprintf ("nx", "set +%s%s%s -%s%s%s on 
0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" before:%c%c%c after:%c%c%c\n",
+               (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
+               (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
+               (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
+               (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
+               (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
+               (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
+               addr, addr + size - 1,
+               (before & GRUB_MEM_ATTR_R) ? 'r' : '-',
+               (before & GRUB_MEM_ATTR_W) ? 'w' : '-',
+               (before & GRUB_MEM_ATTR_X) ? 'x' : '-',
+               (after & GRUB_MEM_ATTR_R) ? 'r' : '-',
+               (after & GRUB_MEM_ATTR_W) ? 'w' : '-',
+               (after & GRUB_MEM_ATTR_X) ? 'x' : '-');
+
+  return grub_efi_status_to_err (efi_status);
+}
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index d44d00ad7..b686e8afe 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -379,6 +379,11 @@
     {0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } \
   }
 
+#define GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID \
+  { 0xf4560cf6, 0x40ec, 0x4b4a, \
+    { 0xa1, 0x92, 0xbf, 0x1d, 0x57, 0xd0, 0xb1, 0x89 } \
+  }
+
 struct grub_efi_sal_system_table
 {
   grub_uint32_t signature;
@@ -1815,4 +1820,24 @@ struct initrd_media_device_path {
 } GRUB_PACKED;
 typedef struct initrd_media_device_path initrd_media_device_path_t;
 
+struct grub_efi_memory_attribute_protocol
+{
+  grub_efi_status_t (__grub_efi_api *get_memory_attributes) (
+                           struct grub_efi_memory_attribute_protocol *this,
+                           grub_efi_physical_address_t base_address,
+                           grub_efi_uint64_t length,
+                           grub_efi_uint64_t *attributes);
+  grub_efi_status_t (__grub_efi_api *set_memory_attributes) (
+                           struct grub_efi_memory_attribute_protocol *this,
+                           grub_efi_physical_address_t base_address,
+                           grub_efi_uint64_t length,
+                           grub_efi_uint64_t attributes);
+  grub_efi_status_t (__grub_efi_api *clear_memory_attributes) (
+                           struct grub_efi_memory_attribute_protocol *this,
+                           grub_efi_physical_address_t base_address,
+                           grub_efi_uint64_t length,
+                           grub_efi_uint64_t attributes);
+};
+typedef struct grub_efi_memory_attribute_protocol 
grub_efi_memory_attribute_protocol_t;
+
 #endif /* ! GRUB_EFI_API_HEADER */
diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
index a5cd99e5a..194adc1f7 100644
--- a/include/grub/efi/efi.h
+++ b/include/grub/efi/efi.h
@@ -151,4 +151,6 @@ struct grub_net_card;
 grub_efi_handle_t
 grub_efinet_get_device_handle (struct grub_net_card *card);
 
+grub_err_t EXPORT_FUNC(grub_efi_status_to_err) (grub_efi_status_t status);
+
 #endif /* ! GRUB_EFI_EFI_HEADER */
diff --git a/include/grub/mm.h b/include/grub/mm.h
index f3bf87fa0..8ee1fc717 100644
--- a/include/grub/mm.h
+++ b/include/grub/mm.h
@@ -23,6 +23,7 @@
 #include <grub/err.h>
 #include <grub/types.h>
 #include <grub/symbol.h>
+#include <grub/err.h>
 #include <config.h>
 
 #ifndef NULL
@@ -56,6 +57,37 @@ void *EXPORT_FUNC(grub_realloc) (void *ptr, grub_size_t 
size);
 void *EXPORT_FUNC(grub_memalign) (grub_size_t align, grub_size_t size);
 #endif
 
+#define GRUB_MEM_ATTR_R        0x0000000000000004LLU
+#define GRUB_MEM_ATTR_W        0x0000000000000002LLU
+#define GRUB_MEM_ATTR_X        0x0000000000000001LLU
+
+#ifdef GRUB_MACHINE_EFI
+grub_err_t EXPORT_FUNC(grub_get_mem_attrs) (grub_addr_t addr,
+                                           grub_size_t size,
+                                           grub_uint64_t *attrs);
+grub_err_t EXPORT_FUNC(grub_update_mem_attrs) (grub_addr_t addr,
+                                              grub_size_t size,
+                                              grub_uint64_t set_attrs,
+                                              grub_uint64_t clear_attrs);
+#else /* !GRUB_MACHINE_EFI */
+static inline grub_err_t
+grub_get_mem_attrs (grub_addr_t addr __attribute__((__unused__)),
+                   grub_size_t size __attribute__((__unused__)),
+                   grub_uint64_t *attrs __attribute__((__unused__)))
+{
+  return GRUB_ERR_NONE;
+}
+
+static inline grub_err_t
+grub_update_mem_attrs (grub_addr_t addr __attribute__((__unused__)),
+                      grub_size_t size __attribute__((__unused__)),
+                      grub_uint64_t set_attrs __attribute__((__unused__)),
+                      grub_uint64_t clear_attrs __attribute__((__unused__)))
+{
+  return GRUB_ERR_NONE;
+}
+#endif /* GRUB_MACHINE_EFI */
+
 void grub_mm_check_real (const char *file, int line);
 #define grub_mm_check() grub_mm_check_real (GRUB_FILE, __LINE__);
 
-- 
2.39.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]