File xmlrpc_gzip_33.patch of Package python3.openSUSE_13.1_Update
Index: Python-3.3.5/Doc/library/xmlrpc.client.rst
===================================================================
--- Python-3.3.5.orig/Doc/library/xmlrpc.client.rst 2014-03-09 09:40:05.000000000 +0100
+++ Python-3.3.5/Doc/library/xmlrpc.client.rst 2014-03-27 16:35:39.652012416 +0100
@@ -123,6 +123,15 @@
:class:`Server` is retained as an alias for :class:`ServerProxy` for backwards
compatibility. New code should use :class:`ServerProxy`.
+.. data:: MAX_GZIP_DECODE
+
+ The module constant specifies the amount of bytes that are decompressed by
+ :func:`gzip_decode`. The default value is *20 MB*. A value of *-1* disables
+ the protection.
+
+ .. versionadded:: 3.3.4
+ The constant was added to strengthen the module against gzip bomb
+ attacks.
.. seealso::
Index: Python-3.3.5/Lib/test/test_xmlrpc.py
===================================================================
--- Python-3.3.5.orig/Lib/test/test_xmlrpc.py 2014-03-09 09:40:20.000000000 +0100
+++ Python-3.3.5/Lib/test/test_xmlrpc.py 2014-03-27 16:37:11.996511684 +0100
@@ -19,6 +19,11 @@
except ImportError:
threading = None
+try:
+ import gzip
+except ImportError:
+ gzip = None
+
alist = [{'astring': 'foo@bar.baz.spam',
'afloat': 7283.43,
'anint': 2**20,
@@ -219,6 +224,27 @@
except socket.error:
self.assertTrue(has_ssl)
+ def test_gzip_decode_limit(self):
+ data = b'\0' * xmlrpclib.MAX_GZIP_DECODE
+ encoded = xmlrpclib.gzip_encode(data)
+ decoded = xmlrpclib.gzip_decode(encoded)
+ self.assertEqual(len(decoded), xmlrpclib.MAX_GZIP_DECODE)
+
+ data = b'\0' * (xmlrpclib.MAX_GZIP_DECODE + 1)
+ encoded = xmlrpclib.gzip_encode(data)
+
+ with self.assertRaisesRegexp(ValueError,
+ "max gzipped payload length exceeded"):
+ xmlrpclib.gzip_decode(encoded)
+
+ oldmax = xmlrpclib.MAX_GZIP_DECODE
+ try:
+ xmlrpclib.MAX_GZIP_DECODE = -1
+ xmlrpclib.gzip_decode(encoded)
+ finally:
+ xmlrpclib.MAX_GZIP_DECODE = oldmax
+
+
class HelperTestCase(unittest.TestCase):
def test_escape(self):
self.assertEqual(xmlrpclib.escape("a&b"), "a&b")
@@ -845,7 +871,7 @@
p.pow(6, 8)
p("close")()
- def test_gsip_response(self):
+ def test_gzip_response(self):
t = self.Transport()
p = xmlrpclib.ServerProxy(URL, transport=t)
old = self.requestHandler.encode_threshold
@@ -1090,11 +1117,8 @@
xmlrpc_tests.append(SimpleServerTestCase)
xmlrpc_tests.append(KeepaliveServerTestCase1)
xmlrpc_tests.append(KeepaliveServerTestCase2)
- try:
- import gzip
+ if gzip is not None:
xmlrpc_tests.append(GzipServerTestCase)
- except ImportError:
- pass #gzip not supported in this build
xmlrpc_tests.append(MultiPathServerTestCase)
xmlrpc_tests.append(ServerProxyTestCase)
xmlrpc_tests.append(FailingServerTestCase)
Index: Python-3.3.5/Lib/xmlrpc/client.py
===================================================================
--- Python-3.3.5.orig/Lib/xmlrpc/client.py 2014-03-09 09:40:22.000000000 +0100
+++ Python-3.3.5/Lib/xmlrpc/client.py 2014-03-27 16:35:39.653012421 +0100
@@ -49,6 +49,7 @@
# 2003-07-12 gp Correct marshalling of Faults
# 2003-10-31 mvl Add multicall support
# 2004-08-20 mvl Bump minimum supported Python version to 2.1
+# 2013-01-20 ch Add workaround for gzip bomb vulnerability
#
# Copyright (c) 1999-2002 by Secret Labs AB.
# Copyright (c) 1999-2002 by Fredrik Lundh.
@@ -142,6 +143,10 @@
except ImportError:
gzip = None #python can be built without zlib/gzip support
+# Limit the maximum amount of decoded data that is decompressed. The
+# limit prevents gzip bomb attacks.
+MAX_GZIP_DECODE = 20 * 1024 * 1024 # 20 MB
+
# --------------------------------------------------------------------
# Internal stuff
@@ -1044,11 +1049,16 @@
f = BytesIO(data)
gzf = gzip.GzipFile(mode="rb", fileobj=f)
try:
- decoded = gzf.read()
+ if MAX_GZIP_DECODE < 0: # no limit
+ decoded = gzf.read()
+ else:
+ decoded = gzf.read(MAX_GZIP_DECODE + 1)
except IOError:
raise ValueError("invalid data")
f.close()
gzf.close()
+ if MAX_GZIP_DECODE >= 0 and len(decoded) > MAX_GZIP_DECODE:
+ raise ValueError("max gzipped payload length exceeded")
return decoded
##