[PATCH] Check sh_entsize is not zero.

Mark Wielaard mark@klomp.org
Fri Oct 19 13:03:00 GMT 2018


There were some recent bug reports where we trusted the ELF section header
to be sane and divided the sh_size by the sh_entsize to get the number of
objects in the section. This would cause a divide by zero if the file was
corrupt and the sh_entsize was zero. Add checks for any such code.

Signed-off-by: Mark Wielaard <mark@klomp.org>
---
 libasm/ChangeLog               |  4 ++++
 libasm/disasm_cb.c             |  2 ++
 libdwfl/ChangeLog              |  4 ++++
 libdwfl/dwfl_module_getdwarf.c |  2 ++
 src/ChangeLog                  |  7 +++++++
 src/unstrip.c                  | 27 ++++++++++++++++++++++++++-
 6 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/libasm/ChangeLog b/libasm/ChangeLog
index 2efd85f..92dfd72 100644
--- a/libasm/ChangeLog
+++ b/libasm/ChangeLog
@@ -1,3 +1,7 @@
+2018-10-19  Mark Wielaard  <mark@klomp.org>
+
+	* disasm_cb.c (read_symtab_exec): Check sh_entsize is not zero.
+
 2018-07-04  Ross Burton <ross.burton@intel.com>
 
 	* asm_end.c: Remove error.h include.
diff --git a/libasm/disasm_cb.c b/libasm/disasm_cb.c
index cf278c7..80f8b25 100644
--- a/libasm/disasm_cb.c
+++ b/libasm/disasm_cb.c
@@ -93,6 +93,8 @@ read_symtab_exec (DisasmCtx_t *ctx)
 	xndxdata = elf_getdata (elf_getscn (ctx->elf, xndxscnidx), NULL);
 
       /* Iterate over all symbols.  Add all defined symbols.  */
+      if (shdr->sh_entsize == 0)
+	continue;
       int nsyms = shdr->sh_size / shdr->sh_entsize;
       for (int cnt = 1; cnt < nsyms; ++cnt)
 	{
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 2e7efd4..6c333d8 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,7 @@
+2018-10-19  Mark Wielaard  <mark@klomp.org>
+
+	* dwfl_module_getdwarf.c (find_aux_sym): Check sh_entsize is not zero.
+
 2018-10-14  Mark Wielaard  <mark@klomp.org>
 
 	* dwfl_segment_report_module.c (read_portion): Check requested
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index af6838a..56e6105 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -1007,6 +1007,8 @@ find_aux_sym (Dwfl_Module *mod __attribute__ ((unused)),
 		    switch (shdr->sh_type)
 		      {
 		      case SHT_SYMTAB:
+			if (shdr->sh_entsize == 0)
+			  return;
 			minisymtab = true;
 			*aux_symscn = scn;
 			*aux_strshndx = shdr->sh_link;
diff --git a/src/ChangeLog b/src/ChangeLog
index 3d2214f..32eaa84 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,10 @@
+2018-10-19  Mark Wielaard  <mark@klomp.org>
+
+	* dwfl_module_getdwarf.c (adjust_relocs): Check sh_entsize is not
+	zero.
+	(add_new_section_symbols): Likewise.
+	(copy_elided_sections): Likewise.
+
 2018-10-18  Mark Wielaard  <mark@klomp.org>
 
 	* size.c (handle_ar): Only close elf if prefix was NULL.
diff --git a/src/unstrip.c b/src/unstrip.c
index 03a0346..9dc468f 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -446,6 +446,9 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr,
   switch (shdr->sh_type)
     {
     case SHT_REL:
+      if (shdr->sh_entsize == 0)
+	error (EXIT_FAILURE, 0, "REL section cannot have zero sh_entsize");
+
       for (size_t i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i)
 	{
 	  GElf_Rel rel_mem;
@@ -457,6 +460,9 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr,
       break;
 
     case SHT_RELA:
+      if (shdr->sh_entsize == 0)
+	error (EXIT_FAILURE, 0, "RELA section cannot have zero sh_entsize");
+
       for (size_t i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i)
 	{
 	  GElf_Rela rela_mem;
@@ -483,6 +489,10 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr,
     case SHT_HASH:
       /* We must expand the table and rejigger its contents.  */
       {
+	if (shdr->sh_entsize == 0)
+	  error (EXIT_FAILURE, 0, "HASH section cannot have zero sh_entsize");
+	if (symshdr->sh_entsize == 0)
+	  error (EXIT_FAILURE, 0, "Symbol table cannot have zero sh_entsize");
 	const size_t nsym = symshdr->sh_size / symshdr->sh_entsize;
 	const size_t onent = shdr->sh_size / shdr->sh_entsize;
 	assert (data->d_size == shdr->sh_size);
@@ -538,6 +548,11 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr,
     case SHT_GNU_versym:
       /* We must expand the table and move its elements around.  */
       {
+	if (shdr->sh_entsize == 0)
+	  error (EXIT_FAILURE, 0,
+		 "GNU_versym section cannot have zero sh_entsize");
+	if (symshdr->sh_entsize == 0)
+	  error (EXIT_FAILURE, 0, "Symbol table cannot have zero sh_entsize");
 	const size_t nent = symshdr->sh_size / symshdr->sh_entsize;
 	const size_t onent = shdr->sh_size / shdr->sh_entsize;
 	assert (nent >= onent);
@@ -603,6 +618,8 @@ add_new_section_symbols (Elf_Scn *old_symscn, size_t old_shnum,
   GElf_Shdr shdr_mem;
   GElf_Shdr *shdr = gelf_getshdr (symscn, &shdr_mem);
   ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
+  if (shdr->sh_entsize == 0)
+    error (EXIT_FAILURE, 0, "Symbol table section cannot have zero sh_entsize");
 
   const size_t nsym = shdr->sh_size / shdr->sh_entsize;
   size_t symndx_map[nsym - 1];
@@ -1671,6 +1688,9 @@ more sections in stripped file than debug file -- arguments reversed?"));
 
 	    Elf_Data *shndxdata = NULL;	/* XXX */
 
+	    if (shdr_mem.sh_entsize == 0)
+	      error (EXIT_FAILURE, 0,
+		     "SYMTAB section cannot have zero sh_entsize");
 	    for (size_t i = 1; i < shdr_mem.sh_size / shdr_mem.sh_entsize; ++i)
 	      {
 		GElf_Sym sym_mem;
@@ -1722,11 +1742,16 @@ more sections in stripped file than debug file -- arguments reversed?"));
       /* Merge the stripped file's symbol table into the unstripped one.  */
       const size_t stripped_nsym = (stripped_symtab == NULL ? 1
 				    : (stripped_symtab->shdr.sh_size
-				       / stripped_symtab->shdr.sh_entsize));
+				       / (stripped_symtab->shdr.sh_entsize == 0
+					  ? 1
+					  : stripped_symtab->shdr.sh_entsize)));
 
       GElf_Shdr shdr_mem;
       GElf_Shdr *shdr = gelf_getshdr (unstripped_symtab, &shdr_mem);
       ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
+      if (shdr->sh_entsize == 0)
+	error (EXIT_FAILURE, 0,
+	       "unstripped SYMTAB section cannot have zero sh_entsize");
       const size_t unstripped_nsym = shdr->sh_size / shdr->sh_entsize;
 
       /* First collect all the symbols from both tables.  */
-- 
1.8.3.1



More information about the Elfutils-devel mailing list