]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
modules: Load module sections at page-aligned addresses
authorMate Kukri <mate.kukri@canonical.com>
Wed, 9 Oct 2024 08:16:39 +0000 (09:16 +0100)
committerDaniel Kiper <daniel.kiper@oracle.com>
Fri, 11 Oct 2024 12:34:28 +0000 (14:34 +0200)
Currently we load module sections at whatever alignment gcc+ld happened
to dump into the ELF section header which is often less then the page
size. Since NX protections are page based this alignment must be rounded
up to page size on platforms supporting NX protections. This patch
switches EFI platforms to load module sections at 4 KiB page-aligned
addresses. It then changes the allocation size computation and the
loader code in grub_dl_load_segments() to align the locations and sizes
up to these boundaries and fills any added padding with zeros. All of
this happens before relocations are applied, so the relocations factor
that in with no change.

Signed-off-by: Peter Jones <pjones@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>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
grub-core/kern/dl.c

index 37db9fab09c936cf84c9be07ebeb350377b71e04..e9e2afb5b402c1a859e148b3daf147036c220a83 100644 (file)
 #include <grub/cache.h>
 #include <grub/i18n.h>
 
+#ifdef GRUB_MACHINE_EFI
+#include <grub/efi/memory.h>
+#endif
+
 /* Platforms where modules are in a readonly area of memory.  */
 #if defined(GRUB_MACHINE_QEMU)
 #define GRUB_MODULES_MACHINE_READONLY
 #endif
 
-\f
+#ifdef GRUB_MACHINE_EFI
+#define DL_ALIGN       GRUB_EFI_PAGE_SIZE
+#else
+#define DL_ALIGN       1
+#endif
 
 #pragma GCC diagnostic ignored "-Wcast-align"
 
@@ -224,25 +232,34 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
 {
   unsigned i;
   const Elf_Shdr *s;
-  grub_size_t tsize = 0, talign = 1;
+  grub_size_t tsize = 0, talign = 1, arch_addralign = 1;
 #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \
   !defined (__loongarch__)
   grub_size_t tramp;
+  grub_size_t tramp_align;
   grub_size_t got;
+  grub_size_t got_align;
   grub_err_t err;
 #endif
   char *ptr;
 
+  arch_addralign = DL_ALIGN;
+
   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_size_t sh_addralign;
+      grub_size_t sh_size;
+
       if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC))
        continue;
 
-      tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size;
-      if (talign < s->sh_addralign)
-       talign = s->sh_addralign;
+      sh_addralign = ALIGN_UP (s->sh_addralign, arch_addralign);
+      sh_size = ALIGN_UP (s->sh_size, sh_addralign);
+
+      tsize = ALIGN_UP (tsize, sh_addralign) + sh_size;
+      talign = grub_max (talign, sh_addralign);
     }
 
 #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \
@@ -250,12 +267,12 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
   err = grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
   if (err)
     return err;
-  tsize += ALIGN_UP (tramp, GRUB_ARCH_DL_TRAMP_ALIGN);
-  if (talign < GRUB_ARCH_DL_TRAMP_ALIGN)
-    talign = GRUB_ARCH_DL_TRAMP_ALIGN;
-  tsize += ALIGN_UP (got, GRUB_ARCH_DL_GOT_ALIGN);
-  if (talign < GRUB_ARCH_DL_GOT_ALIGN)
-    talign = GRUB_ARCH_DL_GOT_ALIGN;
+  tramp_align = grub_max (GRUB_ARCH_DL_TRAMP_ALIGN, arch_addralign);
+  tsize += ALIGN_UP (tramp, tramp_align);
+  talign = grub_max (talign, tramp_align);
+  got_align = grub_max (GRUB_ARCH_DL_GOT_ALIGN, arch_addralign);
+  tsize += ALIGN_UP (got, got_align);
+  talign = grub_max (talign, got_align);
 #endif
 
 #ifdef GRUB_MACHINE_EMU
@@ -272,6 +289,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
        i < e->e_shnum;
        i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
     {
+      grub_size_t sh_addralign = ALIGN_UP (s->sh_addralign, arch_addralign);
+      grub_size_t sh_size = ALIGN_UP (s->sh_size, sh_addralign);
+
       if (s->sh_flags & SHF_ALLOC)
        {
          grub_dl_segment_t seg;
@@ -284,17 +304,18 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
            {
              void *addr;
 
-             ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign);
+             ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, sh_addralign);
              addr = ptr;
-             ptr += s->sh_size;
+             ptr += sh_size;
 
              switch (s->sh_type)
                {
                case SHT_PROGBITS:
                  grub_memcpy (addr, (char *) e + s->sh_offset, s->sh_size);
+                 grub_memset ((char *) addr + s->sh_size, 0, sh_size - s->sh_size);
                  break;
                case SHT_NOBITS:
-                 grub_memset (addr, 0, s->sh_size);
+                 grub_memset (addr, 0, sh_size);
                  break;
                }
 
@@ -303,7 +324,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
          else
            seg->addr = 0;
 
-         seg->size = s->sh_size;
+         seg->size = sh_size;
          seg->section = i;
          seg->next = mod->segment;
          mod->segment = seg;
@@ -311,11 +332,11 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
     }
 #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \
   !defined (__loongarch__)
-  ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN);
+  ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, tramp_align);
   mod->tramp = ptr;
   mod->trampptr = ptr;
   ptr += tramp;
-  ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_GOT_ALIGN);
+  ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, got_align);
   mod->got = ptr;
   mod->gotptr = ptr;
   ptr += got;