Bug 741606 (CVE-2011-3378)

Summary: CVE-2011-3378 rpm: crashes and overflows on malformed header
Product: [Other] Security Response Reporter: Tavis Ormandy <taviso>
Component: vulnerabilityAssignee: Red Hat Product Security <security-response-team>
Status: CLOSED ERRATA QA Contact:
Severity: high Docs Contact:
Priority: high    
Version: unspecifiedCC: jlieskov, jnovy, ksrot, mjc, pinto.elia, pmatilai, psklenar, rajiv.durai, rcvalle, wnefal+redhatbugzilla
Target Milestone: ---Keywords: Security
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard: impact=important,public=20110927,reported=20110927,source=researcher,cvss2=7.6/AV:N/AC:H/Au:N/C:C/I:C/A:C,rhel-3/rpm=affected,rhel-4/rpm=affected,rhel-5.3.z/rpm=affected,rhel-5.6.z/rpm=affected,rhel-5/rpm=affected,rhel-6.0.z/rpm=affected,rhel-6/rpm=affected,fedora-all/rpm=affected,cwe=CWE-228->CWE-119
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2012-02-29 09:16:57 EST Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---
Bug Depends On: 742154, 742155, 742156, 742157, 742158, 742159, 742160, 742161, 742162, 743103    
Bug Blocks: 741810, 744203    
Attachments:
Description Flags
testcase
none
testcase none

Description Tavis Ormandy 2011-09-27 08:31:08 EDT
Created attachment 525110 [details]
testcase

Description of problem:

	    int off = ntohl(pe->offset);

	    if (hdrchkData(off))
		goto errxit;
	    if (off) {
		size_t nb = REGION_TAG_COUNT;
		int32_t 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 libthread_db enabled]
Using host libthread_db library "/lib/libthread_db.so.1".
error: no dbpath has been set
error: cannot open Packages database in /%{_dbpath}

Program received signal SIGSEGV, Segmentation fault.
memcpy () at ../sysdeps/x86_64/memcpy.S:117
117	../sysdeps/x86_64/memcpy.S: No such file or directory.
	in ../sysdeps/x86_64/memcpy.S
(gdb) bt
#0  memcpy () at ../sysdeps/x86_64/memcpy.S:117
#1  0x00007ffff7946493 in headerLoad (uh=0x623e00) at header.c:831
#2  0x00007ffff7946af9 in headerRead (fd=0x622180, magicp=HEADER_MAGIC_YES) 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
Comment 2 Tavis Ormandy 2011-09-27 09:01:38 EDT
Created attachment 525123 [details]
testcase

This is probably exploitable, the same error exists in regionSwab, and allows you to damage internal structures.
Comment 3 Tavis Ormandy 2011-09-27 10:33:41 EDT
Marking urgent, because I didn't realise that yum just uses librpm via a native wrapper.

Also sent a mail to secalert@.
Comment 4 Panu Matilainen 2011-09-28 02:55:24 EDT
This probably affects pretty much every single rpm version ever released. I could only easily test down to rpm-4.4.x (which is certainly affected too), but this is ancient code which hasn't seen much changes in a long long time.

What makes this even more "fun" is that the code path taken by regular query behaves correctly here:
[pmatilai@localhost ~]$ rpm -qpi ~/Downloads/dataStart.rpm error: /home/pmatilai/Downloads/dataStart.rpm: headerRead failed: tag[0]: BAD, tag 63 type 7 offset 7540604 count 16
error: /home/pmatilai/Downloads/dataStart.rpm: not an rpm package (or package manifest)
Comment 6 Tavis Ormandy 2011-09-28 05:49:53 EDT
Just FYI

# yum install regionSwab.rpm
Setting up Install Process
*** glibc detected *** /usr/bin/python: free(): invalid pointer: 0x0ae8e8f4 ***
======= Backtrace: =========
/lib/libc.so.6[0x4d68e2b5]
/usr/lib/librpmio.so.2(rfree+0x1c)[0x41010a9c]
/usr/lib/librpm.so.2(headerFree+0x8a)[0x4103b92a]
/usr/lib/python2.7/site-packages/rpm/_rpmmodule.so(+0x763a)[0xd8163a]
/usr/lib/libpython2.7.so.1.0[0x4f7674b7]

