Where
-Infinity
0
Severity
5.5
Out-of-bounds Read
AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H

A flaw was found in libsolv, a dependency-resolution library used by RPM-based package managers such as dnf and zypper to work with .solv repository cache files. When libsolv rewrites a .solv cache file, it reads directory-id values from the file's compressed filelist data without validating that they fall within the expected range. A corrupted or specially crafted .solv cache file (for example, one left in a torn state after an unclean system shutdown) can cause an out-of-bounds memory write when a tool such as dnf, yum, or zypper next processes it. Successful exploitation is expected to result in a crash of the affected tool (denial of service); it is not expected to allow arbitrary code execution because the out-of-bounds write always stores a fixed, non-attacker-controlled value.

1 / 2
Source: MITRE
First published (updated )
Severity
4

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.

First published (updated )
Severity
7.5
Buffer Overflow
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

A flaw was found in libsolv. A stack-based buffer overflow vulnerability exists in the PGP verification component due to incorrect length handling when copying EdDSA 's' MPI into a stack buffer. A remote attacker could craft a malicious Ed25519 PGP signature with mismatched MPI lengths. Processing this crafted signature could lead to a denial of service in automated package or repository processing workflows.

1 / 3
Source: MITRE
First published (updated )
Severity
7.8
Buffer Overflow, Input Validation
AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

A flaw was found in libsolv. This heap buffer overflow occurs during the decompression of attacker-controlled compressed data within .solv files due to insufficient input validation. An attacker can provide a specially crafted .solv file, which, when processed by a vulnerable application, can lead to out-of-bounds memory access. This could result in information disclosure, alteration of program execution, or a denial of service.

1 / 2
Source: MITRE
First published (updated )
Severity
4
Buffer Overflow, Input Validation

AIONLYREPORT package: libsolv-0.7.36-2.hum1 ------ Summary: Heap Buffer Overflow in repopagestoreloadpagerange via Malicious Compressed Data: libsolv decompresses attacker-controlled compressed .solv page data with uncheckeddecompressbuf before validating the required output length or back-reference safety, allowing out-of-bounds reads and writes during page loading. Requirements to exploit: An attacker must be able to supply a crafted .solv file or attacker-controlled repository metadata with compressed page data and cause a victim application to parse it through the normal loading flow that reaches repopagestorereadorsetuppages or repopagestoreloadpagerange. No privileges on the target are required, but the victim must ingest the malicious content. Component affected: libsolv - src/repopage.c (repopagestoreloadpagerange, repopagestorereadorsetuppages) Version affected: at least libsolv-0.7.36 (confirmed in the source report); likely other releases that contain the same src/repopage.c call sites without checkdecompressbuf before page decompression Patch available: Proposed fix included in this report (see "Proposed Fix"); upstream release status unknown. Version fixed (if any already): unknown Upstream coordination: Initial disclosure draft prepared for libsolv maintainers. CVSS: CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H - 7.8 (HIGH) AV:L - The vulnerable component is a local parser reached when a victim application loads attacker-controlled .solv content. AC:L - No unusual preconditions are required once crafted compressed page data is processed. PR:N - The attacker does not need privileges on the target system. UI:R - A victim must cause a vulnerable libsolv consumer to parse the malicious .solv content. S:U - The impact remains within the vulnerable component's security scope. C:H - Successful memory corruption could expose sensitive process memory. I:H - Successful memory corruption could allow modification of process state or control flow. A:H - Malformed metadata can crash the process and may permit broader denial of service. Impact: Moderate. This is a memory-safety flaw in a parser for attacker-controlled .solv metadata. The report demonstrates out-of-bounds read and write conditions during normal parsing, but exploitation still requires the victim to ingest malicious .solv content and does not show reliable code execution in a default remote, no-interaction scenario. Embargo: yes Reason: The source report proposes a standard 90-day coordinated disclosure window while the issue is validated and a fix is prepared. Suggested public date: 16-Jul-2026 Acknowledgement: Aisle Research Steps to reproduce: 1. Build libsolv with AddressSanitizer (-fsanitize=address) and symbols. 2. Prepare a .solv file containing vertical page data marked as compressed. 3. Encode a compressed stream that either decompresses beyond REPOPAGEBLOBSIZE (32 KB) or uses a back-reference offset larger than the amount of data already produced. 4. Load the file via normal .solv parsing flow, for example through a path that reaches repoaddsolv, repopagestorereadorsetuppages, or repopagestoreloadpagerange. 5. Observe an ASan crash such as heap-buffer-overflow or invalid read during uncheckeddecompressbuf. ------

