python/xmlrpc_gzip_27.patch
Jan Matejek 4f815b3251 - added patches for CVE-2013-1752 (bnc#856836) issues that are
missing in 2.7.6:
  python-2.7.6-imaplib.patch
  python-2.7.6-poplib.patch
  smtplib_maxline-2.7.patch
- CVE-2013-1753 (bnc#856835) gzip decompression bomb in xmlrpc client:
  xmlrpc_gzip_27.patch

OBS-URL: https://build.opensuse.org/package/show/devel:languages:python:Factory/python?expand=0&rev=159
2014-02-10 14:35:47 +00:00

125 lines
3.9 KiB
Diff

diff --git a/Doc/library/xmlrpclib.rst b/Doc/library/xmlrpclib.rst
--- a/Doc/library/xmlrpclib.rst
+++ b/Doc/library/xmlrpclib.rst
@@ -120,6 +120,15 @@
*__dict__* attribute and don't have a base class that is marshalled in a
special way.
+.. 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:: 2.7.4
+ The constant was added to strengthen the module against gzip bomb
+ attacks.
.. seealso::
diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py
--- a/Lib/test/test_xmlrpc.py
+++ b/Lib/test/test_xmlrpc.py
@@ -19,6 +19,11 @@
threading = None
try:
+ import gzip
+except ImportError:
+ gzip = None
+
+try:
unicode
except NameError:
have_unicode = False
@@ -731,7 +736,7 @@
with cm:
p.pow(6, 8)
- def test_gsip_response(self):
+ def test_gzip_response(self):
t = self.Transport()
p = xmlrpclib.ServerProxy(URL, transport=t)
old = self.requestHandler.encode_threshold
@@ -744,6 +749,27 @@
self.requestHandler.encode_threshold = old
self.assertTrue(a>b)
+ def test_gzip_decode_limit(self):
+ data = '\0' * xmlrpclib.MAX_GZIP_DECODE
+ encoded = xmlrpclib.gzip_encode(data)
+ decoded = xmlrpclib.gzip_decode(encoded)
+ self.assertEqual(len(decoded), xmlrpclib.MAX_GZIP_DECODE)
+
+ data = '\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
+
+
#Test special attributes of the ServerProxy object
class ServerProxyTestCase(unittest.TestCase):
def setUp(self):
@@ -1011,11 +1037,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)
diff --git a/Lib/xmlrpclib.py b/Lib/xmlrpclib.py
--- a/Lib/xmlrpclib.py
+++ b/Lib/xmlrpclib.py
@@ -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.
@@ -147,6 +148,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
@@ -1178,11 +1183,16 @@
f = StringIO.StringIO(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
##