The same bug being reached via rpm-python and yum.
Comment 7 Panu Matilainen 2011-09-28 06:34:13 EDT
Yup. I initially missed the regionSwab.rpm case which is different from the others in that no existing safeguard catches that, whereas the two others (dataStart.rpm and the copyTdEntry.rpm) are cleanly caught by the "normal" code paths taken by yum, and rpm in other than --checksig modes.
Comment 8 devzero2000 2011-09-28 06:59:59 EDT
In reply at comment 4



rpm --checksig dataStart.rpm
error: dataStart.rpm: Header: tag[0]: BAD, tag 63 type 7 offset 7540604 count
16
[andrew@andorra rpmb]# rpm --checksig regionSwab.rpm
rpm: signature.c:749: verifyRSA: Assertion `rsactx != ((void *)0)' failed.
Aborted

rpm --version
rpm (RPM) 5.3.9

[andrew@andorra rpmb]# cat /etc/redhat-release
Mandriva Linux release 2011.0 (Cooker) for x86_64

No dump here
Comment 11 Tomas Hoger 2011-09-28 15:13:13 EDT
(In reply to comment #2)
> This is probably exploitable, the same error exists in regionSwab, and allows
> you to damage internal structures.

Tavis, can you be a little more specific what exactly you refer to here?
Comment 12 Tavis Ormandy 2011-09-28 15:54:20 EDT
The second testcase I attached demonstrates it, you can see it damages a pointer and then libc complains it's invalid.

Sorry I didn't give the attachment a better summary!
Comment 13 Tomas Hoger 2011-09-29 04:07:56 EDT
(In reply to comment #12)
> The second testcase I attached demonstrates it, you can see it damages a
> pointer and then libc complains it's invalid.

This is what I see with the second test case:

In headerLoad, rdl is read from the file.  The value is 0, hence both rdl and ril is 0.  Follows the first regionSwab call:

rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);

as:

regionSwab (entry=0x669a60, il=-1, dl=0, pe=0x668758, dataStart=0x668aa8 "", dataEnd=0x669a34 "", regionid=0)

Negative il makes it exit immediately.  Follows another call to regionSwab:

/* Load dribble entries from region. */
rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, dataEnd, rid);

as:

regionSwab (entry=0x669a40, il=54, dl=0, pe=0x668748, dataStart=0x668aa8 "", dataEnd=0x669a34 "", regionid=1)

ie.info.offset and ie.info.count comes from file and is used to compute ie.data and ie.length.  The code does check that fits inside dataStart and dataEnd.  Test case does not seem to bypass those checks.

Then there is:

if (entry) {
  ie.info.offset = regionid;
  *entry = ie;        /* structure assignment */
  entry++;
}

which is what "damages" entry->data pointer.

Later on in headerFree, the check seems to distinguish cases where entry has own malloced data chunk, and data pointing to inside of some larger chunk using:

} else if (!ENTRY_IN_REGION(entry)) {
  entry->data = _free(entry->data);

which translates to:

} else if (!(entry->info.offset < 0)) {

and hence code is confused to free something it should not.

It does not seem quite similar to the comment #0 case (i.e. not a memory corruption from buffer overflow due to missing end of buffer check, afaics), hence the question what I'm missing.
Comment 14 Mark J. Cox (Product Security) 2011-09-29 05:20:20 EDT
*** Bug 741612 has been marked as a duplicate of this bug. ***
Comment 15 Mark J. Cox (Product Security) 2011-09-29 05:22:28 EDT
Assigning CVE-2011-3378 for the issue described in bug #741612 and bug #741606 comment #2.  The issue described in comment #0 does not have a security implication.
Comment 17 Ramon de C Valle 2011-09-29 07:42:59 EDT
Shouldn't be more appropriate check the offset; index and data lenghts; in rpmReadSignature (or headerVerifyInfo) rather than in headerLoad and regionSwab?
Comment 18 Panu Matilainen 2011-09-29 08:09:16 EDT
Sort of yes, but the problem is with multiple levels of related historical API's, each of which do different levels of validation. While we could make rpm -K use rpmReadHeader() which does far more thorough checking on the header sanity than headerRead() does, but that would still leave headerRead() and headerLoad() (both are public API functions) open to this vulnerability. headerRead() could be made to use rpmReadHeader() internally with some twisting and turning for newer versions, in old versions its not possible. And even then headerLoad() would be vulnerable. Rpm generally expects callers to have done maximum possible pre-validation before calling headerLoad(), but there's no way to enforce that. The whole headerLoad() interface is as unsafe as they come, and there will always be ways to make it crash as long as it's exported the way it is now. And we can't very well just remove it in stable releases either. Etc.

So the approach here is more of a minimal patch to plug these particular issues at the lowest level rather than attempt to cure the entire way headers get read and loaded.
Comment 22 Tomas Hoger 2011-09-30 09:47:14 EDT
(In reply to comment #15)
> Assigning CVE-2011-3378 for the issue described in bug #741612 and bug #741606
> comment #2.

Upstream git commit:
http://rpm.org/gitweb?p=rpm.git;a=commitdiff;h=11a7e5d95a8ca8c7d4eaff179094afd8bb74fc3f

> The issue described in comment #0 does not have a security implication.

http://rpm.org/gitweb?p=rpm.git;a=commitdiff;h=a48f0e20cbe2ababc88b2fc52fb7a281d6fc1656
Comment 23 errata-xmlrpc 2011-10-03 16:11:15 EDT
This issue has been addressed in following products:

  Red Hat Enterprise Linux 3 Extended Lifecycle Support
  Red Hat Enterprise Linux 4
  Red Hat Enterprise Linux 5.3 Long Life
  Red Hat Enterprise Linux 5.6.Z - Server Only
  Red Hat Enterprise Linux 5
  Red Hat Enterprise Linux 6.0.Z - Server Only
  Red Hat Enterprise Linux 6

Via RHSA-2011:1349 https://rhn.redhat.com/errata/RHSA-2011-1349.html
Comment 24 Vincent Danen 2011-10-03 16:23:04 EDT
Created rpm tracking bugs for this issue

Affects: fedora-all [bug 743103]
Comment 25 Ramon de C Valle 2011-10-07 13:19:41 EDT
*** Bug 744263 has been marked as a duplicate of this bug. ***
Comment 26 Fedora Update System 2011-10-09 15:40:01 EDT
rpm-4.9.1.2-1.fc16 has been pushed to the Fedora 16 stable repository.  If problems still persist, please make note of it in this bug report.
Comment 27 Fedora Update System 2011-10-11 04:27:32 EDT
rpm-4.9.1.2-1.fc15 has been pushed to the Fedora 15 stable repository.  If problems still persist, please make note of it in this bug report.
Comment 28 Fedora Update System 2011-10-24 19:03:40 EDT
rpm-4.8.1-7.fc14 has been pushed to the Fedora 14 stable repository.  If problems still persist, please make note of it in this bug report.
Comment 29 Rajiv Durai Pandian 2011-11-16 08:17:48 EST
Segmentation fault is received while trying to install the specially crafted rpm regionSwab.rpm from rpm libraries after applying the update from RHSA-2011:1349.


Package version:
----------------

# rpm -qa | grep -i rpm
redhat-rpm-config-8.0.45-32.el5
rpm-devel-4.4.2.3-22.el5_7.2
rpm-apidocs-4.4.2.3-22.el5_7.2
rpm-python-4.4.2.3-22.el5_7.2
rpm-4.4.2.3-22.el5_7.2
rpm-libs-4.4.2.3-22.el5_7.2
rpm-build-4.4.2.3-22.el5_7.2
# rpm -qa | grep -i popt
popt-1.10.2.3-22.el5_7.2

Repro:
-----

# rpm -ivh regionSwab.rpm
error: regionSwab.rpm: headerRead failed: Header sanity check: OK
Segmentation fault (core dumped)

# gdb rpm -c core.4813
GNU gdb (GDB) Red Hat Enterprise Linux (7.0.1-37.el5)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /bin/rpm...(no debugging symbols found)...done.
[New Thread 4813]
Reading symbols from /usr/lib/librpm-4.4.so...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/librpm-4.4.so
Reading symbols from /usr/lib/librpmdb-4.4.so...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/librpmdb-4.4.so
Reading symbols from /lib/libselinux.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib/libselinux.so.1
Reading symbols from /usr/lib/librpmio-4.4.so...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/librpmio-4.4.so
Reading symbols from /usr/lib/libpopt.so.0...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/libpopt.so.0
Reading symbols from /usr/lib/libsqlite3.so.0...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/libsqlite3.so.0
Reading symbols from /usr/lib/libelf.so.1...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/libelf.so.1
Reading symbols from /lib/libm.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libm.so.6
Reading symbols from /lib/libz.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib/libz.so.1
Reading symbols from /usr/lib/libnss3.so...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/libnss3.so
Reading symbols from /usr/lib/libnssutil3.so...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/libnssutil3.so
Reading symbols from /usr/lib/libplds4.so...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/libplds4.so
Reading symbols from /usr/lib/libplc4.so...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/libplc4.so
Reading symbols from /usr/lib/libnspr4.so...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/libnspr4.so
Reading symbols from /lib/libdl.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib/libdl.so.2
Reading symbols from /lib/librt.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib/librt.so.1
Reading symbols from /lib/libpthread.so.0...(no debugging symbols found)...done.
[Thread debugging using libthread_db enabled]
Loaded symbols for /lib/libpthread.so.0
Reading symbols from /usr/lib/libbz2.so.1...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/libbz2.so.1
Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/libsepol.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib/libsepol.so.1
Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
Reading symbols from /lib/libgcc_s.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib/libgcc_s.so.1
Reading symbols from /usr/lib/libsoftokn3.so...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/libsoftokn3.so
Reading symbols from /usr/lib/libfreebl3.so...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/libfreebl3.so
Core was generated by `rpm -ivh regionSwab.rpm'.
Program terminated with signal 11, Segmentation fault.
#0  0x00486e28 in ?? () from /usr/lib/librpm-4.4.so
(gdb) run -ivh regionSwab.rpm
No core file now.
Starting program: /bin/rpm -ivh regionSwab.rpm
[Thread debugging using libthread_db enabled]
error: regionSwab.rpm: headerRead failed: Header sanity check: OK

