summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Wielaard <mark@klomp.org>2018-09-12 23:38:28 +0200
committerMark Wielaard <mark@klomp.org>2018-09-13 14:30:30 +0200
commit34534cc1740b198b8999dcf97222940a130905ce (patch)
treeef28e793954155f6a5de14e4e49b0dd30b3c8226
parentbe4ea50a689dcfdb46079f8f5ce616107a77cdc4 (diff)
libelf: Fix shnum and section zero handling.
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>
-rw-r--r--libelf/ChangeLog6
-rw-r--r--libelf/elf32_updatefile.c2
-rw-r--r--libelf/elf_getscn.c33
-rw-r--r--tests/ChangeLog6
-rw-r--r--tests/Makefile.am4
-rwxr-xr-xtests/run-copymany-sections.sh99
6 files changed, 147 insertions, 3 deletions
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index 35421222..be37ab60 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 545ce083..f2e9a288 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 9f7213b4..e1fbaaaa 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 57098578..7668a661 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 e0edef0c..fc7d7bc6 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 00000000..84c052c9
--- /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