Bug 2525602 (CVE-2026-82327) - CVE-2026-82327 libsolv: libsolv: out-of-bounds write in repo_write() via unvalidated directory id from vertical/paged .solv filelist data
Summary: CVE-2026-82327 libsolv: libsolv: out-of-bounds write in repo_write() via unva...
Keywords:
Status: NEW
Alias: CVE-2026-82327
Product: Security Response
Classification: Other
Component: vulnerability
Version: unspecified
Hardware: All
OS: Linux
medium
medium
Target Milestone: ---
Assignee: Product Security DevOps Team
QA Contact:
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2026-08-28 12:59 UTC by OSIDB Bzimport
Modified: 2026-08-28 14:10 UTC (History)
37 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed:
Embargoed:


Attachments (Terms of Use)

Description OSIDB Bzimport 2026-08-28 12:59:47 UTC
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. repo_write() (src/repo_write.c) rewrites such a cache from an in-memory Repo/Repodata, in two passes: pass 1 (collect_needed_cb) collects which directory ids are used, and pass 2 (collect_data_cb / collect_filelist_cb) emits the serialized data.

Root cause: in collect_needed_cb() (src/repo_write.c:614-683), for REPOKEY_TYPE_DIR / REPOKEY_TYPE_DIRNUMNUMARRAY / REPOKEY_TYPE_DIRSTRARRAY 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 repodata_search(). `dirused` is allocated at src/repo_write.c:1525 as `solv_calloc(dirpool->ndirs, sizeof(Id))`, i.e. sized to the number of known directories. For solvable data that is stored incore, the eager decoder (src/repo_solv.c) validates every id against a maximum via data_read_id_max()/SOLV_ERROR_ID_RANGE (e.g. repo_solv.c:252-263) before it is used. However, for data stored KEY_STORAGE_VERTICAL_OFFSET (used for large per-package data such as SOLVABLE_FILELIST / REPOKEY_TYPE_DIRSTRARRAY), the bytes are lazily paged in and decoded on demand by data_fetch() (src/repopack.h:131-211), which reads the id with data_read_id()/data_read_ideof() 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 collect_needed_cb() 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 repo_write.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, repodata_dir2str() (src/repodata.c:356-410) walks the directory pool via dirpool_compid()/dirpool_parent() (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 repo_add_solv 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.


Note You need to log in before you can comment on or make changes to this bug.