REDHAT-BUG-2525602: Medium severity libsolv libsolv vulnerability

Published Aug 28, 2026
·
Updated

libsolv is a dependency-resolution library used by dnf/libdnf, zypper/libzypp, and other RPM-based package managers. It serializes parsed repository metadata into a binary cache format (.solv files) to avoid re-parsing repository XML on every run. repowrite() (src/repowrite.c) rewrites such a cache from an in-memory Repo/Repodata, in two passes: pass 1 (collectneededcb) collects which directory ids are used, and pass 2 (collectdatacb / collectfilelistcb) emits the serialized data.

Root cause: in collectneededcb() (src/repowrite.c:614-683), for REPOKEYTYPEDIR / REPOKEYTYPEDIRNUMNUMARRAY / REPOKEYTYPEDIRSTRARRAY keys, the code executes cbdata->dirused[id] = 1; at line 651, where id = kv->id comes directly from the KeyValue produced while iterating repodata via repodatasearch(). dirused is allocated at src/repowrite.c:1525 as solvcalloc(dirpool->ndirs, sizeof(Id)), i.e. sized to the number of known directories. For solvable data that is stored incore, the eager decoder (src/reposolv.c) validates every id against a maximum via datareadidmax()/SOLVERRORIDRANGE (e.g. reposolv.c:252-263) before it is used. However, for data stored KEYSTORAGEVERTICALOFFSET (used for large per-package data such as SOLVABLEFILELIST / REPOKEYTYPEDIRSTRARRAY), the bytes are lazily paged in and decoded on demand by datafetch() (src/repopack.h:131-211), which reads the id with datareadid()/datareadideof() and performs no range check at all. If the underlying .solv file's vertical filelist section contains a directory id greater than or equal to dirpool->ndirs (e.g. from a torn/corrupted cache after an unclean shutdown, or a hand-crafted .solv file), that raw, unvalidated id flows into collectneededcb() and is used directly as an array index into dirused, producing an out-of-bounds write of the constant value 1 far outside the allocated buffer. The reporter observed kv->id = 65137234 against dirpool->ndirs = 2737 in a field crash, i.e. a write roughly 260 MB past the end of the buffer.

The same unvalidated id is read back (not just written) without a bounds check at repowrite.c:844, 856, 865, and 917 (id = cbdata->dirused[id];) during the second serialization pass -- these are additional out-of-bounds reads beyond what the reporter's report explicitly enumerated. Independently, repodatadir2str() (src/repodata.c:356-410) walks the directory pool via dirpoolcompid()/dirpoolparent() (src/dirpool.h:34-41, 81-85), both of which index dp->dirs[did] with no range check against dp->ndirs; this function is reachable from readers such as dumpsolv and repoquery -l, giving a second, independent OOB-read primitive on the same class of corrupted/malicious input.

Reporter: Dinko Georgiev (StorPool), reported via PSIRT ticket PSIRTSUPT-22561 on 2026-08-26. No upstream fix version or commit is available at time of this analysis (not yet fixed upstream as of libsolv master 1b580675; this analysis used a shallow/depth-1 clone, so the reporter's claim that the code has been 'unchanged since d9ebbcf1 (2018-09-29)' could NOT be independently verified -- flagged as unverifiable, not confirmed or denied). The reporter's claim relating this to CVE-2026-9149 (a 0.7.38 hardening of repoaddsolv robustness against corrupt files) is noted as reporter-supplied prior art; this analysis could not verify the relationship or the CVE's exact fix commit against git history in the shallow clone, and treats this new bug as a distinct, unpatched code path (the vertical/paged filelist decoder), not covered by that prior hardening.

Independent verification performed via sandboxed static source review (see PSIRTSUPT-22561 for full verification report); CVSS independently scored at 5.5 (MODERATE), matching the reporter's own DoS/availability-only framing rather than an inflated rating.

Affected Software

3 affected components
libsolv libsolv
dnf/libdnf
zypper/libzypp

Event History

Aug 28, 2026
Data Sourced
via Red Hat·12:59 PM
DescriptionSeverityAffected Software

Frequently Asked Questions

1

Which package-management stacks may be exposed to this issue?

libsolv is used by dnf/libdnf and zypper/libzypp, as well as other RPM-based package managers that depend on libsolv. Exposure depends on whether the affected libsolv cache-writing path is used.

2

What data condition triggers the vulnerable write?

The issue occurs when repo_write() processes directory-related keys, including REPOKEY_TYPE_DIR, REPOKEY_TYPE_DIRNUMNUMARRAY, or REPOKEY_TYPE_DIRSTRARRAY, and uses a directory ID from KeyValue data without confirming that it is within the allocated dirused array.

3

How does validation differ between the affected and protected data paths?

Incore solvable data is eagerly decoded and validates IDs with data_read_id_max() before use. The affected path involves data stored using KEY_STORAGE_VERTICAL, where the described directory ID reaches collect_needed_cb() directly from repodata_search().

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203