Re: [PATCH] libdw: check offset dwarf_formstring in all cases
Hi Aleksei, On Thu, 2023-11-16 at 21:29 +, vvv...@google.com wrote: > This check was initially added to test if offset overflows the safe > prefix where any string will be null-terminated. However the check > was placed in a wrong place and didn't cover all `attrp->form` cases. > > * libdw/dwarf_formstring.c (dwarf_formstring): Move offset check > right before returning the result. Oops. I see how this happened for DW_FORM_strp and DW_FORM_line_strp we use __libdw_read_offset which already check the section offset. But of course those use d_size, not the string_section_size that was setup in elf_begin_elf. So the check is also needed for them. > Signed-off-by: Aleksei Vetrov > --- > libdw/dwarf_formstring.c | 6 +++--- > 1 file changed, 3 insertions(+), 3 deletions(-) > > diff --git a/libdw/dwarf_formstring.c b/libdw/dwarf_formstring.c > index 0ee42411..65f03a5e 100644 > --- a/libdw/dwarf_formstring.c > +++ b/libdw/dwarf_formstring.c > @@ -173,11 +173,11 @@ dwarf_formstring (Dwarf_Attribute *attrp) > off = read_4ubyte_unaligned (dbg, datap); >else > off = read_8ubyte_unaligned (dbg, datap); > - > - if (off >= data_size) > - goto invalid_offset; > } > > + if (off >= data_size) > +goto invalid_offset; > + >return (const char *) data->d_buf + off; > } > INTDEF(dwarf_formstring) Applied. Thanks, Mark
☺ Buildbot (Sourceware): elfutils - build successful (main)
A restored build has been detected on builder elfutils-debian-testing-x86_64 while building elfutils. Full details are available at: https://builder.sourceware.org/buildbot/#builders/145/builds/218 Build state: build successful Revision: 1bd9deb9aa19ac2e2fa9665009e0d5924adcf4d3 Worker: bb2-1 Build Reason: (unknown) Blamelist: Aleksei Vetrov , Frank Ch. Eigler Steps: - 0: worker_preparation ( success ) - 1: set package name ( success ) - 2: git checkout ( success ) Logs: - stdio: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/2/logs/stdio - 3: autoreconf ( success ) Logs: - stdio: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/3/logs/stdio - 4: configure ( success ) Logs: - stdio: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/4/logs/stdio - config.log: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/4/logs/config_log - 5: get version ( success ) Logs: - stdio: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/5/logs/stdio - property changes: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/5/logs/property_changes - 6: make ( warnings ) Logs: - stdio: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/6/logs/stdio - warnings (3): https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/6/logs/warnings__3_ - 7: make check ( success ) Logs: - stdio: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/7/logs/stdio - test-suite.log: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/7/logs/test-suite_log - 8: make distcheck ( warnings ) Logs: - stdio: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/8/logs/stdio - test-suite.log: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/8/logs/test-suite_log - warnings (4): https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/8/logs/warnings__4_ - 9: prep ( success ) Logs: - stdio: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/9/logs/stdio - 10: build bunsen.cpio.gz ( success ) Logs: - stdio: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/10/logs/stdio - 11: fetch bunsen.cpio.gz ( success ) Logs: - stdio: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/11/logs/stdio - 12: unpack bunsen.cpio.gz ( success ) Logs: - stdio: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/12/logs/stdio - 13: pass .bunsen.source.gitname ( success ) Logs: - stdio: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/13/logs/stdio - 14: pass .bunsen.source.gitdescribe ( success ) Logs: - stdio: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/14/logs/stdio - 15: pass .bunsen.source.gitbranch ( success ) Logs: - stdio: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/15/logs/stdio - 16: pass .bunsen.source.gitrepo ( success ) Logs: - stdio: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/16/logs/stdio - 17: upload to bunsen ( success ) Logs: - stdio: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/17/logs/stdio - 18: clean up ( success ) Logs: - stdio: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/18/logs/stdio - 19: make distclean ( success ) Logs: - stdio: https://builder.sourceware.org/buildbot/#builders/145/builds/218/steps/19/logs/stdio
[PATCH 1/2] libdwfl: handle duplicate ELFs when reporting archives
From: Aleksei Vetrov When archive is processed in process_archive (libdwfl/offline.c), it creates an Elf object for each archive member. Then in process_archive_member it calls process_file to create a Dwfl_Module through __libdwfl_report_elf. The ownership of the Elf object is expected to be: * either transfered to the Dwfl_Module, if __libdwfl_report_elf returns not NULL; * or handled at the end of process_archive_member by calling elf_end. Moreover, Elf object is expected to be alive, if __libdwfl_report_elf returns not NULL, because at the end of process_archive_member it advances to the next member through the elf_next call. The problem happens when __libdwfl_report_elf encounters Elf with the same name and content as it seen before. In that case dwfl_report_module will reuse existing Dwfl_Module object. This leads to a codepath that calls elf_end on the Elf object, while returning not NULL, breaking the elf_next call to the next member. The fix is to destroy m->main.elf instead and put the new Elf object in the already existing Dwfl_Module. * libdwfl/dwfl_report_elf.c (__libdwfl_report_elf): Replace Elf in the Dwfl_Module in case of overlapping or duplicate modules to prolong its lifetime for subsequent processing. Signed-off-by: Aleksei Vetrov --- libdwfl/dwfl_report_elf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libdwfl/dwfl_report_elf.c b/libdwfl/dwfl_report_elf.c index 581f4079..58b06aea 100644 --- a/libdwfl/dwfl_report_elf.c +++ b/libdwfl/dwfl_report_elf.c @@ -276,7 +276,8 @@ __libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name, } else { - elf_end (elf); + elf_end (m->main.elf); + m->main.elf = elf; if (m->main_bias != bias || m->main.vaddr != vaddr || m->main.address_sync != address_sync) goto overlap; -- 2.43.0.rc1.413.gea7ed67945-goog
[PATCH 2/2] tests: Add test for duplicate entries in archive
From: Aleksei Vetrov Test dwfl-report-offline-memory against an archive that contains non-relocatable ELFs with the same name and contents. Signed-off-by: Aleksei Vetrov --- tests/run-dwfl-report-offline-memory.sh | 7 +++ tests/test-ar-duplicates.a.bz2 | Bin 0 -> 783 bytes 2 files changed, 7 insertions(+) create mode 100644 tests/test-ar-duplicates.a.bz2 diff --git a/tests/run-dwfl-report-offline-memory.sh b/tests/run-dwfl-report-offline-memory.sh index 644a45dc..85f43f53 100755 --- a/tests/run-dwfl-report-offline-memory.sh +++ b/tests/run-dwfl-report-offline-memory.sh @@ -20,7 +20,14 @@ testfiles testfile-dwfl-report-elf-align-shlib.so testfiles testarchive64.a +# echo "int _start(void) { return 0; }" > test.c +# gcc test.c -nostdlib -static -o test.o +# ar -r test-ar-duplicates.a test.o test.o test.o +# bzip2 -zf test-ar-duplicates.a +testfiles test-ar-duplicates.a + testrun ${abs_builddir}/dwfl-report-offline-memory ./testfile-dwfl-report-elf-align-shlib.so 1 testrun ${abs_builddir}/dwfl-report-offline-memory ./testarchive64.a 3 +testrun ${abs_builddir}/dwfl-report-offline-memory ./test-ar-duplicates.a 1 exit 0 diff --git a/tests/test-ar-duplicates.a.bz2 b/tests/test-ar-duplicates.a.bz2 new file mode 100644 index ..e8168c6bb813bb05292372d6b856e2ca1163a835 GIT binary patch literal 783 zcmV+q1MvJpT4*^jL0KkKS*O-t`~U>U|NsC0^v!1T{dI5Uazg*-o^**RKmrI*1V9J? z0RUpbpefJ;J^%m!H~;_|001&HG5`Po00EJZ00u$8007Vc0g<7Q042*yPG7bO$ z27mwzjSPSQ0001FWB>t>Z~y=_003lYWB>pF00Sc+01Sb>Qb4DoG|(YN(+YV{O*J>F zZ891m=`tHrY3VgR0F2UlO|*o0s(PNL3ovPT-FWk=B;Jux%~F)fXQs4SQOt9gyiE>j zn6Ga(89!@GYHl-L-dxbs$}&@+(DyVdX=!IB!kuQ))6nI$Da(vh*7{bCREV6#KNqm! zdu&Mb+M`10By`;OIdVe?-cr&jN>kKstt5_(4hBpYI!%S0RYq!zoTdw-r};8m5SuEI zu&BS|S>97Ll_Ks%qWX~|eNFX2+)(wDko6K&h@AyU+*7EjB0KJbX(i2-NWr+XprTIu zB%S!mUnj<+n4}YmKId7>S^5_w!Fy?EWo4tTvdK6U;gV9C5?V$|i8mD;#XsVDVQ%g0=kvP>JW-B*XEa@sbQG}Le!OvXnKQ+tOr1|<*S=e&p2DS+rYDV*_vs1e6 zu1U>irf%B#9wjbP_72;9ds3ZsFn8O_*f5OUXClse^_%iUp6rvfsXM*Jq^>8z@U|Q6 z*J1OxE^e`H$%>n8wk=MZHxzfH?{*p^+fvGr{$BN;1J#puO|@+L>>t^ZP1xPOJkJDd zG&~LmIfeUCo0!>Vz3RBGUhvbk7`3dlX0%-$MeRv3e^oYHE+>J;`q?pM6W?@SQ#QEc ze~0GQ%}g2{wdp?SsT`$F_Z(%Ds5sw)!*Wg-`sD8<;cAYoXHLwT6*G9*M;hmeoNOvD zUXsh63|o(x!uDHDwwJQbnE~C literal 0 HcmV?d1 -- 2.43.0.rc1.413.gea7ed67945-goog
[PATCH v2] libdwfl: Correctly handle corefile non-contiguous segments
v1: https://sourceware.org/pipermail/elfutils-devel/2023q4/006644.html v2 changes: The size of the uncompressed testcore-noncontig has been reduced from 736M to 54K. dwfl_addrsegment tests have been added to verify correct handling of non-contiguous segments. --- libdwfl/dwfl_segment_report_module.c | 37 ++- tests/.gitignore | 1 + tests/Makefile.am| 8 ++-- tests/dwfl-core-noncontig.c | 67 +++ tests/run-dwfl-core-noncontig.sh | 63 + tests/testcore-noncontig.bz2 | Bin 0 -> 54684 bytes 6 files changed, 162 insertions(+), 14 deletions(-) create mode 100644 tests/dwfl-core-noncontig.c create mode 100755 tests/run-dwfl-core-noncontig.sh create mode 100644 tests/testcore-noncontig.bz2 diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c index 3ef62a7d..09ee37b3 100644 --- a/libdwfl/dwfl_segment_report_module.c +++ b/libdwfl/dwfl_segment_report_module.c @@ -737,17 +737,34 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, && invalid_elf (module->elf, module->disk_file_has_build_id, &build_id)) { - elf_end (module->elf); - close (module->fd); - module->elf = NULL; - module->fd = -1; + /* If MODULE's build-id doesn't match the disk file's + build-id, close ELF only if MODULE and ELF refer to + different builds of files with the same name. This + prevents premature closure of the correct ELF in cases + where segments of a module are non-contiguous in memory. */ + if (name != NULL && module->name[0] != '\0' + && strcmp (basename (module->name), basename (name)) == 0) + { + elf_end (module->elf); + close (module->fd); + module->elf = NULL; + module->fd = -1; + } } - if (module->elf != NULL) + else if (module->elf != NULL) { - /* Ignore this found module if it would conflict in address - space with any already existing module of DWFL. */ + /* This module has already been reported. */ skip_this_module = true; } + else + { + /* Only report this module if we haven't already done so. */ + for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; +mod = mod->next) + if (mod->low_addr == module_start + && mod->high_addr == module_end) + skip_this_module = true; + } } if (skip_this_module) goto out; @@ -781,10 +798,6 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, } } - /* Our return value now says to skip the segments contained - within the module. */ - ndx = addr_segndx (dwfl, segment, module_end, true); - /* Examine its .dynamic section to get more interesting details. If it has DT_SONAME, we'll use that as the module name. If it has a DT_DEBUG, then it's actually a PIE rather than a DSO. @@ -929,6 +942,8 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, ndx = -1; goto out; } + else +ndx++; /* We have reported the module. Now let the caller decide whether we should read the whole thing in right now. */ 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 7fb8efb1..9f8f7698 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-