diff options
| author | Aaron Merey <[email protected]> | 2023-11-21 08:56:44 -0500 |
|---|---|---|
| committer | Aaron Merey <[email protected]> | 2023-11-21 08:56:44 -0500 |
| commit | 2f38fa57942f95a9ada35e6802df864747c81cce (patch) | |
| tree | b0d26ced64ca7efbbdcd3ba1954fa32629ce6329 /tests | |
| parent | e54af3a5a78dd9e0502a9ac4050098f6d8ed6506 (diff) | |
libdwfl: Correctly handle corefile non-contiguous segments
It is possible for segments of different shared libaries to be interleaved
in memory such that the segments of one library are located in between
non-contiguous segments of another library.
For example, this can be seen with firefox on RHEL 7.9 where multiple
shared libraries could be mapped in between ld-2.17.so segments:
[...]
7f0972082000-7f09720a4000 00000000 139264 /usr/lib64/ld-2.17.so
7f09720a4000-7f09720a5000 00000000 4096 /memfd:mozilla-ipc (deleted)
7f09720a5000-7f09720a7000 00000000 8192 /memfd:mozilla-ipc (deleted)
7f09720a7000-7f09720a9000 00000000 8192 /memfd:mozilla-ipc (deleted)
7f0972134000-7f0972136000 00000000 8192 /usr/lib64/firefox/libmozwayland.so
7f0972136000-7f0972137000 00002000 4096 /usr/lib64/firefox/libmozwayland.so
7f0972137000-7f0972138000 00003000 4096 /usr/lib64/firefox/libmozwayland.so
7f0972138000-7f0972139000 00003000 4096 /usr/lib64/firefox/libmozwayland.so
7f097213a000-7f0972147000 00000000 53248 /usr/lib64/firefox/libmozsqlite3.so
7f0972147000-7f097221e000 0000d000 880640 /usr/lib64/firefox/libmozsqlite3.so
7f097221e000-7f0972248000 000e4000 172032 /usr/lib64/firefox/libmozsqlite3.so
7f0972248000-7f0972249000 0010e000 4096 /usr/lib64/firefox/libmozsqlite3.so
7f0972249000-7f097224c000 0010e000 12288 /usr/lib64/firefox/libmozsqlite3.so
7f097224c000-7f0972250000 00111000 16384 /usr/lib64/firefox/libmozsqlite3.so
7f0972250000-7f0972253000 00000000 12288 /usr/lib64/firefox/liblgpllibs.so
[...]
7f09722a3000-7f09722a4000 00021000 4096 /usr/lib64/ld-2.17.so
7f09722a4000-7f09722a5000 00022000 4096 /usr/lib64/ld-2.17.so
dwfl_segment_report_module did not account for the possibility of
interleaving non-contiguous segments, resulting in premature closure
of modules as well as failing to report modules.
Fix this by removing segment skipping in dwfl_segment_report_module.
When dwfl_segment_report_module reported a module, it would return
the index of the segment immediately following the end address of the
current module. Since there's a chance that other modules might fall
within this address range, dwfl_segment_report_module instead returns
the index of the next segment.
This patch also fixes premature module closure that can occur in
dwfl_segment_report_module when interleaving non-contiguous segments
are found. Previously modules with start and end addresses that overlap
with the current segment would have their build-ids compared with the
current segment's build-id. If there was a mismatch, that module would
be closed. Avoid closing modules in this case when mismatching build-ids
correspond to distinct modules.
https://sourceware.org/bugzilla/show_bug.cgi?id=30975
Signed-off-by: Aaron Merey <[email protected]>
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/.gitignore | 1 | ||||
| -rw-r--r-- | tests/Makefile.am | 8 | ||||
| -rw-r--r-- | tests/dwfl-core-noncontig.c | 82 | ||||
| -rwxr-xr-x | tests/run-dwfl-core-noncontig.sh | 63 | ||||
| -rw-r--r-- | tests/testcore-noncontig.bz2 | bin | 0 -> 54684 bytes |
5 files changed, 151 insertions, 3 deletions
diff --git a/tests/.gitignore b/tests/.gitignore index b9aa22ba..5bebb2c4 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -49,6 +49,7 @@ /dwfl-report-elf-align /dwfl-report-offline-memory /dwfl-report-segment-contiguous +/dwfl-core-noncontig /dwfllines /dwflmodtest /dwflsyms diff --git a/tests/Makefile.am b/tests/Makefile.am index 80f6cb59..2373c980 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -42,7 +42,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \ dwfl-bug-addr-overflow arls dwfl-bug-fd-leak \ dwfl-addr-sect dwfl-bug-report early-offscn \ dwfl-bug-getmodules dwarf-getmacros dwarf-ranges addrcfi \ - dwarfcfi \ + dwfl-core-noncontig dwarfcfi \ test-flag-nobits dwarf-getstring rerequest_tag \ alldts typeiter typeiter2 low_high_pc \ test-elf_cntl_gelf_getshdr dwflsyms dwfllines \ @@ -212,7 +212,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \ $(asm_TESTS) run-disasm-bpf.sh run-low_high_pc-dw-form-indirect.sh \ run-nvidia-extended-linemap-libdw.sh run-nvidia-extended-linemap-readelf.sh \ run-readelf-dw-form-indirect.sh run-strip-largealign.sh \ - run-readelf-Dd.sh + run-readelf-Dd.sh run-dwfl-core-noncontig.sh if !BIARCH export ELFUTILS_DISABLE_BIARCH = 1 @@ -633,7 +633,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \ testfile_nvidia_linemap.bz2 \ testfile-largealign.o.bz2 run-strip-largealign.sh \ run-funcretval++11.sh \ - test-ar-duplicates.a.bz2 + test-ar-duplicates.a.bz2 \ + run-dwfl-core-noncontig.sh testcore-noncontig.bz2 if USE_VALGRIND @@ -739,6 +740,7 @@ dwfl_bug_fd_leak_LDADD = $(libeu) $(libdw) $(libebl) $(libelf) dwfl_bug_report_LDADD = $(libdw) $(libebl) $(libelf) dwfl_bug_getmodules_LDADD = $(libeu) $(libdw) $(libebl) $(libelf) dwfl_addr_sect_LDADD = $(libeu) $(libdw) $(libebl) $(libelf) $(argp_LDADD) +dwfl_core_noncontig_LDADD = $(libdw) $(libelf) dwarf_getmacros_LDADD = $(libdw) dwarf_ranges_LDADD = $(libdw) dwarf_getstring_LDADD = $(libdw) diff --git a/tests/dwfl-core-noncontig.c b/tests/dwfl-core-noncontig.c new file mode 100644 index 00000000..04558e28 --- /dev/null +++ b/tests/dwfl-core-noncontig.c @@ -0,0 +1,82 @@ +/* Test program for dwfl_getmodules bug. + Copyright (C) 2008 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/>. */ + +#include <config.h> +#include <stdio.h> +#include <fcntl.h> +#include <assert.h> +#include ELFUTILS_HEADER(dwfl) +#include ELFUTILS_HEADER(elf) + +static const Dwfl_Callbacks cb = +{ + NULL, + NULL, + NULL, + NULL, +}; + +int +main (int argc, char **argv) +{ + assert (argc == 2); + + Dwfl *dwfl = dwfl_begin (&cb); + + int fd = open (argv[1], O_RDONLY); + assert (fd != -1); + + Elf *elf = elf_begin (fd, ELF_C_READ, NULL); + (void) dwfl_core_file_report (dwfl, elf, argv[0]); + + /* testcore-noncontig contains a shared library mapped between + non-contiguous segments of another shared library: + + [...] + 7f14e458c000-7f14e45ae000 00000000 139264 /usr/lib64/ld-2.17.so (1) + 7f14e4795000-7f14e4798000 00000000 12288 /usr/lib64/firefox/liblgpllibs.so (2) + 7f14e4798000-7f14e479d000 00003000 20480 /usr/lib64/firefox/liblgpllibs.so + 7f14e479d000-7f14e479f000 00008000 8192 /usr/lib64/firefox/liblgpllibs.so + 7f14e479f000-7f14e47a0000 00009000 4096 /usr/lib64/firefox/liblgpllibs.so + 7f14e47a0000-7f14e47a1000 0000a000 4096 /usr/lib64/firefox/liblgpllibs.so (3) + 7f14e47ad000-7f14e47ae000 00021000 4096 /usr/lib64/ld-2.17.so (4) + 7f14e47ae000-7f14e47af000 00022000 4096 /usr/lib64/ld-2.17.so */ + + /* First segment of the non-contiguous module (1). */ + int seg = dwfl_addrsegment (dwfl, 0x7f14e458c000, NULL); + assert (seg == 32); + + /* First segment of the module within the non-contiguous module's address + range (2). */ + seg = dwfl_addrsegment (dwfl, 0x7f14e4795000, NULL); + assert (seg == 33); + + /* Last segment of the module within the non-contiguous module's + address range (3). */ + seg = dwfl_addrsegment (dwfl, 0x7f14e47a0000, NULL); + assert (seg == 37); + + /* First segment of non-contiguous module following its address space + gap (4). */ + seg = dwfl_addrsegment (dwfl, 0x7f14e47ad000, NULL); + assert (seg == 40); + + dwfl_end (dwfl); + elf_end (elf); + + return 0; +} diff --git a/tests/run-dwfl-core-noncontig.sh b/tests/run-dwfl-core-noncontig.sh new file mode 100755 index 00000000..1245b67f --- /dev/null +++ b/tests/run-dwfl-core-noncontig.sh @@ -0,0 +1,63 @@ +#! /bin/sh +# Copyright (C) 2023 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/>. + +. $srcdir/test-subr.sh + +# Test whether libdwfl can handle corefiles containing non-contiguous +# segments where multiple modules are contained within the address +# space of some other module. + +# testcore-noncontig was generated from the following program with +# systemd-coredump on RHEL 7.9 Workstation, kernel +# 3.10.0-1160.105.1.el7.x86_64. liblgpllibs.so was packaged with +# firefox-115.4.0-1.el7_9.x86_64.rpm. + +# #include <unistd.h> +# #include <dlfcn.h> +# +# int main () { +# dlopen ("/usr/lib64/firefox/liblgpllibs.so", RTLD_GLOBAL | RTLD_NOW); +# sleep (60); +# return 0; +# } +# +# gcc -ldl -o test test.c + +tempfiles out +testfiles testcore-noncontig + +testrun ${abs_builddir}/dwfl-core-noncontig testcore-noncontig + +# Remove parts of the output that could change depending on which +# libraries are locally installed. +testrun ${abs_top_builddir}/src/unstrip -n --core testcore-noncontig \ + | sed 's/+/ /g' | cut -d " " -f1,3 | sort > out + +testrun_compare cat out <<\EOF +0x400000 3a1748a544b40a38b3be3d2d13ffa34a2a5a71c0@0x400284 +0x7f14e357e000 edf51350c7f71496149d064aa8b1441f786df88a@0x7f14e357e1d8 +0x7f14e3794000 7615604eaf4a068dfae5085444d15c0dee93dfbd@0x7f14e37941d8 +0x7f14e3a96000 09cfb171310110bc7ea9f4476c9fa044d85baff4@0x7f14e3a96210 +0x7f14e3d9e000 e10cc8f2b932fc3daeda22f8dac5ebb969524e5b@0x7f14e3d9e248 +0x7f14e3fba000 fc4fa58e47a5acc137eadb7689bce4357c557a96@0x7f14e3fba280 +0x7f14e4388000 7f2e9cb0769d7e57bd669b485a74b537b63a57c4@0x7f14e43881d8 +0x7f14e458c000 62c449974331341bb08dcce3859560a22af1e172@0x7f14e458c1d8 +0x7f14e4795000 175efdcef445455872a86a6fbee7567ca16a513e@0x7f14e4795248 +0x7ffcfe59f000 80d79b32785868a2dc10047b39a80d1daec8923d@0x7ffcfe59f328 +EOF + +exit 0 diff --git a/tests/testcore-noncontig.bz2 b/tests/testcore-noncontig.bz2 Binary files differnew file mode 100644 index 00000000..514ad010 --- /dev/null +++ b/tests/testcore-noncontig.bz2 |
