grub-devel
[Top][All Lists]
Advanced

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

[PATCH] util/grub-module-verifierXX.c: Add module_size parameter to func


From: Alec Brown
Subject: [PATCH] util/grub-module-verifierXX.c: Add module_size parameter to functions for sanity checking
Date: Thu, 9 Mar 2023 14:43:59 -0500

In grub-module-verifierXX.c, the function grub_module_verifyXX() performs an
initial check that the ELF section headers are within the module's size, but
doesn't check if the sections being accessed have contents that are within the
module's size. In particular, we need to check that sh_offset and sh_size are
less than the module's size. However, for some section header types we don't
need to make these checks. For the type SHT_NULL, the section header is marked
as inactive and the rest of the members within the section header have undefined
values, so we don't need to check for sh_offset or sh_size. In the case of the
type SHT_NOBITS, sh_offset has a conceptual offset which may be beyond the
module size. Also, this type's sh_size may have a non-zero size, but a section
of this type will take up no space in the module. This can all be checked in the
function get_shdr(), but in order to do so, the parameter module_size must be
added to functions so that the value of the module size can be used in
get_shdr() from grub_module_verifyXX().

Also, had to rework some for loops to ensure the index passed to get_shdr() is
within bounds.

Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
---
 util/grub-module-verifierXX.c | 111 ++++++++++++++++++++--------------
 1 file changed, 64 insertions(+), 47 deletions(-)

diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c
index d5907f268..b3f77ea0e 100644
--- a/util/grub-module-verifierXX.c
+++ b/util/grub-module-verifierXX.c
@@ -143,13 +143,24 @@ grub_target_to_host_real (const struct 
grub_module_verifier_arch *arch, grub_uin
 }
 
 static Elf_Shdr *
-get_shdr (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, Elf_Word 
index)
+get_shdr (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, Elf_Word 
index, size_t module_size)
 {
+  Elf_Shdr *s;
+
   if (grub_target_to_host (e->e_shoff) == 0)
     grub_util_error ("Invalid section header offset");
 
-  return (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff) +
-                      index * grub_target_to_host16 (e->e_shentsize));
+  s = (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff) +
+                   index * grub_target_to_host16 (e->e_shentsize));
+  /* Check that the header being accessed isn't outside the module size */
+  if (grub_target_to_host32 (s->sh_type) != SHT_NULL && grub_target_to_host32 
(s->sh_type) != SHT_NOBITS)
+    {
+      if (grub_target_to_host (s->sh_offset) > module_size)
+       grub_util_error ("Section %d starts after the end of the module", 
index);
+      if (grub_target_to_host (s->sh_offset) + grub_target_to_host 
(s->sh_size) > module_size)
+       grub_util_error ("Section %d ends after the end of the module", index);
+    }
+  return s;
 }
 
 static Elf_Shnum