Vulnerability Details

The issue is in page-loading paths that decompress attacker-controlled data from .solv files using uncheckeddecompressbuf without pre-validation: c / src/repopage.c / if (compressed) { unsigned int outlen; outlen = uncheckeddecompressbuf(buf, inlen, dest, REPOPAGEBLOBSIZE); if (outlen != REPOPAGEBLOBSIZE && pnum < store->numpages - 1) return 0; } c / src/repopage.c / if (compressed) { outlen = uncheckeddecompressbuf(buf, inlen, dest, REPOPAGEBLOBSIZE); if (outlen != REPOPAGEBLOBSIZE && i < npages - 1) return SOLVERRORCORRUPT; } uncheckeddecompressbuf does not enforce output bounds and does not validate back-reference safety before dereference. A safer pattern already exists elsewhere: c / src/repopage.c / unsigned int l = checkdecompressbuf(cpage, len); if (l == 0 || l > max) return 0; return uncheckeddecompressbuf(cpage, len, page, max); This makes crafted compressed pages able to trigger: Out-of-bounds write to the destination page buffer (REPOPAGEBLOBSIZE), and/or

Out-of-bounds read via invalid back-reference offsets.

Relevant CWEs: CWE-787 (Out-of-bounds Write)

CWE-125 (Out-of-bounds Read)

CWE-20 (Improper Input Validation)

Proposed Fix

