[PATCH 05/10] libelf: Fix shnum and section zero handling.

Mark Wielaard mark@klomp.org
Thu Sep 13 23:02:00 GMT 2018


For ELF files with more than SHN_LOWRESERVE sections we always need
section zero to store the section number (it doesn't just fit in the
Ehdr e_shnum field). Make sure to create it if it doesn't exist yet
in elf_getscn. Also fix handling on shnum in updatefile for the mmap
case (we already got this correct for the non-mmap case).

This adds a new test run-copymany-sections.sh which is like
run-copyadd-sections.sh but tries to add two times 65535 sections.
It makes sure libelf can copy the whole file and elfcmp checks they
are the same. It doesn't use mmap for addsections since that doesn't
work yet. ELF_C_RDWR_MMAP needs mremap which will fail since it needs
too much space and the original mmap cannot move.

Signed-off-by: Mark Wielaard <mark@klomp.org>
---
 libelf/ChangeLog               |  6 +++
 libelf/elf32_updatefile.c      |  2 +-
 libelf/elf_getscn.c            | 33 ++++++++++++++
 tests/ChangeLog                |  6 +++
 tests/Makefile.am              |  4 +-
 tests/run-copymany-sections.sh | 99 ++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 147 insertions(+), 3 deletions(-)
 create mode 100755 tests/run-copymany-sections.sh

diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index 3542122..be37ab6 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,9 @@
+2018-09-13  Mark Wielaard  <mark@klomp.org>
+
+	* elf32_updatefile.c (updatemmap): Use shnum, not ehdr->e_shnum.
+	* elf_getscn.c (elf_getscn): Create section zero if it is requested,
+	but doesn't exist yet.
+
 2018-09-12  Mark Wielaard  <mark@klomp.org>
 
 	* elf32_updatefile.c (updatemmap): Use memmove, not memcpy.
diff --git a/libelf/elf32_updatefile.c b/libelf/elf32_updatefile.c
index 545ce08..f2e9a28 100644
--- a/libelf/elf32_updatefile.c
+++ b/libelf/elf32_updatefile.c
@@ -236,7 +236,7 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
 	}
       char *const shdr_start = ((char *) elf->map_address + elf->start_offset
 				+ ehdr->e_shoff);
-      char *const shdr_end = shdr_start + ehdr->e_shnum * ehdr->e_shentsize;
+      char *const shdr_end = shdr_start + shnum * ehdr->e_shentsize;
 
 #if EV_NUM != 2
       xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
diff --git a/libelf/elf_getscn.c b/libelf/elf_getscn.c
index 9f7213b..e1fbaaa 100644
--- a/libelf/elf_getscn.c
+++ b/libelf/elf_getscn.c
@@ -59,6 +59,38 @@ elf_getscn (Elf *elf, size_t idx)
 		       || (offsetof (struct Elf, state.elf32.scns)
 			   == offsetof (struct Elf, state.elf64.scns))
 		       ? &elf->state.elf32.scns : &elf->state.elf64.scns);
+
+  /* Section zero is special.  It always exists even if there is no
+     "first" section.  And it is needed to store "overflow" values
+     from the Elf header.  */
+  if (idx == 0 && runp->cnt == 0 && runp->max > 0)
+    {
+      Elf_Scn *scn0 = &runp->data[0];
+      if (elf->class == ELFCLASS32)
+	{
+	  scn0->shdr.e32 = (Elf32_Shdr *) calloc (1, sizeof (Elf32_Shdr));
+	  if (scn0->shdr.e32 == NULL)
+	    {
+	      __libelf_seterrno (ELF_E_NOMEM);
+	      goto out;
+	    }
+	}
+      else
+	{
+	  scn0->shdr.e64 = (Elf64_Shdr *) calloc (1, sizeof (Elf64_Shdr));
+	  if (scn0->shdr.e64 == NULL)
+	    {
+	      __libelf_seterrno (ELF_E_NOMEM);
+	      goto out;
+	    }
+	}
+      scn0->elf = elf;
+      scn0->shdr_flags = ELF_F_DIRTY | ELF_F_MALLOCED;
+      scn0->list = elf->state.elf.scns_last;
+      scn0->data_read = 1;
+      runp->cnt = 1;
+    }
+
   while (1)
     {
       if (idx < runp->max)
@@ -80,6 +112,7 @@ elf_getscn (Elf *elf, size_t idx)
 	}
     }
 
