Fedora Account System
Red Hat Associate
Red Hat Customer
Created attachment 2148200 [details] upstream 93f536d813c, applies to the Fedora tree Created attachment 2148200 [details] upstream 93f536d813c, applies to the Fedora tree Description of problem: gdb in Rawhide crashes on essentially every core file produced by a graphical application. Depending on heap layout it either dies immediately inside core_target::build_file_mappings(), or prints the backtrace and then dies at exit, inside objalloc_free() <- _bfd_delete_bfd() <- bfd_close_all_done() <- gdb_bfd_unref() <- core_target::clear_core() <- core_target::close() during quit_force(). This makes gnome-abrt/abrt unusable: they invoke /usr/libexec/gdb in batch mode to collect a backtrace, and gdb dumps core itself, so the crash of the original application cannot be reported. Version-Release number of selected component: gdb-17.2-1.fc45.x86_64 How reproducible: Always, given a core file with more than 128 distinct file-backed mappings where at least one file is mapped non-contiguously. On a desktop this is the common case: libffi mapped twice via gjs, /dev/dri/card1, memfd:pulseaudio, memfd:wayland-cursor, *.gresource, and so on. Steps to Reproduce: mkdir -p /tmp/m for i in $(seq -w 0 199); do head -c 4096 /dev/urandom > /tmp/m/$i; done cat > repro.c <<'EOF' #include <assert.h> #include <fcntl.h> #include <stdio.h> #include <sys/mman.h> int main(void) { char path[64]; int first = -1; for (int i = 0; i < 200; i++) { snprintf(path, sizeof(path), "/tmp/m/%03d", i); int fd = open(path, O_RDONLY); assert(fd >= 0); if (i == 0) first = fd; void *p = mmap(NULL, 4096, PROT_READ, MAP_PRIVATE, fd, 0); assert(p != MAP_FAILED); } /* second, non-contiguous mapping of file #0, created after the std::vector<core_mapped_file> has reallocated */ void *p = mmap(NULL, 4096, PROT_READ, MAP_PRIVATE, first, 0); assert(p != MAP_FAILED); *(volatile int *)0 = 0; } EOF gcc -g -O0 -o repro repro.c && ./repro coredumpctl -1 dump repro > /tmp/core.repro gdb -nx -batch -iex 'set debuginfod enabled off' ./repro /tmp/core.repro -ex bt Actual results: gdb prints the backtrace and then: Fatal signal: Segmentation fault ----- Backtrace ----- 0x... handle_fatal_signal ../../gdb/event-top.c:1013 0x... handle_sigsegv ../../gdb/event-top.c:1090 0x... objalloc_free ../../libiberty/objalloc.c:186 0x... _bfd_delete_bfd ../../bfd/opncls.c:157 0x... bfd_close_all_done ../../bfd/opncls.c:902 0x... gdb_bfd_close_or_warn ../../gdb/gdb_bfd.c:661 0x... gdb_bfd_unref ../../gdb/gdb_bfd.c:742 0x... core_target::clear_core ../../gdb/corelow.c:600 0x... core_target::close ../../gdb/corelow.c:612 0x... quit_force ../../gdb/top.c:1778 --------------------- A fatal error internal to GDB has been detected, further debugging is not possible. GDB will now terminate. On a real core (gnome-shell) gdb instead segfaults straight away in core_target::build_file_mappings(). Expected results: gdb opens the core file and exits normally. Additional info: This is a Fedora-only regression, not an upstream bug. Vanilla gdb 17.2 keys mapped_files by filename in a map, so references into it stay valid (gdb-17.2-release:gdb/corelow.c:434): mapped_file &file_data = mapped_files[filename]; The downstream patch gdb-backport-dap-core-file-support.patch backports upstream commit fc8e5a565b3 ("gdb: make structured core file mappings processing global"), which replaces that with a std::vector<core_mapped_file> ("results") plus a hash map caching raw pointers into that vector: struct map_entry { core_mapped_file *file_data; bool ignore_build_id_p; }; results.emplace_back() (corelow.c:2141) reallocates the vector and invalidates every file_data pointer already stored in mapped_files. Any later NT_FILE entry naming an already seen file then dereferences a stale pointer at corelow.c:2157 and appends to a freed std::vector<core_mapped_file::region>. The freed regions vector is subsequently read at corelow.c:449, 450, 546, 548, 549, 554 and freed a second time in ~core_mapped_file at corelow.c:582. Upstream fixed exactly this in commit 93f536d813c ("gdb/corelow: Fix use-after-free in gdb_read_core_file_mappings", Lancelot SIX, Approved-By: Andrew Burgess), which stores an index into the vector instead of a pointer. That commit is on master only; it is not in gdb-17-branch and not in any release tag, so it was never picked up alongside the DAP backport. valgrind on gdb-17.2-1.fc45 with the reproducer above (full log attached): ==151732== Invalid read of size 8 ==151732== at emplace_back<...> (vector.tcc:118) ==151732== by operator() (corelow.c:2157) ==151732== by linux_read_core_file_mappings (linux-tdep.c:1237) ==151732== by gdb_read_core_file_mappings (corelow.c:2120) ==151732== by core_target::build_file_mappings() (corelow.c:375) ==151732== Address 0x... is 120 bytes inside a block of size 144 free'd ==151732== at operator delete(void*, unsigned long) ==151732== by _M_realloc_append<> (vector.tcc:649) ==151732== by emplace_back<> (vector.tcc:127) ==151732== by operator() (corelow.c:2141) [...] ==151732== Invalid free() / delete / delete[] / realloc() ==151732== by ~core_mapped_file (gdbcore.h:264) ==151732== by core_target::build_file_mappings() (corelow.c:582) ==151732== ERROR SUMMARY: 14 errors from 14 contexts (suppressed: 0 from 0) Proposed fix: add upstream 93f536d813c as a downstream patch on top of gdb-backport-dap-core-file-support.patch. Patch attached (gdb-corelow-uaf-fix.patch, produced with git format-patch). I verified it: a local rebuild as gdb-17.2-2.fc45 applies the patch cleanly (patch -p1 --fuzz=0) and builds without new warnings under --enable-werror. With it installed: ==571955== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) gdb opens both the reproducer core and the gnome-shell core normally, and gnome-abrt works again.
Created attachment 2148201 [details] reproducer
Created attachment 2148202 [details] valgrind, gdb-17.2-1.fc45, 14 errors
Created attachment 2148203 [details] valgrind, gdb-17.2-2.fc45 (patched), 0 errors
Created attachment 2148407 [details] Full coredumpctl backtrace on gdb-17.2-1.fc44 / plasma-workspace-6.7.2-2.fc44 Confirming on gdb-17.2-1.fc44 / plasma-workspace-6.7.2-2.fc44 (Fedora 44, KDE Wayland session), with a full (non-reduced) backtrace obtained via `coredumpctl info`. The actual crash is NOT inside the brightness applet itself, but is a downstream consequence: onServiceUnregistered() sets m_isBrightnessAvailable to false, which propagates through Qt's property binding system (QPropertyBindingData::notifyObservers -> QQmlBinding::update -> Plasma::Applet::statusChanged), which in turn triggers the system tray's SortedSystemTrayModel to reorder (needsReorder -> lessThan -> PlasmoidModel::data -> Plasma::Applet::status()). The actual SIGSEGV happens inside Plasma::Applet::status(), called on what is presumably an already partially-destroyed applet, since this whole chain fires from inside ShellCorona::~ShellCorona() during session shutdown. Full backtrace attached (plasmashell-full-backtrace.txt).
I can reproduce this on Fedora 44 as well. Package: gdb-17.2-1.fc44.x86_64 Environment: Fedora 44 x86_64 Kernel: 7.1.3-200.fc44.x86_64 When opening a systemsettings ELF core file with debuginfod disabled: /usr/bin/gdb --nw --nx --batch \ --init-eval-command='set debuginfod enabled off' \ --core=/path/to/systemsettings.core \ /usr/bin/systemsettings GDB aborts with: free(): double free detected in tcache 2 The backtrace includes: malloc_printerr tcache_double_free_verify core_target::build_file_mappings() core_target::core_target() I have also observed SIGSEGV in core_target::build_file_mappings. readelf and eu-stack can parse the same core file successfully. The core file has not been attached because it may contain private process memory. I can provide it privately if needed.
*** This bug has been marked as a duplicate of bug 2498034 ***