See how rpm compares to other vendors in security performance
A flaw was found in the RPM Package Manager (RPM). A local user could be affected by a heap buffer overflow vulnerability when processing a specially crafted NDB database file. This issue arises from an error in how RPM handles certain calculations during file parsing, leading to an incorrect memory allocation. An attacker could leverage this to cause a denial of service, making the system unavailable.
A heap buffer overflow exists in RPM's NDB database backend (lib/backend/ndb/rpmpkg.c) due to unchecked 32-bit arithmetic when parsing the slot table. The slotnpages value is read directly from the on-disk NDB header and used in a 32-bit multiplication (slotnpages (PAGESIZE / SLOTSIZE)) to size a heap allocation. A crafted Packages.db can supply a slotnpages value that wraps this product to a small number, causing xcalloc to allocate an undersized buffer. The subsequent loop iterates over the full unwrapped page count, writing pkgslot entries past the heap boundary before per-slot validation runs. Exploitation requires the victim to open a crafted NDB database file with RPM tooling, and NDB is not the default backend in Fedora or RHEL (both default to sqlite).
AIONLYREPORT package: rpm-6.0.1-5.1.hum1 ------ Summary: Command Injection in rpmuncompress via malicious archive content: in the -x -C extraction path for single-root extractable archives, doUntar() inserts an archive-derived top-level directory name into a popen() shell command without escaping embedded single quotes, allowing arbitrary shell execution when a malicious archive is processed. Requirements to exploit: The attacker must supply a malicious single-root archive whose top-level directory name contains an embedded single quote and have a user or build workflow process it through the rpmuncompress -x -C extraction path. This vulnerable branch is narrower than general archive handling: it covers ZIP and other extractable formats that use the same path, such as 7z and GEM, while common tar/default extraction paths are not affected. RPM source-preparation workflows using %setup/%autosetup -C can reach this path. Component affected: github.com/rpm-software-management/rpm - tools/rpmuncompress.cc (rpmuncompress doUntar() / singleRoot() path) Version affected: Confirmed in rpm-6.0.1-5.1.hum1 (upstream 6.0.1); likely affects other versions containing the same singleRoot() + moveup + popen() construction in doUntar(), but the exact introduction point is unknown. Patch available: Proposed fix included in this report (see Proposed Fix); upstream release status unknown. Version fixed (if any already): unknown Upstream coordination: Not yet notified. This report is the initial triage. 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 attacker provides a malicious archive that is processed locally. AC:L - Exploitation requires only a crafted top-level directory name containing a single quote and reaching the -x -C extraction path; no race or special environment is required. PR:N - No prior privileges on the target system are required beyond delivering the archive. UI:R - A user or automated build workflow must process the archive. S:U - Code execution occurs within the same RPM extraction/build security scope. C:H - Successful injection can read data available to the extraction/build context. I:H - Successful injection can execute arbitrary shell commands and modify files or build outputs in that context. A:H - Successful injection can disrupt or destroy the build workspace or build process. Impact: Important. Although the reachable branch is narrower than all archive extraction, successful exploitation gives deterministic arbitrary shell execution in the permissions of the build or extraction user from attacker-controlled archive metadata. Because %setup/%autosetup -C can invoke this path, the issue affects real RPM source-preparation workflows rather than only a niche manual helper. Embargo: no Reason: This is a local-file processing issue with clear prerequisites and straightforward mitigations. Exploitation requires an attacker-controlled archive to be processed through a specific workflow rather than exposing a broad unauthenticated remote attack surface, and common tar/default extraction paths are not affected. Acknowledgement: Aisle Research Steps to reproduce: 1. Create a ZIP archive with a single top-level directory name containing a single quote and a shell payload: bash python3 - <<'PY' import zipfile name = "evil'$(touch /tmp/rpmuncompresspoc)'" with zipfile.ZipFile("/tmp/poc.zip", "w") as z: z.writestr(f"{name}/README.txt", "x") PY 2. Trigger the vulnerable extraction path: bash mkdir -p /tmp/out rpmuncompress -x -C /tmp/out /tmp/poc.zip 3. Verify command execution: bash test -f /tmp/rpmuncompresspoc && echo "INJECTED" 4. Optional non-destructive confirmation: bash rpmuncompress -n -x -C /tmp/out /tmp/poc.zip This prints the generated shell command and shows the unescaped sr interpolation. Mitigation: Treat source archives as trusted-code inputs in build and CI pipelines.
Do not process untrusted archives through rpmuncompress -x -C, including workflows that expand to %setup/%autosetup -C.
Prefer extraction paths that do not use this vulnerable branch until a fix is available; common tar/default extraction paths are not affected by this specific issue.
Long term, avoid shell composition for file moves. If a short-term fix is needed, escape embedded single quotes in sr before interpolating it into shell-quoted strings.
Vulnerability Details
In tools/rpmuncompress.cc, singleRoot() reads the archive top-level directory name (sr) from archive metadata, and doUntar() interpolates it into a shell string that is executed with popen(): cpp char sr = singleRoot(fn); ... rasprintf( &moveup, " && " "(shopt -s dotglob; mv \"$tmp\"/'%s'/ '%s') && " "rmdir \"$tmp\"/'%s' \"$tmp\" ", sr, dstpath, sr); ... inp = popen(cmd, "r"); Because sr is inserted inside single quotes without escaping embedded ', a crafted root directory name can break quoting and execute shell syntax. Reachability constraints: Requires rpmuncompress -x -C ...
Requires singleRoot(fn) to return non-NULL, meaning a single top-level directory archive
Affects extractable formats using this branch, such as ZIP, 7z, and GEM
Common tar/default extraction paths are not this vulnerable branch
Relevant CWEs: CWE-78 (OS Command Injection)
CWE-88 (Argument Injection)
Proposed Fix
A minimal hardening patch is to escape sr for single-quoted shell context before interpolation: diff — a/tools/rpmuncompress.cc +++ b/tools/rpmuncompress.cc @@ +static char shSingleQuoteEscape(const char s) +{ + sizet extra = 0; + for (const char p = s; p; p++) + if (p == '\'') + extra += 3; / '\'' replaces 1 char with 4 / + char out = (char )xmalloc(strlen(s) + extra + 1); + char o = out; + for (const char p = s; p; p++) { + if (p == '\'') { + memcpy(o, "' ''", 4); + o += 4; + } else { + o++ = p; + } + } + o = '\0'; + return out; +} @@ rasprintf( + char sresc = shSingleQuoteEscape(sr); + rasprintf( &moveup, " && " "(shopt -s dotglob; mv \"$tmp\"/'%s'/ '%s') && "
"rmdir \"$tmp\"/'%s' \"$tmp\" ", sr, dstpath, sr); + "rmdir \"$tmp\"/'%s' \"$tmp\" ", sresc, dstpath, sresc); + free(sresc);
Preferred long-term fix: avoid shell composition for file moves and use filesystem APIs directly. ------ This report was generated using AI technology. Always review AI-generated content prior to use
A crafted RPM file can trigger a Rust panic in the OpenPGP signature parsing code (librpmsequoia) during RPM signature verification. The panic crosses the Rust/C FFI boundary and causes an unconditional abort of the rpm process, resulting in a denial of service. The issue is reachable via standard RPM CLI operations such as rpm -Kv and rpm --checksig without installing the package.
An attacker only needs to supply a specially crafted RPM file to a victim system where the RPM file is processed for signature verification (e.g., rpm -Kv, rpm --checksig, CI pipelines, or automated package validation workflows). No privileges, user interaction, or package installation are required.
Local Root Exploit via Configuration Dictionary
In response to CVE-2017-7500 and CVE-2017-7501, it was decided that the policy of RPM is "Only follow directory symlinks owned by target directory owner or root." [1]. This check was only implemented for the parent directory of the file to be created. If an untrusted user owns another ancestor directory, the problem remains unfixed.
An actual exploit requires that a similar directory structure exists both at the location where RPM operates and for the files the attacker wants to get control over. Packages with such paths do exist in the real world, however. For example, in openSUSE both matomo and icinga2 ship a 'Pdo/Mysql.php' somewhere in the file system, with different ownership. A compromised 'matomo' user can create a symlink /srv/www/matomo/core/Tracker/Db -> /usr/share/icingaweb2/library/vendor/Zend/Db/Adapter/ and on the next update of matomo, RPM would replace the 'Pdo/Mysql.php' of icinga2 and give ownership of it to the 'matomo' user.
A fix for this requires a messy ball of code using OPATH to manually walk the whole directory structure and manually resolving symlinks, like in [1] and [2].
References:
1: https://github.com/systemd/systemd/blob/a5648b809457d120500b2acb18b31e2168a4817a/src/basic/fs-util.c#L716 2: https://build.suse.de/package/viewfile/SUSE:Maintenance:13179/permissions.SUSESLE-15-SP1Update/0007-chkstat-fix-privesc-CVE-2019-3690.patch?expand=1 3. https://bugzilla.suse.com/showbug.cgi?id=1157883
A race condition vulnerability was found in rpm. A local unprivileged user could use this flaw to bypass the checks that were introduced in response to CVE-2017-7500 and CVE-2017-7501, potentially gaining root privileges. The highest threat from this vulnerability is to data confidentiality and integrity as well as system availability.
A symbolic link issue was found in rpm. It occurs when rpm sets the desired permissions and credentials after installing a file. A local unprivileged user could use this flaw to exchange the original file with a symbolic link to a security-critical file and escalate their privileges on the system. The highest threat from this vulnerability is to data confidentiality and integrity as well as system availability.
RPM does not require subkeys to have a valid binding signature. This could potentially result in a signature being wrongly trusted in the following (rather contrived) scenario: A malicious subkey (to which an attacker has the secret key) is added to a legitimate public key, via a process that rejects main keys but not subkeys and does not itself check binding signatures. The main key is exported and then imported into RPM.
RPM does not require subkeys to have a valid binding signature. This could potentially result in a signature being wrongly trusted in the following (rather contrived) scenario: A malicious subkey (to which an attacker has the secret key) is added to a legitimate public key, via a process that rejects main keys but not subkeys and does not itself check binding signatures. The main key is exported and then imported into RPM.
A flaw was found in rpm. Given an RPM package signed by a trusted key, it is possible to modify it such that it still passes signature checks, but installing it corrupts the rpmdb.
A flaw was found in rpm. Given an RPM package signed by a trusted key, it is possible to modify it such that it still passes signature checks, but installing it corrupts the rpmdb.
A flaw was found in libdnf's signature verification functionality in versions before 0.60.1. This flaw allows an attacker to achieve code execution if they can alter the header information of an RPM package and then trick a user or system into installing it. The highest risk of this vulnerability is to confidentiality, integrity, as well as system availability.
A flaw was found in the RPM package in the read functionality. This flaw allows an attacker who can convince a victim to install a seemingly verifiable package or compromise an RPM repository, to cause RPM database corruption. The highest threat from this vulnerability is to data integrity. This flaw affects RPM versions before 4.17.0-alpha.
A flaw was found in RPM's hdrblobInit() in lib/header.c. This flaw allows an attacker who can modify the rpmdb to cause an out-of-bounds read. The highest threat from this vulnerability is to system availability.
A use-after-free flaw has been discovered in libcomps before version 0.1.10 in the way ObjMRTrees are merged. An attacker, who is able to make an application read a crafted comps XML file, may be able to crash the application or execute malicious code.
It was found that rpm did not properly handle RPM installations when a destination path was a symbolic link to a directory, possibly changing ownership and permissions of an arbitrary directory, and RPM files being placed in an arbitrary destination. An attacker, with write access to a directory in which a subdirectory will be installed, could redirect that directory to an arbitrary location and gain root privilege.
A directory traversal issue was found in reposync, a part of yum-utils, where reposync fails to sanitize paths in remote repository configuration files. If an attacker controls a repository, they may be able to copy files outside of the destination directory on the targeted system via path traversal. If reposync is running with heightened privileges on a targeted system, this flaw could potentially result in system compromise via the overwriting of critical system files. Version 1.1.31 and older are believed to be affected.
It was found that versions of rpm before 4.13.0.2 use temporary files with predictable names when installing an RPM. An attacker with ability to write in a directory where files will be installed could create symbolic links to an arbitrary location and modify content, and possibly permissions to arbitrary files, which could be used for denial of service or possibly privilege escalation.
Integer overflow in RPM 4.12 and earlier allows remote attackers to execute arbitrary code via a crafted CPIO header in the payload section of an RPM file, which triggers a stack-based buffer overflow.
IssueDescription:
It was found that RPM wrote file contents to the target installation directory under a temporary name, and verified its cryptographic signature only after the temporary file has been written completely. Under certain conditions, the system interprets the unverified temporary file contents and extracts commands from it. This could allow an attacker to modify signed RPM files in such a way that they would execute code chosen by the attacker during package installation.
Acknowledgements:
This issue was discovered by Florian Weimer of the Red Hat Product Security Team.
The rpmpkgRead function in lib/package.c in RPM 4.10.x before 4.10.2 does not return an error code in certain situations involving an "unparseable signature," which allows remote attackers to bypass RPM signature checks via a crafted package.
It was discovered that RPM did not properly validate region size in headerLoad() when loading header from an RPM file, allowing region size to exceed containing header size. A malformed or malicious RPM file could cause RPM to crash and possibly execute arbitrary code before file signature was properly verified.
Upstream commits: http://rpm.org/gitweb?p=rpm.git;a=commitdiff;h=472e569562d4c90d7a298080e0052856aa7fa86b http://rpm.org/gitweb?p=rpm.git;a=commitdiff;h=858a328cd0f7d4bcd8500c78faaf00e4f8033df6
RPM before 4.9.1.3 does not properly validate region tags, which allows remote attackers to cause a denial of service (crash) and possibly execute arbitrary code via an invalid region tag in a package header to the (1) headerLoad, (2) rpmReadSignature, or (3) headerVerify function.
The headerVerifyInfo function in lib/header.c in RPM before 4.9.1.3 allows remote attackers to cause a denial of service (crash) and possibly execute arbitrary code via a negative value in a region offset of a package header, which is not properly handled in a numeric range comparison.
Created attachment 525110 [details] testcase
Description of problem:
int off = ntohl(pe->offset);
if (hdrchkData(off)) goto errxit; if (off) { sizet nb = REGIONTAGCOUNT; int32t stei[nb]; / XXX Hmm, why the copy? / memcpy(&stei, dataStart + off, nb);
No check for dataStart + off > dataEnd.
(gdb) r --checksig rpminput.rpm [Thread debugging using libthreaddb enabled] Using host libthreaddb library "/lib/libthreaddb.so.1". error: no dbpath has been set error: cannot open Packages database in /%{dbpath}
Program received signal SIGSEGV, Segmentation fault. memcpy () at ../sysdeps/x8664/memcpy.S:117 117 ../sysdeps/x8664/memcpy.S: No such file or directory. in ../sysdeps/x8664/memcpy.S (gdb) bt #0 memcpy () at ../sysdeps/x8664/memcpy.S:117 #1 0x00007ffff7946493 in headerLoad (uh=0x623e00) at header.c:831 #2 0x00007ffff7946af9 in headerRead (fd=0x622180, magicp=HEADERMAGICYES) at header.c:994 #3 0x00007ffff79731d1 in readFile (fd=0x622180, fn=0x60a080 "rpminput.rpm", dig=0x622ab0, plbundle=0x6223b0, hdrbundle=0x622420) at rpmchecksig.c:462 #4 0x00007ffff7973c29 in rpmpkgVerifySigs (keyring=0x620ef0, flags=1572865, fd=0x622180, fn=0x60a080 "rpminput.rpm") at rpmchecksig.c:689 #5 0x00007ffff797429e in rpmcliSign (ts=0x621630, qva=0x7ffff7bab180, argv=0x609ed8) at rpmchecksig.c:824 #6 0x00000000004036e0 in main (argc=3, argv=0x7fffffffe458) at rpmqv.c:787
rpmbuild in RPM 4.8.0 and earlier does not properly parse the syntax of spec files, which allows user-assisted remote attackers to remove home directories via vectors involving a ;~ (semicolon tilde) sequence in a Name tag.
Created attachment 418879 [details] SRPM for testing this bug
Description of problem: When RPM replaces an executable, it does not clear the setuid and setgid bits of the old file. Thus, if a user made a hard link to the old executable, he/she will still be able to run it with elevated privileges. This is bad if it was replaced because it had a vulnerability. The problem seems to occur only when executables are replaced, not when they are erased.
This is the same bug that was previously noted in dpkg: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=225692
Version-Release number of selected component (if applicable): rpm-4.8.0-14.fc13.x8664
How reproducible: Always
Steps to Reproduce: 1. Rebuild the attached SRPM twice, once with -D 'rel 1' and once with -D 'rel 2'. 2. mkdir /tmp/rpm-setuid-test 3. rpm -i rpm-setuid-test-0-1.fc13.$(rpm -E '%{buildarch}').rpm 4. ln /usr/bin/rpm-setuid-test /tmp/rpm-setuid-test/ 5. rpm -U rpm-setuid-test-0-2.fc13.$(rpm -E '%{buildarch}').rpm 6. ls -l /tmp/rpm-setuid-test/rpm-setuid-test
Actual results: The old executable is setuid.
Expected results: The old executable is not setuid.
Common Vulnerabilities and Exposures assigned an identifier CVE-2005-4889 to the following vulnerability:
lib/fsm.c in RPM before 4.4.3 does not properly reset the metadata of an executable file during deletion of the file in an RPM package removal, which might allow local users to gain privileges by creating a hard link to a vulnerable (1) setuid or (2) setgid file, a related issue to CVE-2010-2059.
References: https://bugzilla.redhat.com/showbug.cgi?id=125517 https://bugzilla.redhat.com/showbug.cgi?id=598775 http://xforce.iss.net/xforce/xfdb/59426
This issue was fixed in Fedora rpm some time ago via bug #125517. RPM versions in Red Hat Enterprise Linux 3 and 4 do not contain the fix and are affected.
Created attachment 418879 [details] SRPM for testing this bug
Description of problem: When RPM replaces an executable, it does not clear the setuid and setgid bits of the old file. Thus, if a user made a hard link to the old executable, he/she will still be able to run it with elevated privileges. This is bad if it was replaced because it had a vulnerability. The problem seems to occur only when executables are replaced, not when they are erased.
This is the same bug that was previously noted in dpkg: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=225692
Version-Release number of selected component (if applicable): rpm-4.8.0-14.fc13.x8664
How reproducible: Always
Steps to Reproduce: 1. Rebuild the attached SRPM twice, once with -D 'rel 1' and once with -D 'rel 2'. 2. mkdir /tmp/rpm-setuid-test 3. rpm -i rpm-setuid-test-0-1.fc13.$(rpm -E '%{buildarch}').rpm 4. ln /usr/bin/rpm-setuid-test /tmp/rpm-setuid-test/ 5. rpm -U rpm-setuid-test-0-2.fc13.$(rpm -E '%{buildarch}').rpm 6. ls -l /tmp/rpm-setuid-test/rpm-setuid-test
Actual results: The old executable is setuid.
Expected results: The old executable is not setuid.