]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libelf: Fix shnum and section zero handling.
authorMark Wielaard <mark@klomp.org>
Wed, 12 Sep 2018 21:38:28 +0000 (23:38 +0200)
committerMark Wielaard <mark@klomp.org>
Thu, 13 Sep 2018 12:30:30 +0000 (14:30 +0200)
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
libelf/elf32_updatefile.c
libelf/elf_getscn.c
tests/ChangeLog
tests/Makefile.am
tests/run-copymany-sections.sh [new file with mode: 0755]

index 35421222479c78092a33c9c529a797f51cb5bdf5..be37ab6081ecc947605edd03d2533236783c3e98 100644 (file)
@@ -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.
index 545ce083d82d93513305bab6184223c8349278db..f2e9a2889e459e5731a5cae198fe9b7063423622 100644 (file)
@@ -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];
index 9f7213b46f4f0cc858313ca23600b6da0c96b7db..e1fbaaaaebb34cbe9a73fa0eef2c9b04e20c74f5 100644 (file)
@@ -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;
index 57098578952ef5138d836846c736ea218644b1f4..7668a661affea5738580d46463c9c054608798a7 100644 (file)
@@ -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.
index e0edef0c7aee7eb603cbca2615bc117cb0217970..fc7d7bc6897bd54bd88f3d9a077398c5e3006c76 100644 (file)
@@ -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 (executable)
index 0000000..84c052c
--- /dev/null
@@ -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