Blame SOURCES/00203-CVE-2013-1752-nntplib.patch

f63228
f63228
# HG changeset patch
f63228
# User Barry Warsaw <barry@python.org>
f63228
# Date 1380582569 14400
f63228
# Node ID 36680a7c0e22686df9c338a9ca3cdb2c60e05b27
f63228
# Parent  0f5611bca5a284c0b5f978e83a05818f0907bda8# Parent  731abf7834c43efb321231e65e7dd76ad9e8e661
f63228
- Issue #16040: CVE-2013-1752: nntplib: Limit maximum line lengths to 2048 to
f63228
  prevent readline() calls from consuming too much memory.  Patch by Jyrki
f63228
  Pulliainen.
f63228
f63228
diff --git a/Lib/nntplib.py b/Lib/nntplib.py
f63228
--- a/Lib/nntplib.py
f63228
+++ b/Lib/nntplib.py
f63228
@@ -37,6 +37,13 @@ import socket
f63228
            "error_reply","error_temp","error_perm","error_proto",
f63228
            "error_data",]
f63228
 
f63228
+# maximal line length when calling readline(). This is to prevent
f63228
+# reading arbitrary lenght lines. RFC 3977 limits NNTP line length to
f63228
+# 512 characters, including CRLF. We have selected 2048 just to be on
f63228
+# the safe side.
f63228
+_MAXLINE = 2048
f63228
+
f63228
+
f63228
 # Exceptions raised when an error or invalid response is received
f63228
 class NNTPError(Exception):
f63228
     """Base class for all nntplib exceptions"""
f63228
@@ -200,7 +207,9 @@ class NNTP:
f63228
     def getline(self):
f63228
         """Internal: return one line from the server, stripping CRLF.
f63228
         Raise EOFError if the connection is closed."""
f63228
-        line = self.file.readline()
f63228
+        line = self.file.readline(_MAXLINE + 1)
f63228
+        if len(line) > _MAXLINE:
f63228
+            raise NNTPDataError('line too long')
f63228
         if self.debugging > 1:
f63228
             print '*get*', repr(line)
f63228
         if not line: raise EOFError
f63228
diff --git a/Lib/test/test_nntplib.py b/Lib/test/test_nntplib.py
f63228
new file mode 100644
f63228
--- /dev/null
f63228
+++ b/Lib/test/test_nntplib.py
f63228
@@ -0,0 +1,65 @@
f63228
+import socket
f63228
+import threading
f63228
+import nntplib
f63228
+import time
f63228
+
f63228
+from unittest import TestCase
f63228
+from test import test_support
f63228
+
f63228
+HOST = test_support.HOST
f63228
+
f63228
+
f63228
+def server(evt, serv, evil=False):
f63228
+    serv.listen(5)
f63228
+    try:
f63228
+        conn, addr = serv.accept()
f63228
+    except socket.timeout:
f63228
+        pass
f63228
+    else:
f63228
+        if evil:
f63228
+            conn.send("1 I'm too long response" * 3000 + "\n")
f63228
+        else:
f63228
+            conn.send("1 I'm OK response\n")
f63228
+        conn.close()
f63228
+    finally:
f63228
+        serv.close()
f63228
+        evt.set()
f63228
+
f63228
+
f63228
+class BaseServerTest(TestCase):
f63228
+    def setUp(self):
f63228
+        self.evt = threading.Event()
f63228
+        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
f63228
+        self.sock.settimeout(3)
f63228
+        self.port = test_support.bind_port(self.sock)
f63228
+        threading.Thread(
f63228
+            target=server,
f63228
+            args=(self.evt, self.sock, self.evil)).start()
f63228
+        time.sleep(.1)
f63228
+
f63228
+    def tearDown(self):
f63228
+        self.evt.wait()
f63228
+
f63228
+
f63228
+class ServerTests(BaseServerTest):
f63228
+    evil = False
f63228
+
f63228
+    def test_basic_connect(self):
f63228
+        nntp = nntplib.NNTP('localhost', self.port)
f63228
+        nntp.sock.close()
f63228
+
f63228
+
f63228
+class EvilServerTests(BaseServerTest):
f63228
+    evil = True
f63228
+
f63228
+    def test_too_long_line(self):
f63228
+        self.assertRaises(nntplib.NNTPDataError,
f63228
+                          nntplib.NNTP, 'localhost', self.port)
f63228
+
f63228
+
f63228
+def test_main(verbose=None):
f63228
+    test_support.run_unittest(EvilServerTests)
f63228
+    test_support.run_unittest(ServerTests)
f63228
+
f63228
+if __name__ == '__main__':
f63228
+    test_main()