grub-devel
[Top][All Lists]
Advanced

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

[PATCH v8 06/10] nx: set page permissions for loaded modules.


From: Mate Kukri
Subject: [PATCH v8 06/10] nx: set page permissions for loaded modules.
Date: Wed, 9 Oct 2024 09:16:41 +0100

For NX, we need to set write and executable permissions on the sections
of GRUB modules when we load them.

All allocatable sections are marked readable. In addition,
- SHF_WRITE sections are marked as writable,
- and SHF_EXECINSTR sections are marked as executable.

Where relevant for the plaform, the tramp and GOT areas are marked
non-writable.

Signed-off-by: Peter Jones <pjones@redhat.com>
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Jan Setje-Eilers <jan.setjeeilers@oracle.com>
Signed-off-by: Mate Kukri <mate.kukri@canonical.com>
---
 grub-core/kern/dl.c | 91 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 90 insertions(+), 1 deletion(-)

diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
index 5dc15f070..be1ef5476 100644
--- a/grub-core/kern/dl.c
+++ b/grub-core/kern/dl.c
@@ -627,6 +627,94 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
   return GRUB_ERR_NONE;
 }
 
+/* Only define this on EFI to save space in core */
+#ifdef GRUB_MACHINE_EFI
+static grub_err_t
+grub_dl_set_mem_attrs (grub_dl_t mod, void *ehdr)
+{
+  unsigned i;
+  const Elf_Shdr *s;
+  const Elf_Ehdr *e = ehdr;
+  grub_err_t err;
+#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \
+  !defined (__loongarch__)
+  grub_size_t arch_addralign = GRUB_DL_ALIGN;
+  grub_addr_t tgaddr;
+  grub_size_t tgsz;
+#endif
+
+  for (i = 0, s = (const Elf_Shdr *) ((const char *) e + e->e_shoff);
+       i < e->e_shnum;
+       i++, s = (const Elf_Shdr *) ((const char *) s + e->e_shentsize))
+    {
+      grub_dl_segment_t seg;
+      grub_uint64_t set_attrs = GRUB_MEM_ATTR_R;
+      grub_uint64_t clear_attrs = GRUB_MEM_ATTR_W | GRUB_MEM_ATTR_X;
+
+      for (seg = mod->segment; seg; seg = seg->next)
+       /* Does this ELF section's index match GRUB DL segment? */
+       if (seg->section == s->sh_info)
+         break;
+
+      /* No GRUB DL segment found for this ELF section, skip it */
+      if (!seg)
+       continue;
+
+      if (seg->size == 0 || !(s->sh_flags & SHF_ALLOC))
+       continue;
+
+      if (s->sh_flags & SHF_WRITE)
+       {
+         set_attrs |= GRUB_MEM_ATTR_W;
+         clear_attrs &= ~GRUB_MEM_ATTR_W;
+       }
+
+      if (s->sh_flags & SHF_EXECINSTR)
+       {
+         set_attrs |= GRUB_MEM_ATTR_X;
+         clear_attrs &= ~GRUB_MEM_ATTR_X;
+       }
+
+      err = grub_update_mem_attrs ((grub_addr_t) seg->addr, seg->size,
+                                  set_attrs, clear_attrs);
+      if (err != GRUB_ERR_NONE)
+       return err;
+    }
+
+#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \
+  !defined (__loongarch__)
+  tgaddr = grub_min ((grub_addr_t) mod->tramp, (grub_addr_t) mod->got);
+  tgsz = grub_max ((grub_addr_t) mod->trampptr, (grub_addr_t) mod->gotptr) - 
tgaddr;
+
+  if (tgsz)
+    {
+      tgsz = ALIGN_UP (tgsz, arch_addralign);
+
+      if (tgaddr < (grub_addr_t) mod->base ||
+         tgsz > (grub_addr_t) -1 - tgaddr ||
+         tgaddr + tgsz > (grub_addr_t) mod->base + mod->sz)
+       return grub_error (GRUB_ERR_BUG,
+                          "BUG: trying to protect pages outside of module "
+                          "allocation (\"%s\"): module base %p, size 0x%"
+                          PRIxGRUB_SIZE "; tramp/GOT base 0x%" PRIxGRUB_ADDR
+                          ", size 0x%" PRIxGRUB_SIZE,
+                          mod->name, mod->base, mod->sz, tgaddr, tgsz);
+      err = grub_update_mem_attrs (tgaddr, tgsz, GRUB_MEM_ATTR_R | 
GRUB_MEM_ATTR_X, GRUB_MEM_ATTR_W);
+      if (err != GRUB_ERR_NONE)
+       return err;
+    }
+#endif
+
+  return GRUB_ERR_NONE;
+}
+#else
+static grub_err_t
+grub_dl_set_mem_attrs (grub_dl_t mod, void *ehdr)
+{
+  return GRUB_ERR_NONE;
+}
+#endif
+
 /* Load a module from core memory.  */
 grub_dl_t
 grub_dl_load_core_noinit (void *addr, grub_size_t size)
@@ -673,7 +761,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size)
       || grub_dl_resolve_dependencies (mod, e)
       || grub_dl_load_segments (mod, e)
       || grub_dl_resolve_symbols (mod, e)
-      || grub_dl_relocate_symbols (mod, e))
+      || grub_dl_relocate_symbols (mod, e)
+      || grub_dl_set_mem_attrs (mod, e))
     {
       mod->fini = 0;
       grub_dl_unload (mod);
-- 
2.39.2




reply via email to

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