[Python-checkins] cpython (2.6): - Issue #16041: CVE-2013-1752: poplib: Limit maximum line lengths to 2048 to

barry.warsaw python-checkins at python.org
Mon Sep 30 21:58:47 CEST 2013


http://hg.python.org/cpython/rev/7214e3324a45
changeset:   85889:7214e3324a45
branch:      2.6
parent:      85861:582e5072ff89
user:        Barry Warsaw <barry at python.org>
date:        Mon Sep 30 15:56:29 2013 -0400
summary:
  - Issue #16041: CVE-2013-1752: poplib: Limit maximum line lengths to 2048 to
  prevent readline() calls from consuming too much member.  Patch by Jyrki
  Pulliainen.

files:
  Lib/poplib.py           |  14 +++++-
  Lib/test/test_poplib.py |  71 +++++++++++++++++++++++++++++
  Misc/NEWS               |  17 ++++--
  3 files changed, 95 insertions(+), 7 deletions(-)


diff --git a/Lib/poplib.py b/Lib/poplib.py
--- a/Lib/poplib.py
+++ b/Lib/poplib.py
@@ -32,6 +32,12 @@
 LF = '\n'
 CRLF = CR+LF
 
+# maximal line length when calling readline(). This is to prevent
+# reading arbitrary lenght lines. RFC 1939 limits POP3 line length to
+# 512 characters, including CRLF. We have selected 2048 just to be on
+# the safe side.
+_MAXLINE = 2048
+
 
 class POP3:
 
@@ -103,7 +109,10 @@
     # Raise error_proto('-ERR EOF') if the connection is closed.
 
     def _getline(self):
-        line = self.file.readline()
+        line = self.file.readline(_MAXLINE + 1)
+        if len(line) > _MAXLINE:
+            raise error_proto('line too long')
+
         if self._debugging > 1: print '*get*', repr(line)
         if not line: raise error_proto('-ERR EOF')
         octets = len(line)
@@ -363,7 +372,10 @@
             line = ""
             renewline = re.compile(r'.*?\n')
             match = renewline.match(self.buffer)
+
             while not match:
+                if len(self.buffer) > _MAXLINE:
+                    raise error_proto('line too long')
                 self._fillBuffer()
                 match = renewline.match(self.buffer)
             line = match.group(0)
diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py
--- a/Lib/test/test_poplib.py
+++ b/Lib/test/test_poplib.py
@@ -1,3 +1,4 @@
+import os
 import socket
 import threading
 import poplib
@@ -21,6 +22,34 @@
         serv.close()
         evt.set()
 
+
+def evil_server(evt, serv, use_ssl=False):
+    serv.listen(5)
+    try:
+        conn, addr = serv.accept()
+        if use_ssl:
+            conn = ssl.wrap_socket(
+                conn,
+                server_side=True,
+                certfile=CERTFILE,
+            )
+    except socket.timeout:
+        pass
+    else:
+        if use_ssl:
+            try:
+                conn.do_handshake()
+            except ssl.SSLError, err:
+                if err.args[0] not in (ssl.SSL_ERROR_WANT_READ,
+                                       ssl.SSL_ERROR_WANT_WRITE):
+                    raise
+        conn.send("+ Hola mundo" * 1000 + "\n")
+        conn.close()
+    finally:
+        serv.close()
+        evt.set()
+
+
 class GeneralTests(TestCase):
 
     def setUp(self):
@@ -65,8 +94,50 @@
         pop.sock.close()
 
 
+class EvilServerTests(TestCase):
+    use_ssl = False
+
+    def setUp(self):
+        self.evt = threading.Event()
+        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        self.sock.settimeout(3)
+        self.port = test_support.bind_port(self.sock)
+        threading.Thread(
+            target=evil_server,
+            args=(self.evt, self.sock, self.use_ssl)).start()
+        time.sleep(.1)
+
+    def tearDown(self):
+        self.evt.wait()
+
+    def testTooLongLines(self):
+        self.assertRaises(poplib.error_proto, poplib.POP3,
+                          'localhost', self.port, timeout=30)
+
+
+SUPPORTS_SSL = False
+
+if hasattr(poplib, 'POP3_SSL'):
+    import ssl
+
+    SUPPORTS_SSL = True
+    CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
+                            "keycert.pem")
+
+    class EvilSSLServerTests(EvilServerTests):
+        use_ssl = True
+
+        def testTooLongLines(self):
+            self.assertRaises(poplib.error_proto, poplib.POP3_SSL,
+                              'localhost', self.port)
+
+
 def test_main(verbose=None):
     test_support.run_unittest(GeneralTests)
+    test_support.run_unittest(EvilServerTests)
+
+    if SUPPORTS_SSL:
+        test_support.run_unittest(EvilSSLServerTests)
 
 if __name__ == '__main__':
     test_main()
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -13,15 +13,22 @@
 Library
 -------
 
-- Issue #16037: HTTPMessage.readheaders() raises an HTTPException when more
-  than 100 headers are read.  Adapted from patch by Jyrki Pulliainen.
+- Issue #16042: CVE-2013-1752: smtplib: Limit amount of data read by
+  limiting the call to readline().  Original patch by Christian Heimes.
+
+- Issue #16041: CVE-2013-1752: poplib: Limit maximum line lengths to 2048 to
+  prevent readline() calls from consuming too much member.  Patch by Jyrki
+  Pulliainen.
+
+- Issue #16039: CVE-2013-1752: Change use of readline in imaplib module to
+  limit line length.  Patch by Emil Lind.
 
 - Issue #16038: CVE-2013-1752: ftplib: Limit amount of data read by
   limiting the call to readline().  Original patch by Michał
   Jastrzębski and Giampaolo Rodola.
 
-- Issue #16039: CVE-2013-1752: Change use of readline in imaplib module to
-  limit line length.  Patch by Emil Lind.
+- Issue #16037: HTTPMessage.readheaders() raises an HTTPException when more
+  than 100 headers are read.  Adapted from patch by Jyrki Pulliainen.
 
 - Issue #14984: On POSIX systems, when netrc is called without a filename
   argument (and therefore is reading the user's $HOME/.netrc file), it now
@@ -32,8 +39,6 @@
 - Issue #16248: Disable code execution from the user's home directory by
   tkinter when the -E flag is passed to Python.  Patch by Zachary Ware.
 
-- Issue #16042: CVE-2013-1752: smtplib: Limit amount of data read by
-  limiting the call to readline().  Original patch by Christian Heimes.
 
 Extension Modules
 -----------------

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list