Bug 1273360

Summary: rpm: crash when parsing corrupted RPM file
Product: [Other] Security Response Reporter: Stefan Cornelius <scorneli>
Component: vulnerabilityAssignee: Red Hat Product Security <security-response-team>
Status: CLOSED WONTFIX QA Contact:
Severity: low Docs Contact:
Priority: low    
Version: unspecifiedCC: ffesti, jorton, jrusnack, scorneli, security-response-team
Target Milestone: ---Keywords: Security
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard: impact=low,public=20151106,reported=20151015,source=researcher,cvss2=4.3/AV:N/AC:M/Au:N/C:N/I:N/A:P,cwe=CWE-125->CWE-20,rhel-6/rpm=wontfix,rhel-7/rpm=wontfix,fedora-all/rpm=affected
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2016-10-28 04:27:51 EDT Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---
Bug Depends On: 1278797    
Bug Blocks: 1270711    

Description Stefan Cornelius 2015-10-20 05:38:29 EDT
t was discovered that rpm did not properly parse certain corrupt RPM files. This can be exploited to cause a crash by tricking an unsuspecting user into processing a specially crafted RPM file.
Comment 2 Stefan Cornelius 2015-10-20 10:46:20 EDT
I think the problem is within the "CompressFilelist()" function in lib/legacy.c.

It allocates memory to store filename data from the header:
50 baseNames = xmalloc(sizeof(*dirNames) * count);

It then attempts to do some processing in order to fill this memory with sane data:
 72     while ((i = rpmtdNext(&fileNames)) >= 0) {
 73     char ** needle;
 74     char savechar;
 75     char * baseName;
 76     size_t len;
 77     char *filename = (char *) rpmtdGetString(&fileNames); /* HACK HACK */
 78
 79     if (filename == NULL)    /* XXX can't happen */
 80         continue;
 81     baseName = strrchr(filename, '/') + 1;
 82     len = baseName - filename;
 83     needle = dirNames;
 84     savechar = *baseName;
 85     *baseName = '\0';
 86     if (dirIndex < 0 ||
 87         (needle = bsearch(&filename, dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
 88         char *s = xmalloc(len + 1);
 89         rstrlcpy(s, filename, len + 1);
 90         dirIndexes[i] = ++dirIndex;
 91         dirNames[dirIndex] = s;
 92     } else
 93         dirIndexes[i] = needle - dirNames;
 94
 95     *baseName = savechar;
 96     baseNames[i] = baseName;
 97     }
 98
 99 exit:
100     if (count > 0) {
101     headerPutUint32(h, RPMTAG_DIRINDEXES, dirIndexes, count);
102     headerPutStringArray(h, RPMTAG_BASENAMES, baseNames, count);
103     headerPutStringArray(h, RPMTAG_DIRNAMES,
104                  (const char **) dirNames, dirIndex + 1);

In case of the rpm provided, the (filename == NULL) check in line 79 will be true in every iteration, thus the remaining processing steps in this loop are always skipped and "baseNames" is never put in a state that's expected by subsequent functions, which are called via headerPutStringArray() in line 102. This will ultimately lead to a crash due to invalid memory access in a strlen() function.
Comment 7 Stefan Cornelius 2015-11-06 07:53:09 EST
Created rpm tracking bugs for this issue:

Affects: fedora-all [bug 1278797]
Comment 8 Fedora Update System 2015-11-23 15:53:27 EST
rpm-4.13.0-0.rc1.7.fc23 has been pushed to the Fedora 23 stable repository. If problems still persist, please make note of it in this bug report.
Comment 9 Fedora Update System 2015-11-30 18:22:23 EST
rpm-4.12.0.1-14.fc22 has been pushed to the Fedora 22 stable repository. If problems still persist, please make note of it in this bug report.