grub-devel
[Top][All Lists]
Advanced

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

[PATCH v5 04/10] modules: load module sections at page-aligned addresses


From: Mate Kukri
Subject: [PATCH v5 04/10] modules: load module sections at page-aligned addresses
Date: Thu, 15 Aug 2024 10:51:29 +0100

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 most EFI platforms to load module sections at 4kB
page-aligned addresses.  To do so, it adds an new per-arch function,
grub_arch_dl_min_alignment(), which returns the alignment needed for
dynamically loaded sections (in bytes).  Currently it sets it to 4096
when GRUB_MACHINE_EFI is true on x86_64, i386, arm, arm64, and emu, and
1-byte alignment on everything else.

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>
---
 docs/grub-dev.texi          |  6 ++---
 grub-core/kern/arm/dl.c     | 14 ++++++++++
 grub-core/kern/arm64/dl.c   | 14 ++++++++++
 grub-core/kern/dl.c         | 52 +++++++++++++++++++++++++------------
 grub-core/kern/emu/full.c   | 14 ++++++++++
 grub-core/kern/i386/dl.c    | 14 ++++++++++
 grub-core/kern/ia64/dl.c    |  9 +++++++
 grub-core/kern/mips/dl.c    |  8 ++++++
 grub-core/kern/powerpc/dl.c |  9 +++++++
 grub-core/kern/riscv/dl.c   | 14 ++++++++++
 grub-core/kern/sparc64/dl.c |  9 +++++++
 grub-core/kern/x86_64/dl.c  | 14 ++++++++++
 include/grub/dl.h           |  4 +++
 include/grub/efi/memory.h   |  2 ++
 14 files changed, 164 insertions(+), 19 deletions(-)

diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
index 1276c5930..2f782cda5 100644
--- a/docs/grub-dev.texi
+++ b/docs/grub-dev.texi
@@ -996,9 +996,9 @@ declare startup asm file ($cpu_$platform_startup) as well 
as any other files
 (e.g. init.c and callwrap.S) (e.g. $cpu_$platform = 
kern/$cpu/$platform/init.c).
 At this stage you will also need to add dummy dl.c and cache.S with functions
 grub_err_t grub_arch_dl_check_header (void *ehdr), grub_err_t
-grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c) and
-void grub_arch_sync_caches (void *address, grub_size_t len) (cache.S). They
-won't be used for now.
+grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c), grub_uint32_t
+grub_arch_dl_min_alignment (void), and void grub_arch_sync_caches (void
+*address, grub_size_t len) (cache.S). They won't be used for now.
 
 You will need to create directory include/$cpu/$platform and a file
 include/$cpu/types.h. The latter following this template:
diff --git a/grub-core/kern/arm/dl.c b/grub-core/kern/arm/dl.c
index eab9d17ff..ed98b4006 100644
--- a/grub-core/kern/arm/dl.c
+++ b/grub-core/kern/arm/dl.c
@@ -24,6 +24,7 @@
 #include <grub/mm.h>
 #include <grub/i18n.h>
 #include <grub/arm/reloc.h>
+#include <grub/efi/memory.h>
 
 struct trampoline_arm
 {
@@ -278,3 +279,16 @@ grub_arch_dl_check_header (void *ehdr)
 
   return GRUB_ERR_NONE;
 }
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+#ifdef GRUB_MACHINE_EFI
+  return GRUB_EFI_DL_ALIGN;
+#else
+  return GRUB_DEFAULT_DL_ALIGN;
+#endif
+}
diff --git a/grub-core/kern/arm64/dl.c b/grub-core/kern/arm64/dl.c
index a2b5789a9..7c1cf73fb 100644
--- a/grub-core/kern/arm64/dl.c
+++ b/grub-core/kern/arm64/dl.c
@@ -24,6 +24,7 @@
 #include <grub/mm.h>
 #include <grub/i18n.h>
 #include <grub/cpu/reloc.h>