Program received signal SIGSEGV, Segmentation fault.
0x00486e28 in ?? () from /usr/lib/librpm-4.4.so
(gdb) backtrace
#0  0x00486e28 in ?? () from /usr/lib/librpm-4.4.so
#1  0x00487ba9 in rpmtsAddInstallElement () from /usr/lib/librpm-4.4.so
#2  0x004b1709 in rpmInstall () from /usr/lib/librpm-4.4.so
#3  0x0804b824 in getStringBuf ()
#4  0x00a3fe9c in __libc_start_main () from /lib/libc.so.6
#5  0x0804a4e1 in getStringBuf ()
(gdb) frame 0
#0  0x00486e28 in ?? () from /usr/lib/librpm-4.4.so
(gdb) 

Thanks
Rajiv
Comment 31 Jan Lieskovsky 2011-11-23 11:42:29 EST
(In reply to comment #29)

Hello Rajiv,

  thank you for your report. 

Please note this particular (CVE-2011-3378) Red Hat Bugzilla entry is dedicated
to the CVE-2011-3378 issue only. Any new issues (even related with original
CVE-2011-3378 patch) should be reported as new Red Hat Bugzilla entries.

We will investigate your report below and based on the results of the research,
either dedicate a new Red Hat Bugzilla entry for that (if being a security
flaw) or comment here to clarify, why Red Hat Security Response Team does not
consider this issue to be a security flaw.

For future cases like this, please consult Red Hat Security Response Team:
[1] https://access.redhat.com/security/team/contact/

first, to ensure your concerns to be promptly investigated and particular
resolution provided.

Thank you for your understanding and cooperation.

Regards, Jan.
--
Jan iankko Lieskovsky / Red Hat Security Response Team

> Segmentation fault is received while trying to install the specially crafted
> rpm regionSwab.rpm from rpm libraries after applying the update from
> RHSA-2011:1349.

[..]

> Thanks
> Rajiv
Comment 35 Tomas Hoger 2012-02-29 09:16:57 EST
(In reply to comment #29)
> Segmentation fault is received while trying to install the specially crafted
> rpm regionSwab.rpm from rpm libraries after applying the update from
> RHSA-2011:1349.

Patches from that erratum try to ensure that rpm does not misbehave until the moment rpm signature is successfully verified.  After that point, rpm needs to be considered trusted as installation of rpm implies that, by definition, the rpm can execute arbitrary code even when it's perfectly well-formed.

> # rpm -ivh regionSwab.rpm
> error: regionSwab.rpm: headerRead failed: Header sanity check: OK
> Segmentation fault (core dumped)

rpm run this way does not abort if signature verification can not be done or if it fails.  If you want to install package that way, you should first check its signature (rpm -K) and proceed if it was signed by a trusted vendor.