Suggested patch to validate compressed pages before decompression in both vulnerable paths: diff diff --git a/src/repopage.c b/src/repopage.c — a/src/repopage.c +++ b/src/repopage.c @@ -770,8 +770,13 @@ repopagestoreloadpagerange(Repopagestore store, unsigned int pstart, unsigned int pend) if (compressed) { unsigned int outlen;

outlen = uncheckeddecompressbuf(buf, inlen, dest, REPOPAGEBLOBSIZE); + unsigned int outlen; + unsigned int needlen = checkdecompressbuf(buf, inlen); + if (needlen == 0 || needlen > REPOPAGEBLOBSIZE || + (needlen != REPOPAGEBLOBSIZE && pnum < store->numpages - 1)) + return 0; + outlen = uncheckeddecompressbuf(buf, inlen, dest, REPOPAGEBLOBSIZE); + if (outlen != needlen) + return 0; if (outlen != REPOPAGEBLOBSIZE && pnum < store->numpages - 1) { #ifdef DEBUGPAGING @@ -910,8 +915,13 @@ repopagestorereadorsetuppages(Repopagestore store, FILE fp, unsigned int pagesz, unsigned int blobsz) if (compressed) {

outlen = uncheckeddecompressbuf(buf, inlen, dest, REPOPAGEBLOBSIZE); + unsigned int needlen = checkdecompressbuf(buf, inlen); + if (needlen == 0 || needlen > REPOPAGEBLOBSIZE || + (needlen != REPOPAGEBLOBSIZE && i < npages - 1)) + return SOLVERRORCORRUPT; + outlen = uncheckeddecompressbuf(buf, inlen, dest, REPOPAGEBLOBSIZE); + if (outlen != needlen) + return SOLVERRORCORRUPT; if (outlen != REPOPAGEBLOBSIZE && i < npages - 1) { return SOLVERRORCORRUPT;

------ This report was generated using AI technology. Always review AI-generated content prior to use

First published (updated )
Severity
6.5
EPSS
0.31%
Buffer Overflow, Input Validation
AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H

A flaw was found in libsolv. This heap buffer overflow vulnerability occurs when a victim processes a specially crafted .solv file containing negative size values in the repoaddsolv function. This leads to an undersized memory allocation and a subsequent out-of-bounds write. An attacker could exploit this to cause a denial of service (DoS).

1 / 3
Source: MITRE
First published (updated )
Severity
4
Buffer Overflow, Input Validation

MANUALLYVERIFIEDREPORT package: libsolv-0.7.33-2.el10 ------

[Security] Heap Buffer Overflow in repoaddsolv via Negative maxsize

Summary: Heap buffer overflow in repoaddsolv when parsing attacker-controlled .solv files; large encoded maxsize/allsize header values can decode to negative signed Id values, leading to undersized heap allocation while a subsequent fread uses DATAREADCHUNK (8192) bytes.

Requirements to exploit: Ability to supply a crafted .solv file that a victim processes with libsolv (directly or via a consumer such as dumpsolv or an application that calls repoaddsolv on untrusted input).

Component affected: libsolv

Version affected: <= 0.7.36

Version fixed (if any already): >= TBD

CVSS: 6.5 (Medium) — CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H

Impact: Moderate (proposed). Per https://access.redhat.com/security/updates/classification this is memory corruption reachable via untrusted .solv ingestion and can at least cause a denial of service; it is not clearly "High" because an attacker typically needs the victim to process attacker-controlled input (configuration/user action) and reliable system compromise is not demonstrated here. This may be "Low" instead in product contexts where the vulnerable path is not used by default, is only reachable via uncommon workflows, or is effectively mitigated (e.g., only trusted solvdb is processed).

Embargo: no

Acknowledgement: Aisle Research

Steps to reproduce if available: See "Reproduction steps" below.

Mitigation if available: Prefer only consuming trusted .solv / solvdb inputs; avoid parsing untrusted .solv files until patched.

Original report:

Hello libsolv maintainers,

We believe that we have discovered a potential security vulnerability in repoaddsolv when parsing attacker-controlled .solv files.

Vulnerability details

readid decodes into an unsigned value and returns Id (signed int), so large encoded values can become negative after conversion:

c / src/reposolv.c / static Id readid(Repodata data, Id max) { unsigned int x = 0; ... return x; }

In repoaddsolv, maxsize and allsize are read with max=0 (no bounds check), then used for allocation and read length:

c / src/reposolv.c / maxsize = readid(&data, 0); allsize = readid(&data, 0); maxsize += 5; if (maxsize > allsize) maxsize = allsize;

buf = solvcalloc(maxsize + DATAREADCHUNK + 4, 1);

l = maxsize; if (l < DATAREADCHUNK) l = DATAREADCHUNK; if (l > allsize) l = allsize; if (!l || fread(buf, l, 1, data.fp) != 1)

If maxsize is negative, solvcalloc(maxsize + 8192 + 4, 1) can allocate a much smaller buffer, but l is then raised to 8192, and fread writes 8192 bytes into that undersized heap buffer.

Most relevant CWEs: - CWE-122 (Heap-based Buffer Overflow): direct overflow sink. - CWE-20 (Improper Input Validation): negative header fields are accepted. - CWE-195 (Signed to Unsigned Conversion Error): signed int values flow into allocation sizing.

Reproduction steps

1. Build libsolv with ASAN (or run a consumer binary that calls repoaddsolv on .solv input, e.g. dumpsolv). 2. Run the parser on this file (dumpsolv crafted.solv or equivalent).

Crash: [root@c28a4ffb0823 workspace]# ./build-asan/tools/dumpsolv ./vuln11011negativemaxsize.solv ================================================================= ==542==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x5020000000b1 at pc 0x00000041fb3c bp 0x7ffffffc5fd0 sp 0x7ffffffc5798 WRITE of size 8192 at 0x5020000000b1 thread T0 #0 0x00000041fb3b (/workspace/build-asan/tools/dumpsolv+0x41fb3b) (BuildId: 3a1e71d74bd4d38c896ffc899393aedf86bf1cfc) #1 0x7fffff662147 (/workspace/build-asan/src/libsolv.so.1+0x57147) (BuildId: ebfff12c035b97f95b2d532a1d6d237ac31e770a) #2 0x0000004e45fe (/workspace/build-asan/tools/dumpsolv+0x4e45fe) (BuildId: 3a1e71d74bd4d38c896ffc899393aedf86bf1cfc) #3 0x7fffff2f0447 (/lib64/libc.so.6+0x3447) (BuildId: dae6ae6929d69dca842288f5300af5a33d1bdcd7) #4 0x7fffff2f050a (/lib64/libc.so.6+0x350a) (BuildId: dae6ae6929d69dca842288f5300af5a33d1bdcd7) #5 0x000000401514 (/workspace/build-asan/tools/dumpsolv+0x401514) (BuildId: 3a1e71d74bd4d38c896ffc899393aedf86bf1cfc)

0x5020000000b1 is located 0 bytes after 1-byte region [0x5020000000b0,0x5020000000b1) allocated by thread T0 here: #0 0x0000004a1343 (/workspace/build-asan/tools/dumpsolv+0x4a1343) (BuildId: 3a1e71d74bd4d38c896ffc899393aedf86bf1cfc) #1 0x7fffff6b6be6 (/workspace/build-asan/src/libsolv.so.1+0xabbe6) (BuildId: ebfff12c035b97f95b2d532a1d6d237ac31e770a) #2 0x7fffff662100 (/workspace/build-asan/src/libsolv.so.1+0x57100) (BuildId: ebfff12c035b97f95b2d532a1d6d237ac31e770a) #3 0x0000004e45fe (/workspace/build-asan/tools/dumpsolv+0x4e45fe) (BuildId: 3a1e71d74bd4d38c896ffc899393aedf86bf1cfc) #4 0x7fffff2f0447 (/lib64/libc.so.6+0x3447) (BuildId: dae6ae6929d69dca842288f5300af5a33d1bdcd7) #5 0x7fffff2f050a (/lib64/libc.so.6+0x350a) (BuildId: dae6ae6929d69dca842288f5300af5a33d1bdcd7) #6 0x000000401514 (/workspace/build-asan/tools/dumpsolv+0x401514) (BuildId: 3a1e71d74bd4d38c896ffc899393aedf86bf1cfc)

SUMMARY: AddressSanitizer: heap-buffer-overflow (/workspace/build-asan/tools/dumpsolv+0x41fb3b) (BuildId: 3a1e71d74bd4d38c896ffc899393aedf86bf1cfc) Shadow bytes around the buggy address: 0x501ffffffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x501ffffffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x501fffffff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x501fffffff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x502000000000: fa fa 00 00 fa fa 04 fa fa fa 00 00 fa fa 04 fa =>0x502000000080: fa fa 04 fa fa fa[01]fa fa fa fa fa fa fa fa fa 0x502000000100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x502000000180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x502000000200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x502000000280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x502000000300: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Proposed fix

diff diff --git a/src/reposolv.c b/src/reposolv.c @@ maxsize = readid(&data, 0); allsize = readid(&data, 0); + if (maxsize < 0 || allsize < 0) + { + data.error = poolerror(pool, SOLVERRORCORRUPT, "negative data size in solv header"); + id = 0; + goto dataerror; + } + if (maxsize > INTMAX - 5) + { + data.error = poolerror(pool, SOLVERROROVERFLOW, "data size overflow in solv header"); + id = 0; + goto dataerror; + } maxsize += 5; / so we can read the next schema of an array / if (maxsize > allsize) maxsize = allsize; @@ if (keydepth) data.error = poolerror(pool, SOLVERROREOF, "unexpected EOF, depth = %d", keydepth); @@ +dataerror:

Best wishes, Aisle Research

------ This report was generated using AI technology. Always review AI-generated content prior to use

First published (updated )
Severity
6.5
EPSS
0.41%
Buffer Overflow
AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H

A flaw was found in libsolv. This stack-based buffer overflow vulnerability occurs in libsolv's Debian metadata parser when processing specially crafted Debian repository metadata. An attacker could exploit this by providing malicious SHA384 or SHA512 checksum tags, leading to memory corruption and a denial of service (DoS) in the affected system.

1 / 3
Source: MITRE
First published (updated )

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