+#include <grub/efi/memory.h>
 
 #define LDR 0x58000050
 #define BR 0xd61f0200
@@ -196,3 +197,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
 
   return GRUB_ERR_NONE;
 }
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+#ifdef GRUB_MACHINE_EFI
+  return GRUB_EFI_DL_ALIGN;
+#else
+  return GRUB_DEFAULT_DL_ALIGN;
+#endif
+}
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
index 37db9fab0..0d22b9cd5 100644
--- a/grub-core/kern/dl.c
+++ b/grub-core/kern/dl.c
@@ -224,25 +224,35 @@ 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 = grub_arch_dl_min_alignment ();
+
   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;
+      if (talign < sh_addralign)
+       talign = sh_addralign;
     }
 
 #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \
@@ -250,12 +260,18 @@ 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_ARCH_DL_TRAMP_ALIGN;
+  if (tramp_align < arch_addralign)
+    tramp_align = arch_addralign;
+  tsize += ALIGN_UP (tramp, tramp_align);
+  if (talign < tramp_align)
+    talign = tramp_align;
+  got_align = GRUB_ARCH_DL_GOT_ALIGN;
+  if (got_align < arch_addralign)
+    got_align = arch_addralign;
+  tsize += ALIGN_UP (got, got_align);
+  if (talign < got_align)
+    talign = got_align;
 #endif
 
 #ifdef GRUB_MACHINE_EMU
@@ -272,6 +288,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 +303,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 +323,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 +331,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;
diff --git a/grub-core/kern/emu/full.c b/grub-core/kern/emu/full.c
index e8d63b1f5..28edec01d 100644
--- a/grub-core/kern/emu/full.c
+++ b/grub-core/kern/emu/full.c
@@ -23,6 +23,7 @@
 #include <grub/misc.h>
 #include <grub/emu/misc.h>
 #include <grub/disk.h>
+#include <grub/efi/memory.h>
 
 const int grub_no_modules = 1;
 
@@ -67,3 +68,16 @@ grub_arch_dl_init_linker (void)
 }
 #endif
 
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+ #ifdef GRUB_MACHINE_EFI
+  return GRUB_EFI_DL_ALIGN;
+ #else
+  return GRUB_DEFAULT_DL_ALIGN;
+ #endif
+}
diff --git a/grub-core/kern/i386/dl.c b/grub-core/kern/i386/dl.c
index 1346da5cc..ae440dbcc 100644
--- a/grub-core/kern/i386/dl.c
+++ b/grub-core/kern/i386/dl.c
@@ -22,6 +22,7 @@
 #include <grub/misc.h>
 #include <grub/err.h>
 #include <grub/i18n.h>
+#include <grub/efi/memory.h>
 
 /* Check if EHDR is a valid ELF header.  */
 grub_err_t
@@ -79,3 +80,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
 
   return GRUB_ERR_NONE;
 }
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+#ifdef GRUB_MACHINE_EFI
+  return GRUB_EFI_DL_ALIGN;
+#else
+  return GRUB_DEFAULT_DL_ALIGN;
+#endif
+}
diff --git a/grub-core/kern/ia64/dl.c b/grub-core/kern/ia64/dl.c
index db59300fe..5ecb1dc5b 100644
--- a/grub-core/kern/ia64/dl.c
+++ b/grub-core/kern/ia64/dl.c
@@ -148,3 +148,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
     }
   return GRUB_ERR_NONE;
 }
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+  return GRUB_DEFAULT_DL_ALIGN;
+}
diff --git a/grub-core/kern/mips/dl.c b/grub-core/kern/mips/dl.c
index 5b02f97fc..8073c1ecf 100644
--- a/grub-core/kern/mips/dl.c
+++ b/grub-core/kern/mips/dl.c
@@ -272,3 +272,11 @@ grub_arch_dl_init_linker (void)
   grub_dl_register_symbol ("_gp_disp", &_gp_disp_dummy, 0, 0);
 }
 
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+  return GRUB_DEFAULT_DL_ALIGN;
+}
diff --git a/grub-core/kern/powerpc/dl.c b/grub-core/kern/powerpc/dl.c
index 7b6418eab..18c3928e7 100644
--- a/grub-core/kern/powerpc/dl.c
+++ b/grub-core/kern/powerpc/dl.c
@@ -167,3 +167,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
 
   return GRUB_ERR_NONE;
 }
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+  return GRUB_DEFAULT_DL_ALIGN;
+}
diff --git a/grub-core/kern/riscv/dl.c b/grub-core/kern/riscv/dl.c
index 896653bb4..0e4103ed0 100644
--- a/grub-core/kern/riscv/dl.c
+++ b/grub-core/kern/riscv/dl.c
@@ -23,6 +23,7 @@
 #include <grub/err.h>
 #include <grub/mm.h>
 #include <grub/i18n.h>
