4fe85b
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
4fe85b
From: Andrei Borzenkov <arvidjaar@gmail.com>
4fe85b
Date: Wed, 3 Feb 2016 20:34:55 +0300
4fe85b
Subject: [PATCH] support modules without symbol table
4fe85b
4fe85b
all_video module does not have any code or data and exists solely for
4fe85b
.moddeps section to pull in dependencies. This makes all symbols unneeded.
4fe85b
4fe85b
While in current binutils (last released version as of this commit is 2.26)
4fe85b
``strip --strip-unneeded'' unintentionally adds section symbols for each
4fe85b
existing section, this behavior was considered a bug and changed in commit
4fe85b
14f2c699ddca1e2f706342dffc59a6c7e23e844c to completely strip symbol table
4fe85b
in this case.
4fe85b
4fe85b
Older binutils (verified with 2.17) and some other toolchains (at least
4fe85b
elftoolchain r3223M), both used in FreeBSD, remove symbol table in all_video
4fe85b
as well.
4fe85b
4fe85b
Relax run-time check and do not return error for modules without symbol table.
4fe85b
Add additional checks to module verifier to make sure such modules
4fe85b
4fe85b
a) have non-empty .moddeps section. Without either externally visible symbols
4fe85b
or .moddeps modules are completely useless and should not be built.
4fe85b
4fe85b
b) do not have any relocations.
4fe85b
4fe85b
Closes: 46986
4fe85b
4fe85b
v2: add run-time check for empty symbol table if relocations are present as
4fe85b
    suggested by Vladimir.
4fe85b
---
4fe85b
 grub-core/kern/dl.c           |  8 +++++++-
4fe85b
 util/grub-module-verifierXX.c | 18 +++++++++++++++++-
4fe85b
 2 files changed, 24 insertions(+), 2 deletions(-)
4fe85b
4fe85b
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
4fe85b
index b0b0405fcbe..c45afc64950 100644
4fe85b
--- a/grub-core/kern/dl.c
4fe85b
+++ b/grub-core/kern/dl.c
4fe85b
@@ -341,8 +341,11 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
4fe85b
     if (s->sh_type == SHT_SYMTAB)
4fe85b
       break;
4fe85b
 
4fe85b
+  /* Module without symbol table may still be used to pull in dependencies.
4fe85b
+     We verify at build time that such modules do not contain any relocations
4fe85b
+     that may reference symbol table. */
4fe85b
   if (i == e->e_shnum)
4fe85b
-    return grub_error (GRUB_ERR_BAD_MODULE, N_("no symbol table"));
4fe85b
+    return GRUB_ERR_NONE;
4fe85b
 
4fe85b
 #ifdef GRUB_MODULES_MACHINE_READONLY
4fe85b
   mod->symtab = grub_malloc (s->sh_size);
4fe85b
@@ -584,6 +587,9 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
4fe85b
 
4fe85b
 	if (seg)
4fe85b
 	  {
4fe85b
+	    if (!mod->symtab)
4fe85b
+	      return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table");
4fe85b
+
4fe85b
 	    err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg);
4fe85b
 	    if (err)
4fe85b
 	      return err;
4fe85b
diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c
4fe85b
index f612d51f389..9c04caa63b4 100644
4fe85b
--- a/util/grub-module-verifierXX.c
4fe85b
+++ b/util/grub-module-verifierXX.c
4fe85b
@@ -176,7 +176,7 @@ get_symtab (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, Elf_Word
4fe85b
       break;
4fe85b
 
4fe85b
   if (i == grub_target_to_host16 (e->e_shnum))
4fe85b
-    grub_util_error ("no symbol table");
4fe85b
+    return NULL;
4fe85b
 
4fe85b
   sym = (Elf_Sym *) ((char *) e + grub_target_to_host (s->sh_offset));
4fe85b
   *size = grub_target_to_host (s->sh_size);
4fe85b
@@ -191,7 +191,21 @@ check_symbols (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e)
4fe85b
   Elf_Word size, entsize;
4fe85b
   unsigned i;
4fe85b
 
4fe85b
+  /* Module without symbol table and without .moddeps section is useless
4fe85b
+     at boot time, so catch it early to prevent build errors */
4fe85b
   sym = get_symtab (arch, e, &size, &entsize);
4fe85b
+  if (!sym)
4fe85b
+    {
4fe85b
+      Elf_Shdr *s = find_section (arch, e, ".moddeps");
4fe85b
+
4fe85b
+      if (!s)
4fe85b
+	grub_util_error ("no symbol table and no .moddeps section");
4fe85b
+
4fe85b
+      if (!s->sh_size)
4fe85b
+	grub_util_error ("no symbol table and empty .moddeps section");
4fe85b
+
4fe85b
+      return;
4fe85b
+    }
4fe85b
 
4fe85b
   for (i = 0;
4fe85b
        i < size / entsize;
4fe85b
@@ -243,6 +257,8 @@ section_check_relocations (const struct grub_module_verifier_arch *arch, void *e
4fe85b
   Elf_Word symtabsize, symtabentsize;
4fe85b
 
4fe85b
   symtab = get_symtab (arch, ehdr, &symtabsize, &symtabentsize);
4fe85b
+  if (!symtab)
4fe85b
+    grub_util_error ("relocation without symbol table");
4fe85b
 
4fe85b
   for (rel = (Elf_Rel *) ((char *) ehdr + grub_target_to_host (s->sh_offset)),
4fe85b
 	 max = (Elf_Rel *) ((char *) rel + grub_target_to_host (s->sh_size));