From 42faa55124abcbb132c57745dec9e0489ac74406 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Mon, 30 Sep 2013 18:35:15 -0400 Subject: [PATCH] - Issue #16040: CVE-2013-1752: nntplib: Limit maximum line lengths to 2048 to prevent readline() calls from consuming too much memory. Patch by Jyrki Pulliainen. --- Lib/nntplib.py | 11 ++++++- Lib/test/test_nntplib.py | 65 ++++++++++++++++++++++++++++++++++++++++ Misc/NEWS | 4 +++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 Lib/test/test_nntplib.py diff --git a/Lib/nntplib.py b/Lib/nntplib.py index f519b06e55..f5e0d29c7c 100644 --- a/Lib/nntplib.py +++ b/Lib/nntplib.py @@ -37,6 +37,13 @@ __all__ = ["NNTP","NNTPReplyError","NNTPTemporaryError", "error_reply","error_temp","error_perm","error_proto", "error_data",] +# maximal line length when calling readline(). This is to prevent +# reading arbitrary lenght lines. RFC 3977 limits NNTP line length to +# 512 characters, including CRLF. We have selected 2048 just to be on +# the safe side. +_MAXLINE = 2048 + + # Exceptions raised when an error or invalid response is received class NNTPError(Exception): """Base class for all nntplib exceptions""" @@ -200,7 +207,9 @@ class NNTP: def getline(self): """Internal: return one line from the server, stripping CRLF. Raise EOFError if the connection is closed.""" - line = self.file.readline() + line = self.file.readline(_MAXLINE + 1) + if len(line) > _MAXLINE: + raise NNTPDataError('line too long') if self.debugging > 1: print '*get*', repr(line) if not line: raise EOFError diff --git a/Lib/test/test_nntplib.py b/Lib/test/test_nntplib.py new file mode 100644 index 0000000000..31d41e621c --- /dev/null +++ b/Lib/test/test_nntplib.py @@ -0,0 +1,65 @@ +import socket +import threading +import nntplib +import time + +from unittest import TestCase +from test import test_support + +HOST = test_support.HOST + + +def server(evt, serv, evil=False): + serv.listen(5) + try: + conn, addr = serv.accept() + except socket.timeout: + pass + else: + if evil: + conn.send("1 I'm too long response" * 3000 + "\n") + else: + conn.send("1 I'm OK response\n") + conn.close() + finally: + serv.close() + evt.set() + + +class BaseServerTest(TestCase): + 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=server, + args=(self.evt, self.sock, self.evil)).start() + time.sleep(.1) + + def tearDown(self): + self.evt.wait() + + +class ServerTests(BaseServerTest): + evil = False + + def test_basic_connect(self): + nntp = nntplib.NNTP('localhost', self.port) + nntp.sock.close() + + +class EvilServerTests(BaseServerTest): + evil = True + + def test_too_long_line(self): + self.assertRaises(nntplib.NNTPDataError, + nntplib.NNTP, 'localhost', self.port) + + +def test_main(verbose=None): + test_support.run_unittest(EvilServerTests) + test_support.run_unittest(ServerTests) + +if __name__ == '__main__': + test_main() diff --git a/Misc/NEWS b/Misc/NEWS index 7a14b10da6..dc1dd4b991 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -20,6 +20,10 @@ Library prevent readline() calls from consuming too much memory. Patch by Jyrki Pulliainen. +- Issue #16040: CVE-2013-1752: nntplib: Limit maximum line lengths to 2048 to + prevent readline() calls from consuming too much memory. Patch by Jyrki + Pulliainen. + - Issue #16039: CVE-2013-1752: Change use of readline in imaplib module to limit line length. Patch by Emil Lind. -- 2.50.1