+#include <grub/efi/memory.h>
 
 /*
  * Instructions and instruction encoding are documented in the RISC-V
@@ -344,3 +345,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
 
   return GRUB_ERR_NONE;
 }
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+#ifdef GRUB_MACHINE_EFI
+  return GRUB_EFI_DL_ALIGN;
+#else
+  return GRUB_DEFAULT_DL_ALIGN;
+#endif
+}
diff --git a/grub-core/kern/sparc64/dl.c b/grub-core/kern/sparc64/dl.c
index f3d960186..292aab888 100644
--- a/grub-core/kern/sparc64/dl.c
+++ b/grub-core/kern/sparc64/dl.c
@@ -189,3 +189,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
 
   return GRUB_ERR_NONE;
 }
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+  return GRUB_DEFAULT_DL_ALIGN;
+}
diff --git a/grub-core/kern/x86_64/dl.c b/grub-core/kern/x86_64/dl.c
index e5a8bdcf4..7e8e935ca 100644
--- a/grub-core/kern/x86_64/dl.c
+++ b/grub-core/kern/x86_64/dl.c
@@ -22,6 +22,7 @@
 #include <grub/misc.h>
 #include <grub/err.h>
 #include <grub/i18n.h>
+#include <grub/efi/memory.h>
 
 /* Check if EHDR is a valid ELF header.  */
 grub_err_t
@@ -119,3 +120,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
 
   return GRUB_ERR_NONE;
 }
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+#ifdef GRUB_MACHINE_EFI
+  return GRUB_EFI_DL_ALIGN;
+#else
+  return GRUB_DEFAULT_DL_ALIGN;
+#endif
+}
diff --git a/include/grub/dl.h b/include/grub/dl.h
index 750fc8d3d..beb20cb7e 100644
--- a/include/grub/dl.h
+++ b/include/grub/dl.h
@@ -264,6 +264,8 @@ grub_err_t grub_arch_dl_check_header (void *ehdr);
 grub_err_t
 grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
                               Elf_Shdr *s, grub_dl_segment_t seg);
+grub_size_t
+grub_arch_dl_min_alignment (void);
 #endif
 
 #if defined (_mips)
@@ -308,4 +310,6 @@ grub_arch_dl_get_tramp_got_size (const void *ehdr, 
grub_size_t *tramp,
 
 #endif
 
+#define GRUB_DEFAULT_DL_ALIGN 1
+
 #endif /* ! GRUB_DL_H */
diff --git a/include/grub/efi/memory.h b/include/grub/efi/memory.h
index 08fe62277..3f35500b2 100644
--- a/include/grub/efi/memory.h
+++ b/include/grub/efi/memory.h
@@ -31,6 +31,8 @@
 
 #define GRUB_MMAP_REGISTER_BY_FIRMWARE  1
 
+#define GRUB_EFI_DL_ALIGN              GRUB_EFI_PAGE_SIZE
+
 grub_err_t grub_machine_mmap_register (grub_uint64_t start, grub_uint64_t size,
                                       int type, int handle);
 grub_err_t grub_machine_mmap_unregister (int handle);
-- 
2.39.2




reply via email to

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