Package: release.debian.org Severity: normal User: release.debian....@packages.debian.org Usertags: unblock
Please unblock package swift. This new version fixes CVE-2012-4406 / #686812. Debdiff attached: it only adds upstream patch as see here: https://github.com/openstack/swift/commit/e1ff51c04554d51616d2845f92ab726cb0e5831a Pleaes unblock swift/1.4.8-2, Cheers, Thomas Goirand (zigo)
diff -Nru swift-1.4.8/debian/changelog swift-1.4.8/debian/changelog --- swift-1.4.8/debian/changelog 2012-03-23 07:11:47.000000000 +0000 +++ swift-1.4.8/debian/changelog 2012-09-06 08:45:21.000000000 +0000 @@ -1,3 +1,10 @@ +swift (1.4.8-2) unstable; urgency=high + + * CVE-2012-4406: Do not use pickle for serialization in memcache, but JSON + (Closes: #686812). + + -- Thomas Goirand <z...@debian.org> Thu, 06 Sep 2012 08:40:18 +0000 + swift (1.4.8-1) unstable; urgency=low * New upstream release. diff -Nru swift-1.4.8/debian/patches/CVE-2012-4406_Do-not-use-pickle-for-serialization-in-memcache-but-JSON.patch swift-1.4.8/debian/patches/CVE-2012-4406_Do-not-use-pickle-for-serialization-in-memcache-but-JSON.patch --- swift-1.4.8/debian/patches/CVE-2012-4406_Do-not-use-pickle-for-serialization-in-memcache-but-JSON.patch 1970-01-01 00:00:00.000000000 +0000 +++ swift-1.4.8/debian/patches/CVE-2012-4406_Do-not-use-pickle-for-serialization-in-memcache-but-JSON.patch 2012-09-06 08:45:21.000000000 +0000 @@ -0,0 +1,321 @@ +Description: Do not use pickle for serialization in memcache, but JSON + We don't want to use pickle as it can execute arbitrary code. JSON is + safer. However, note that it supports serialization for only some + specific subset of object types; this should be enough for what we need, + though. + . + To avoid issues on upgrades (unability to read pickled values, and cache + poisoning for old servers not understanding JSON), we add a + memcache_serialization_support configuration option, with the following + values: + . + 0 = older, insecure pickle serialization + 1 = json serialization but pickles can still be read (still insecure) + 2 = json serialization only (secure and the default) + . + To avoid an instant full cache flush, existing installations should + upgrade with 0, then set to 1 and reload, then after some time (24 + hours) set to 2 and reload. Support for 0 and 1 will be removed in + future versions. +Origin: upstream +Bug-Debian: http://bugs.debian.org/686812 +Bug-Ubuntu: https://launchpad.net/bugs/1006414 + +--- swift-1.4.8.orig/etc/memcache.conf-sample ++++ swift-1.4.8/etc/memcache.conf-sample +@@ -3,3 +3,13 @@ + # several other conf files under [filter:cache] for example. You can specify + # multiple servers separated with commas, as in: 10.1.2.3:11211,10.1.2.4:11211 + # memcache_servers = 127.0.0.1:11211 ++# ++# Sets how memcache values are serialized and deserialized: ++# 0 = older, insecure pickle serialization ++# 1 = json serialization but pickles can still be read (still insecure) ++# 2 = json serialization only (secure and the default) ++# To avoid an instant full cache flush, existing installations should ++# upgrade with 0, then set to 1 and reload, then after some time (24 hours) ++# set to 2 and reload. ++# In the future, the ability to use pickle serialization will be removed. ++# memcache_serialization_support = 2 +--- swift-1.4.8.orig/etc/proxy-server.conf-sample ++++ swift-1.4.8/etc/proxy-server.conf-sample +@@ -122,6 +122,18 @@ use = egg:swift#memcache + # default to the value below. You can specify multiple servers separated with + # commas, as in: 10.1.2.3:11211,10.1.2.4:11211 + # memcache_servers = 127.0.0.1:11211 ++# ++# Sets how memcache values are serialized and deserialized: ++# 0 = older, insecure pickle serialization ++# 1 = json serialization but pickles can still be read (still insecure) ++# 2 = json serialization only (secure and the default) ++# If not set here, the value for memcache_serialization_support will be read ++# from /etc/swift/memcache.conf (see memcache.conf-sample). ++# To avoid an instant full cache flush, existing installations should ++# upgrade with 0, then set to 1 and reload, then after some time (24 hours) ++# set to 2 and reload. ++# In the future, the ability to use pickle serialization will be removed. ++# memcache_serialization_support = 2 + + [filter:ratelimit] + use = egg:swift#ratelimit +--- swift-1.4.8.orig/doc/manpages/proxy-server.conf.5 ++++ swift-1.4.8/doc/manpages/proxy-server.conf.5 +@@ -205,6 +205,21 @@ Enables the ability to log request heade + .IP \fBmemcache_servers\fR + The memcache servers that are available. This can be a list separated by commas. The default + is 127.0.0.1:11211. ++.IP \fBmemcache_serialization_support\fR ++This sets how memcache values are serialized and deserialized: ++.RE ++ ++.PD 0 ++.RS 10 ++.IP "0 = older, insecure pickle serialization" ++.IP "1 = json serialization but pickles can still be read (still insecure)" ++.IP "2 = json serialization only (secure and the default)" ++.RE ++ ++.RS 10 ++To avoid an instant full cache flush, existing installations should upgrade with 0, then set to 1 and reload, then after some time (24 hours) set to 2 and reload. In the future, the ability to use pickle serialization will be removed. ++ ++If not set in the configuration file, the value for memcache_serialization_support will be read from /etc/swift/memcache.conf if it exists (see memcache.conf-sample). Otherwise, the default value as indicated above will be used. + .RE + + +--- swift-1.4.8.orig/swift/common/memcached.py ++++ swift-1.4.8/swift/common/memcached.py +@@ -27,11 +27,17 @@ import time + from bisect import bisect + from hashlib import md5 + ++try: ++ import simplejson as json ++except ImportError: ++ import json ++ + DEFAULT_MEMCACHED_PORT = 11211 + + CONN_TIMEOUT = 0.3 + IO_TIMEOUT = 2.0 + PICKLE_FLAG = 1 ++JSON_FLAG = 2 + NODE_WEIGHT = 50 + PICKLE_PROTOCOL = 2 + TRY_COUNT = 3 +@@ -57,7 +63,8 @@ class MemcacheRing(object): + """ + + def __init__(self, servers, connect_timeout=CONN_TIMEOUT, +- io_timeout=IO_TIMEOUT, tries=TRY_COUNT): ++ io_timeout=IO_TIMEOUT, tries=TRY_COUNT, ++ allow_pickle=False, allow_unpickle=False): + self._ring = {} + self._errors = dict(((serv, []) for serv in servers)) + self._error_limited = dict(((serv, 0) for serv in servers)) +@@ -69,6 +76,8 @@ class MemcacheRing(object): + self._client_cache = dict(((server, []) for server in servers)) + self._connect_timeout = connect_timeout + self._io_timeout = io_timeout ++ self._allow_pickle = allow_pickle ++ self._allow_unpickle = allow_unpickle or allow_pickle + + def _exception_occurred(self, server, e, action='talking'): + if isinstance(e, socket.timeout): +@@ -130,16 +139,21 @@ class MemcacheRing(object): + + :param key: key + :param value: value +- :param serialize: if True, value is pickled before sending to memcache ++ :param serialize: if True, value is serialized with JSON before sending ++ to memcache, or with pickle if configured to use ++ pickle instead of JSON (to avoid cache poisoning) + :param timeout: ttl in memcache + """ + key = md5hash(key) + if timeout > 0: + timeout += time.time() + flags = 0 +- if serialize: ++ if serialize and self._allow_pickle: + value = pickle.dumps(value, PICKLE_PROTOCOL) + flags |= PICKLE_FLAG ++ elif serialize: ++ value = json.dumps(value) ++ flags |= JSON_FLAG + for (server, fp, sock) in self._get_conns(key): + try: + sock.sendall('set %s %d %d %s noreply\r\n%s\r\n' % \ +@@ -151,8 +165,9 @@ class MemcacheRing(object): + + def get(self, key): + """ +- Gets the object specified by key. It will also unpickle the object +- before returning if it is pickled in memcache. ++ Gets the object specified by key. It will also unserialize the object ++ before returning if it is serialized in memcache with JSON, or if it ++ is pickled and unpickling is allowed. + + :param key: key + :returns: value of the key in memcache +@@ -168,7 +183,12 @@ class MemcacheRing(object): + size = int(line[3]) + value = fp.read(size) + if int(line[2]) & PICKLE_FLAG: +- value = pickle.loads(value) ++ if self._allow_unpickle: ++ value = pickle.loads(value) ++ else: ++ value = None ++ elif int(line[2]) & JSON_FLAG: ++ value = json.loads(value) + fp.readline() + line = fp.readline().strip().split() + self._return_conn(server, fp, sock) +@@ -258,7 +278,9 @@ class MemcacheRing(object): + :param mapping: dictonary of keys and values to be set in memcache + :param servery_key: key to use in determining which server in the ring + is used +- :param serialize: if True, value is pickled before sending to memcache ++ :param serialize: if True, value is serialized with JSON before sending ++ to memcache, or with pickle if configured to use ++ pickle instead of JSON (to avoid cache poisoning) + :param timeout: ttl for memcache + """ + server_key = md5hash(server_key) +@@ -268,9 +290,12 @@ class MemcacheRing(object): + for key, value in mapping.iteritems(): + key = md5hash(key) + flags = 0 +- if serialize: ++ if serialize and self._allow_pickle: + value = pickle.dumps(value, PICKLE_PROTOCOL) + flags |= PICKLE_FLAG ++ elif serialize: ++ value = json.dumps(value) ++ flags |= JSON_FLAG + msg += ('set %s %d %d %s noreply\r\n%s\r\n' % + (key, flags, timeout, len(value), value)) + for (server, fp, sock) in self._get_conns(server_key): +@@ -302,7 +327,12 @@ class MemcacheRing(object): + size = int(line[3]) + value = fp.read(size) + if int(line[2]) & PICKLE_FLAG: +- value = pickle.loads(value) ++ if self._allow_unpickle: ++ value = pickle.loads(value) ++ else: ++ value = None ++ elif int(line[2]) & JSON_FLAG: ++ value = json.loads(value) + responses[line[1]] = value + fp.readline() + line = fp.readline().strip().split() +--- swift-1.4.8.orig/swift/common/middleware/memcache.py ++++ swift-1.4.8/swift/common/middleware/memcache.py +@@ -27,20 +27,36 @@ class MemcacheMiddleware(object): + def __init__(self, app, conf): + self.app = app + self.memcache_servers = conf.get('memcache_servers') +- if not self.memcache_servers: ++ serialization_format = conf.get('memcache_serialization_support') ++ ++ if not self.memcache_servers or serialization_format is None: + path = os.path.join(conf.get('swift_dir', '/etc/swift'), + 'memcache.conf') + memcache_conf = ConfigParser() + if memcache_conf.read(path): +- try: +- self.memcache_servers = \ +- memcache_conf.get('memcache', 'memcache_servers') +- except (NoSectionError, NoOptionError): +- pass ++ if not self.memcache_servers: ++ try: ++ self.memcache_servers = \ ++ memcache_conf.get('memcache', 'memcache_servers') ++ except (NoSectionError, NoOptionError): ++ pass ++ if serialization_format is None: ++ try: ++ serialization_format = \ ++ memcache_conf.get('memcache', ++ 'memcache_serialization_support') ++ except (NoSectionError, NoOptionError): ++ pass ++ + if not self.memcache_servers: + self.memcache_servers = '127.0.0.1:11211' ++ if serialization_format is None: ++ serialization_format = 2 ++ + self.memcache = MemcacheRing( +- [s.strip() for s in self.memcache_servers.split(',') if s.strip()]) ++ [s.strip() for s in self.memcache_servers.split(',') if s.strip()], ++ allow_pickle=(serialization_format == 0), ++ allow_unpickle=(serialization_format <= 1)) + + def __call__(self, env, start_response): + env['swift.cache'] = self.memcache +--- swift-1.4.8.orig/test/unit/common/test_memcached.py ++++ swift-1.4.8/test/unit/common/test_memcached.py +@@ -1,3 +1,4 @@ ++ # -*- coding: utf8 -*- + # Copyright (c) 2010-2012 OpenStack, LLC. + # + # Licensed under the Apache License, Version 2.0 (the "License"); +@@ -166,6 +167,9 @@ class TestMemcached(unittest.TestCase): + self.assertEquals(memcache_client.get('some_key'), [1, 2, 3]) + memcache_client.set('some_key', [4, 5, 6]) + self.assertEquals(memcache_client.get('some_key'), [4, 5, 6]) ++ memcache_client.set('some_key', ['simple str', 'utf8 str éà']) ++ # As per http://wiki.openstack.org/encoding, we should expect to have unicode ++ self.assertEquals(memcache_client.get('some_key'), ['simple str', u'utf8 str éà']) + self.assert_(float(mock.cache.values()[0][1]) == 0) + esttimeout = time.time() + 10 + memcache_client.set('some_key', [1, 2, 3], timeout=10) +@@ -244,6 +248,24 @@ class TestMemcached(unittest.TestCase): + self.assertEquals(memcache_client.get_multi(('some_key2', 'some_key1', + 'not_exists'), 'multi_key'), [[4, 5, 6], [1, 2, 3], None]) + ++ def test_serialization(self): ++ memcache_client = memcached.MemcacheRing(['1.2.3.4:11211'], ++ allow_pickle=True) ++ mock = MockMemcached() ++ memcache_client._client_cache['1.2.3.4:11211'] = [(mock, mock)] * 2 ++ memcache_client.set('some_key', [1, 2, 3]) ++ self.assertEquals(memcache_client.get('some_key'), [1, 2, 3]) ++ memcache_client._allow_pickle = False ++ memcache_client._allow_unpickle = True ++ self.assertEquals(memcache_client.get('some_key'), [1, 2, 3]) ++ memcache_client._allow_unpickle = False ++ self.assertEquals(memcache_client.get('some_key'), None) ++ memcache_client.set('some_key', [1, 2, 3]) ++ self.assertEquals(memcache_client.get('some_key'), [1, 2, 3]) ++ memcache_client._allow_unpickle = True ++ self.assertEquals(memcache_client.get('some_key'), [1, 2, 3]) ++ memcache_client._allow_pickle = True ++ self.assertEquals(memcache_client.get('some_key'), [1, 2, 3]) + + if __name__ == '__main__': + unittest.main() +--- swift-1.4.8.orig/test/unit/common/middleware/test_memcache.py ++++ swift-1.4.8/test/unit/common/middleware/test_memcache.py +@@ -47,6 +47,8 @@ class SetConfigParser(object): + if section == 'memcache': + if option == 'memcache_servers': + return '1.2.3.4:5' ++ elif option == 'memcache_serialization_support': ++ return '2' + else: + raise NoOptionError(option) + else: +@@ -86,7 +88,8 @@ class TestCacheMiddleware(unittest.TestC + exc = None + try: + app = memcache.MemcacheMiddleware( +- FakeApp(), {'memcache_servers': '1.2.3.4:5'}) ++ FakeApp(), {'memcache_servers': '1.2.3.4:5', ++ 'memcache_serialization_support': '2'}) + except Exception, err: + exc = err + finally: diff -Nru swift-1.4.8/debian/patches/series swift-1.4.8/debian/patches/series --- swift-1.4.8/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ swift-1.4.8/debian/patches/series 2012-09-06 08:45:21.000000000 +0000 @@ -0,0 +1 @@ +CVE-2012-4406_Do-not-use-pickle-for-serialization-in-memcache-but-JSON.patch