@@ -161,7 +172,7 @@ get_shnum (const struct grub_module_verifier_arch *arch, 
Elf_Ehdr *e)
   shnum = grub_target_to_host16 (e->e_shnum);
   if (shnum == SHN_UNDEF)
     {
-      s = get_shdr (arch, e, 0);
+      s = get_shdr (arch, e, 0, 0);
       shnum = grub_target_to_host (s->sh_size);
       if (shnum < SHN_LORESERVE)
        grub_util_error ("Invalid number of section header table entries in 
sh_size: %" PRIuGRUB_UINT64_T, (grub_uint64_t) shnum);
@@ -176,7 +187,7 @@ get_shnum (const struct grub_module_verifier_arch *arch, 
Elf_Ehdr *e)
 }
 
 static Elf_Word
-get_shstrndx (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e)
+get_shstrndx (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, 
size_t module_size)
 {
   Elf_Shdr *s;
   Elf_Word shstrndx;
@@ -184,7 +195,7 @@ get_shstrndx (const struct grub_module_verifier_arch *arch, 
Elf_Ehdr *e)
   shstrndx = grub_target_to_host16 (e->e_shstrndx);
   if (shstrndx == SHN_XINDEX)
     {
-      s = get_shdr (arch, e, 0);
+      s = get_shdr (arch, e, 0, 0);
       shstrndx = grub_target_to_host (s->sh_link);
       if (shstrndx < SHN_LORESERVE)
        grub_util_error ("Invalid section header table index in sh_link: %d", 
shstrndx);
@@ -199,28 +210,30 @@ get_shstrndx (const struct grub_module_verifier_arch 
*arch, Elf_Ehdr *e)
 }
 
 static Elf_Shdr *
-find_section (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, const 
char *name)
+find_section (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, const 
char *name, size_t module_size)
 {
   Elf_Shdr *s;
   const char *str;
   unsigned i;
 
-  s = get_shdr (arch, e, get_shstrndx (arch, e));
+  s = get_shdr (arch, e, get_shstrndx (arch, e, module_size), module_size);
   str = (char *) e + grub_target_to_host (s->sh_offset);
 
-  for (i = 0, s = get_shdr (arch, e, 0);
-       i < get_shnum (arch, e);
-       i++, s = get_shdr (arch, e, i))
-    if (strcmp (str + grub_target_to_host32 (s->sh_name), name) == 0)
-      return s;
+  for (i = 0; i < get_shnum (arch, e); i++)
+    {
+      s = get_shdr (arch, e, i, module_size);
+
+      if (strcmp (str + grub_target_to_host32 (s->sh_name), name) == 0)
+       return s;
+    }
   return NULL;
 }
 
 static void
 check_license (const char * const filename,
-              const struct grub_module_verifier_arch *arch, Elf_Ehdr *e)
+              const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, 
size_t module_size)
 {
-  Elf_Shdr *s = find_section (arch, e, ".module_license");
+  Elf_Shdr *s = find_section (arch, e, ".module_license", module_size);
   if (s && (strcmp ((char *) e + grub_target_to_host(s->sh_offset), 
"LICENSE=GPLv3") == 0
            || strcmp ((char *) e + grub_target_to_host(s->sh_offset), 
"LICENSE=GPLv3+") == 0
            || strcmp ((char *) e + grub_target_to_host(s->sh_offset), 
"LICENSE=GPLv2+") == 0))
@@ -229,17 +242,19 @@ check_license (const char * const filename,
 }
 
 static Elf_Sym *
-get_symtab (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, 
Elf_Word *size, Elf_Word *entsize)
+get_symtab (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, 
Elf_Word *size, Elf_Word *entsize, size_t module_size)
 {
   unsigned i;
   Elf_Shdr *s;
   Elf_Sym *sym;
 
-  for (i = 0, s = get_shdr (arch, e, 0);
-       i < get_shnum (arch, e);
-       i++, s = get_shdr (arch, e, i))
-    if (grub_target_to_host32 (s->sh_type) == SHT_SYMTAB)
-      break;
+  for (i = 0; i < get_shnum (arch, e); i++)
+    {
+      s = get_shdr (arch, e, i, module_size);
+
+      if (grub_target_to_host32 (s->sh_type) == SHT_SYMTAB)
+       break;
+    }
 
   if (i == get_shnum (arch, e))
     return NULL;
@@ -267,7 +282,7 @@ is_whitelisted (const char *modname, const char **whitelist)
 static void
 check_symbols (const struct grub_module_verifier_arch *arch,
               Elf_Ehdr *e, const char *modname,
-              const char **whitelist_empty)
+              const char **whitelist_empty, size_t module_size)
 {
   Elf_Sym *sym;
   Elf_Word size, entsize;
@@ -275,7 +290,7 @@ check_symbols (const struct grub_module_verifier_arch *arch,
 
   /* Module without symbol table and without .moddeps section is useless
      at boot time, so catch it early to prevent build errors */
-  sym = get_symtab (arch, e, &size, &entsize);
+  sym = get_symtab (arch, e, &size, &entsize, module_size);
   if (!sym)
     {
       Elf_Shdr *s;
@@ -287,7 +302,7 @@ check_symbols (const struct grub_module_verifier_arch *arch,
       if (is_whitelisted (modname, whitelist_empty))
        return;
 
-      s = find_section (arch, e, ".moddeps");
+      s = find_section (arch, e, ".moddeps", module_size);
 
       if (!s)
        grub_util_error ("%s: no symbol table and no .moddeps section", 
modname);
@@ -342,13 +357,13 @@ is_symbol_local(Elf_Sym *sym)
 static void
 section_check_relocations (const char * const modname,
                           const struct grub_module_verifier_arch *arch, void 
*ehdr,
-                          Elf_Shdr *s, size_t target_seg_size)
+                          Elf_Shdr *s, size_t target_seg_size, size_t 
module_size)
 {
   Elf_Rel *rel, *max;
   Elf_Sym *symtab;
   Elf_Word symtabsize, symtabentsize;
 
-  symtab = get_symtab (arch, ehdr, &symtabsize, &symtabentsize);
+  symtab = get_symtab (arch, ehdr, &symtabsize, &symtabentsize, module_size);
   if (!symtab)
     grub_util_error ("%s: relocation without symbol table", modname);
 
@@ -424,30 +439,32 @@ section_check_relocations (const char * const modname,
 
 static void
 check_relocations (const char * const modname,
-                  const struct grub_module_verifier_arch *arch, Elf_Ehdr *e)
+                  const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, 
size_t module_size)
 {
   Elf_Shdr *s;
   unsigned i;
 
-  for (i = 0, s = get_shdr (arch, e, 0);
-       i < get_shnum (arch, e);
-       i++, s = get_shdr (arch, e, i))
-    if (grub_target_to_host32 (s->sh_type) == SHT_REL || grub_target_to_host32 
(s->sh_type) == SHT_RELA)
-      {
-       Elf_Shdr *ts;
+  for (i = 0; i < get_shnum (arch, e); i++)
+    {
+      s = get_shdr (arch, e, i, module_size);
 
-       if (grub_target_to_host32 (s->sh_type) == SHT_REL && !(arch->flags & 
GRUB_MODULE_VERIFY_SUPPORTS_REL))
-         grub_util_error ("%s: unsupported SHT_REL", modname);
-       if (grub_target_to_host32 (s->sh_type) == SHT_RELA && !(arch->flags & 
GRUB_MODULE_VERIFY_SUPPORTS_RELA))
-         grub_util_error ("%s: unsupported SHT_RELA", modname);
+      if (grub_target_to_host32 (s->sh_type) == SHT_REL || 
grub_target_to_host32 (s->sh_type) == SHT_RELA)
+       {
+         Elf_Shdr *ts;
 
-       /* Find the target segment.  */
-       if (grub_target_to_host32 (s->sh_info) >= get_shnum (arch, e))
-         grub_util_error ("%s: orphaned reloc section", modname);
-       ts = get_shdr (arch, e, grub_target_to_host32 (s->sh_info));
+         if (grub_target_to_host32 (s->sh_type) == SHT_REL && !(arch->flags & 
GRUB_MODULE_VERIFY_SUPPORTS_REL))
+           grub_util_error ("%s: unsupported SHT_REL", modname);
+         if (grub_target_to_host32 (s->sh_type) == SHT_RELA && !(arch->flags & 
GRUB_MODULE_VERIFY_SUPPORTS_RELA))
+           grub_util_error ("%s: unsupported SHT_RELA", modname);
 
-       section_check_relocations (modname, arch, e, s, grub_target_to_host 
(ts->sh_size));
-      }
+         /* Find the target segment.  */
+         if (grub_target_to_host32 (s->sh_info) >= get_shnum (arch, e))
+           grub_util_error ("%s: orphaned reloc section", modname);
+         ts = get_shdr (arch, e, grub_target_to_host32 (s->sh_info), 
module_size);
+
+         section_check_relocations (modname, arch, e, s, grub_target_to_host 
(ts->sh_size), module_size);
+       }
+    }
 }
 
 void
@@ -488,17 +505,17 @@ SUFFIX(grub_module_verify) (const char * const filename,
       grub_util_error ("%s: ELF sections outside core", filename);
     }
 
-  check_license (filename, arch, e);
+  check_license (filename, arch, e, size);
 
   Elf_Shdr *s;
   const char *modname;
 
-  s = find_section (arch, e, ".modname");
+  s = find_section (arch, e, ".modname", size);
   if (!s)
     grub_util_error ("%s: no module name found", filename);
 
   modname = (const char *) e + grub_target_to_host (s->sh_offset);
 
-  check_symbols(arch, e, modname, whitelist_empty);
-  check_relocations(modname, arch, e);
+  check_symbols(arch, e, modname, whitelist_empty, size);
+  check_relocations(modname, arch, e, size);
 }
-- 
2.27.0




reply via email to

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