[Bug 1493303] Re: [OSSA 2016-004] Swift proxy memory leak on unfinished read (CVE-2016-0738)
OpenStack Infra
1493303 at bugs.launchpad.net
Fri Jan 22 03:40:00 UTC 2016
Reviewed: https://review.openstack.org/270234
Committed: https://git.openstack.org/cgit/openstack/swift/commit/?id=a4c1825a026655b7ed21d779824ae7c25318fd52
Submitter: Jenkins
Branch: stable/kilo
commit a4c1825a026655b7ed21d779824ae7c25318fd52
Author: Samuel Merritt <sam at swiftstack.com>
Date: Tue Dec 8 16:36:05 2015 -0800
Fix memory/socket leak in proxy on truncated SLO/DLO GET
When a client disconnected while consuming an SLO or DLO GET response,
the proxy would leak a socket. This could be observed via strace as a
socket that had shutdown() called on it, but was never closed. It
could also be observed by counting entries in /proc/<pid>/fd, where
<pid> is the pid of a proxy server worker process.
This is due to a memory leak in SegmentedIterable. A SegmentedIterable
has an 'app_iter' attribute, which is a generator. That generator
references 'self' (the SegmentedIterable object). This creates a
cyclic reference: the generator refers to the SegmentedIterable, and
the SegmentedIterable refers to the generator.
Python can normally handle cyclic garbage; reference counting won't
reclaim it, but the garbage collector will. However, objects with
finalizers will stop the garbage collector from collecting them* and
the cycle of which they are part.
For most objects, "has finalizer" is synonymous with "has a __del__
method". However, a generator has a finalizer once it's started
running and before it finishes: basically, while it has stack frames
associated with it**.
When a client disconnects mid-stream, we get a memory leak. We have
our SegmentedIterable object (call it "si"), and its associated
generator. si.app_iter is the generator, and the generator closes over
si, so we have a cycle; and the generator has started but not yet
finished, so the generator needs finalization; hence, the garbage
collector won't ever clean it up.
The socket leak comes in because the generator *also* refers to the
request's WSGI environment, which contains wsgi.input, which
ultimately refers to a _socket object from the standard
library. Python's _socket objects only close their underlying file
descriptor when their reference counts fall to 0***.
This commit makes SegmentedIterable.close() call
self.app_iter.close(), thereby unwinding its generator's stack and
making it eligible for garbage collection.
* in Python < 3.4, at least. See PEP 442.
** see PyGen_NeedsFinalizing() in Objects/genobject.c and also
has_finalizer() in Modules/gcmodule.c in Python.
*** see sock_dealloc() in Modules/socketmodule.c in Python. See
sock_close() in the same file for the other half of the sad story.
This closes CVE-2016-0738.
Closes-Bug: 1493303
Change-Id: I9b617bfc152dca40d1750131d1d814d85c0a88dd
Co-Authored-By: Kota Tsuyuzaki <tsuyuzaki.kota at lab.ntt.co.jp>
** Tags added: in-stable-kilo
** Tags added: in-stable-liberty
--
You received this bug notification because you are a member of Ubuntu
OpenStack, which is subscribed to swift in Ubuntu.
https://bugs.launchpad.net/bugs/1493303
Title:
[OSSA 2016-004] Swift proxy memory leak on unfinished read
(CVE-2016-0738)
Status in Ubuntu Cloud Archive:
New
Status in OpenStack Security Advisory:
Fix Committed
Status in OpenStack Object Storage (swift):
Fix Released
Status in swift package in Ubuntu:
Confirmed
Bug description:
It looks like the Swift proxy will leak memory if the connection is
closed and the full response is not read. This opens for a potential
DoS attacks.
Reproduce:
$ swift -A http://localhost:8888/auth/v1.0 -U .. -K .. upload --use-slo --segment-size 1048576 <container> <big-file>
$ curl -H'X-Auth-Token: AUTH_...' "http://localhost:8888/v1/AUTH_../<container>/<big-file>" -m 0.001 > /dev/null
Repeat the curl command a couple of times and you will have more
information in netstat and sockstat. The important part is the -m
which sets the max time curl spends at downloading. After that point,
it'll close the connection.
$ sudo netstat -ant -p | grep :6000
$ cat /proc/net/sockstat
tcp 0 0 127.0.0.1:6000 0.0.0.0:* LISTEN 1358/python
tcp 0 43221 127.0.0.1:6000 127.0.0.1:48350 FIN_WAIT1 -
tcp 0 43221 127.0.0.1:6000 127.0.0.1:48882 FIN_WAIT1 -
tcp 939820 0 127.0.0.1:48350 127.0.0.1:6000 ESTABLISHED 17897/python
tcp 939820 0 127.0.0.1:48882 127.0.0.1:6000 ESTABLISHED 17890/python
tcp 983041 0 127.0.0.1:48191 127.0.0.1:6000 CLOSE_WAIT 17897/python
tcp 983041 0 127.0.0.1:48948 127.0.0.1:6000 CLOSE_WAIT 17892/python
Restarting the proxy frees up the lingering memory.
This problem did not exist in 2.2.0.
ProblemType: Bug
DistroRelease: Ubuntu 14.04
Package: swift 2.2.2-0ubuntu1~cloud0 [origin: Canonical]
ProcVersionSignature: Ubuntu 3.16.0-48.64~14.04.1-generic 3.16.7-ckt15
Uname: Linux 3.16.0-48-generic x86_64
ApportVersion: 2.14.1-0ubuntu3.12
Architecture: amd64
CrashDB:
{
"impl": "launchpad",
"project": "cloud-archive",
"bug_pattern_url": "http://people.canonical.com/~ubuntu-archive/bugpatterns/bugpatterns.xml",
}
Date: Tue Sep 8 09:55:05 2015
InstallationDate: Installed on 2015-06-22 (77 days ago)
InstallationMedia: Ubuntu-Server 14.04.2 LTS "Trusty Tahr" - Release amd64 (20150218.1)
PackageArchitecture: all
SourcePackage: swift
UpgradeStatus: No upgrade log present (probably fresh install)
To manage notifications about this bug go to:
https://bugs.launchpad.net/cloud-archive/+bug/1493303/+subscriptions
More information about the Ubuntu-openstack-bugs
mailing list