+ out:
   rwlock_unlock (elf->lock);
 
   return result;
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 5709857..7668a66 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,9 @@
+2018-09-13  Mark Wielaard  <mark@klomp.org>
+
+	* run-copymany-sections.sh: New test.
+	* Makefile.am (TESTS): Add run-copymany-sections.sh.
+	(EXTRA_DIST): Likewise.
+
 2018-09-12  Mark Wielaard  <mark@klomp.org>
 
 	* Makefile.am (check_PROGRAMS): Add elfcopy and addsections.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index e0edef0..fc7d7bc 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -155,7 +155,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \
 	run-all-dwarf-ranges.sh run-unit-info.sh \
 	run-reloc-bpf.sh \
 	run-next-cfi.sh run-next-cfi-self.sh \
-	run-copyadd-sections.sh
+	run-copyadd-sections.sh run-copymany-sections.sh
 
 if !BIARCH
 export ELFUTILS_DISABLE_BIARCH = 1
@@ -406,7 +406,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
 	     run-unit-info.sh run-next-cfi.sh run-next-cfi-self.sh \
 	     testfile-riscv64.bz2 testfile-riscv64-s.bz2 \
 	     testfile-riscv64-core.bz2 \
-	     run-copyadd-sections.sh
+	     run-copyadd-sections.sh run-copymany-sections.sh
 
 if USE_VALGRIND
 valgrind_cmd='valgrind -q --leak-check=full --error-exitcode=1'
diff --git a/tests/run-copymany-sections.sh b/tests/run-copymany-sections.sh
new file mode 100755
index 0000000..84c052c
--- /dev/null
+++ b/tests/run-copymany-sections.sh
@@ -0,0 +1,99 @@
+#! /bin/sh
+# Copyright (C) 2018 Red Hat, Inc.
+# This file is part of elfutils.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# elfutils is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Same as run-copyadd-sections.sh, but for many > 0xffff sections.
+# Doesn't use mmap for addsections since that doesn't work.
+# ELF_C_RDWR_MMAP needs mremap which will fail since it needs too 
+# much space and the original mmap cannot move.
+
+. $srcdir/test-subr.sh
+
+test_copy_and_add ()
+{
+  in_file="$1"
+  out_file="${in_file}.copy"
+  out_file_mmap="${out_file}.mmap"
+
+  tempfiles ${out_file} ${out_file_mmap} readelf.out
+
+  # Can we copy the file?
+  testrun ${abs_builddir}/elfcopy ${in_file} ${out_file}
+  testrun ${abs_top_builddir}/src/elfcmp ${in_file} ${out_file}
+
+  # Can we add a section (in-place)?
+  testrun ${abs_builddir}/addsections 65535 ${out_file}
+  testrun ${abs_top_builddir}/src/readelf -S ${out_file} > readelf.out
+  nr=$(grep '.extra' readelf.out | wc -l)
+  # We try twice...
+  if test ${nr} != 65535 -a ${nr} != 131070; then
+    # Show what went wrong
+    testrun ${abs_top_builddir}/src/readelf -S ${out_file}
+    exit 1
+  fi
+
+  # Can we copy the file using ELF_C_WRITE_MMAP?
+  testrun ${abs_builddir}/elfcopy --mmap ${in_file} ${out_file_mmap}
+  testrun ${abs_top_builddir}/src/elfcmp ${in_file} ${out_file_mmap}
+
+  # Don't try to add using mmap (see above)
+}
+
+# A collection of random testfiles to test 32/64bit, little/big endian
+# and non-ET_REL (with phdrs)/ET_REL (without phdrs).
+# Try to add 0xffff sections twice.
+
+# 32bit, big endian, rel
+testfiles testfile29
+test_copy_and_add testfile29
+test_copy_and_add testfile29.copy
+
+# 64bit, big endian, rel
+testfiles testfile23
+test_copy_and_add testfile23
+test_copy_and_add testfile23.copy
+
+# 32bit, little endian, rel
+testfiles testfile9
+test_copy_and_add testfile9
+test_copy_and_add testfile9.copy
+
+# 64bit, little endian, rel
+testfiles testfile38
+test_copy_and_add testfile38
+test_copy_and_add testfile38.copy
+
+# 32bit, big endian, non-rel
+testfiles testfile26
+test_copy_and_add testfile26
+test_copy_and_add testfile26.copy
+
+# 64bit, big endian, non-rel
+testfiles testfile27
+test_copy_and_add testfile27
+test_copy_and_add testfile27.copy
+
+# 32bit, little endian, non-rel
+testfiles testfile
+test_copy_and_add testfile
+test_copy_and_add testfile.copy
+
+# 64bit, little endian, non-rel
+testfiles testfile10
+test_copy_and_add testfile10
+test_copy_and_add testfile10.copy
+
+exit 0
-- 
1.8.3.1



More information about the Elfutils-devel mailing list