View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0000659 | AlmaLinux-9 | rpm | public | 2026-07-29 15:38 | 2026-07-29 15:38 |
| Reporter | nerdsite | Assigned To | |||
| Priority | normal | Severity | crash | Reproducibility | always |
| Status | new | Resolution | open | ||
| Platform | x86_64 | OS | Almalinux | OS Version | 9.8 |
| Summary | 0000659: dnf/rpm segfault via use-after-free in sqlite log callback (history.sqlite) | ||||
| Description | `dnf` intermittently segfaults when opening `/var/lib/dnf/history.sqlite` (and potentially any other sqlite database opened after the rpmdb) with a `Segmentation fault (core dumped)`. This is caused by a known upstream rpm bug: rpm registers a **process-global** sqlite log callback (`sqlite3_config(SQLITE_CONFIG_LOG, errCb, rdb)`) tied to a specific `rpmdb` handle. If that handle is later freed and a *different* sqlite database (e.g. `history.sqlite`) triggers a log message (commonly a WAL-recovery notice), sqlite invokes the stale callback and dereferences freed memory, causing a crash. Upstream rpm fixed this by removing the callback entirely: https://github.com/rpm-software-management/rpm/commit/ea3187cfcf9cac87e5bc5e7db79b0338da9e355e This fix does not appear to be present in `rpm-4.16.1.3-40.el9` (see "Verification" below). ## Environment - OS: AlmaLinux 9 (AlmaLinux release 9.8 (Olive Jaguar)) - `rpm -q rpm`: `rpm-4.16.1.3-40.el9.x86_64` - `rpm -q sqlite-libs`: `sqlite-libs-3.46.1-1.el9.x86_64` - `rpm -q dnf python3-libdnf`: `libdnf-0.69.0-18.el9.alma.1`, dnf version (dnf-0:4.14.0-34.el9_8.alma.1.noarch) Related thread: https://forums.almalinux.org/t/dnf-segmentation-fault-core-dumped/5528/3 | ||||
| Steps To Reproduce | 1. Run `dnf update` or any `dnf install`/`dnf upgrade` operation. 2. dnf segfaults (`Segmentation fault (core dumped)`) while opening `/var/lib/dnf/history.sqlite`. 3. Running `echo 'PRAGMA integrity_check;' | sudo sqlite3 /var/lib/dnf/history.sqlite` or `dnf clean all` "fixes" the crash temporarily by forcing a clean WAL checkpoint outside of dnf's process — but the crash returns once `history.sqlite` accumulates new WAL frames that need recovery inside dnf. 4. This has been recurring for over a year and survives `rpmdb --rebuilddb` and reinstalling dnf/rpm, since the bug is in rpm's sqlite backend, not in the database file itself. Note: setting `--setopt=history_record=false` does **not** reliably avoid the crash, since dnf's `Swdb`/history layer still opens `history.sqlite` to read it even when it isn't recording new history. | ||||
| Additional Information | ## Verification ``` $ rpm -q rpm --changelog | grep -i -A2 sqlite (no output — no changelog entry referencing the sqlite3_config/log-callback fix) ``` ## Backtrace (full symbols, from `coredumpctl gdb` + `bt full`) Core generated by `/usr/bin/dnf /usr/bin/dnf install gdb --setopt=history_record=false`. Key frames (top of stack down through the trigger): ``` #0 __strlen_evex () at ../sysdeps/x86_64/multiarch/strlen-evex.S:77 #1 0x00007fd533661508 in __vfprintf_internal (format=0x7fd53226f215 "%s: %s: %s\n", ...) at vfprintf-internal.c:1655 string = 0x11e <error: Cannot access memory at address 0x11e> 0000002 0x00007fd5336806ba in __vsnprintf_internal (...) at vsnprintf.c:114 0000003 0x00007fd53371ed32 in ___vsnprintf_chk (...) at vsnprintf_chk.c:34 0000004 0x00007fd5321e6388 in vsnprintf (...) at /usr/include/bits/stdio2.h:68 0000005 rpmlog (code=4, fmt=0x7fd53226f215 "%s: %s: %s\n") at /usr/src/debug/rpm-4.16.1.3-40.el9.x86_64/rpmio/rpmlog.c:421 0000006 0x00007fd532088c96 in renderLogMsg () at /lib64/libsqlite3.so.0 0000007 0x00007fd532088d82 in sqlite3_log () at /lib64/libsqlite3.so.0 0000008 0x00007fd532095d78 in walIndexReadHdr () at /lib64/libsqlite3.so.0 0000009 0x00007fd53209642b in walTryBeginRead () at /lib64/libsqlite3.so.0 0000010 0x00007fd532097900 in sqlite3PagerSharedLock.lto_priv.0 () at /lib64/libsqlite3.so.0 0000011 0x00007fd53209d658 in btreeBeginTrans.lto_priv.0 () at /lib64/libsqlite3.so.0 0000012 0x00007fd5320ed321 in sqlite3InitOne.lto_priv.0 () at /lib64/libsqlite3.so.0 ... 0000022 0x00007fd532790aa2 in SQLite3::exec (this=0x555b2e10c880, ...) at libdnf-0.69.0-18.el9.alma.1.x86_64/libdnf/.../Sqlite3.hpp:347 0000023 0x00007fd5327cd35d in SQLite3::open (this=0x555b2e10c880) at libdnf-0.69.0-18.el9.alma.1.x86_64/libdnf/utils/sqlite3/Sqlite3.cpp:43 0000024 0x00007fd532791d98 in SQLite3::SQLite3 (dbPath="/var/lib/dnf/history.sqlite", ...) at libdnf-.../Sqlite3.hpp:334 ... 0000033 libdnf::Swdb::Swdb (this=0x555b2e4bdef0, path="/var/lib/dnf/history.sqlite", ...) at libdnf-0.69.0-18.el9.alma.1.x86_64/libdnf/transaction/Swdb.cpp:89 ``` (Full untrimmed `bt full` output available on request — omitted here for length.) ### Why this confirms the known bug - `rpmlog(code=4, fmt="%s: %s: %s\n")` at frame `0000005` matches the literal format string used by rpm's removed `errCb()`: ```c static void errCb(void *data, int err, const char *msg) { rpmdb rdb = data; rpmlog(RPMLOG_WARNING, "%s: %s: %s\n", rdb->db_descr, sqlite3_errstr(err), msg); } ``` - Frames `0000006-0000009` show sqlite recovering a WAL index (`walIndexReadHdr` / `walTryBeginRead`) and calling `sqlite3_log()` to report it — the normal, harmless trigger for the log callback. - Frame `#1` shows `string = 0x11e`, an invalid near-null pointer being passed as a `%s` argument — consistent with reading a freed `rpmdb->db_descr` via the stale global callback. - Frames `0000022-0000033` confirm this happened while dnf's `Swdb` (software transaction database) was opening `/var/lib/dnf/history.sqlite`, i.e. a *different* sqlite database than the rpmdb the callback was originally registered for. This is the exact mechanism described in the upstream rpm PR discussion: https://github.com/rpm-software-management/rpm/pull/2553 — "the callback can easily end up pointing to an already closed database, causing an innocent API user to crash in librpm on an entirely unrelated error on some other database." Related upstream report with the same signature (Fedora, sqlite 3.42): https://github.com/rpm-software-management/libdnf/issues/1603 ## Suggested fix Backport upstream rpm commit `ea3187cfcf9cac87e5bc5e7db79b0338da9e355e` ("Don't muck with per-process global sqlite configuration from the db backend") into the AlmaLinux 9 rpm package. It removes the offending `sqlite3_config(SQLITE_CONFIG_LOG, errCb, rdb)` call and the `errCb` function entirely — an 8-line removal with no other functional changes. ## Related discussion - AlmaLinux forum thread (same symptoms, unresolved, auto-closed after 1 year): https://forums.almalinux.org/t/dnf-segmentation-fault-core-dumped/5528 - Upstream libdnf issue: https://github.com/rpm-software-management/libdnf/issues/1603 - Upstream rpm fix PR: https://github.com/rpm-software-management/rpm/pull/2553 | ||||
| Tags | No tags attached. | ||||
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2026-07-29 15:38 | nerdsite | New Issue |