cpython: 44ac81e6d584 (original) (raw)
Mercurial > cpython
changeset 86510:44ac81e6d584 2.7
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. [#16038]
Serhiy Storchaka storchaka@gmail.com | |
---|---|
date | Sun, 20 Oct 2013 16:57:07 +0300 |
parents | 625ece68d79a |
children | 0592dc076bb7 |
files | Lib/ftplib.py Lib/test/test_ftplib.py Misc/NEWS |
diffstat | 3 files changed, 46 insertions(+), 7 deletions(-)[+] [-] Lib/ftplib.py 27 Lib/test/test_ftplib.py 22 Misc/NEWS 4 |
line wrap: on
line diff
--- a/Lib/ftplib.py +++ b/Lib/ftplib.py @@ -55,6 +55,8 @@ MSG_OOB = 0x1
The standard FTP server control port
FTP_PORT = 21 +# The sizehint parameter passed to readline() calls +MAXLINE = 8192
Exception raised when an error or invalid response is received
@@ -101,6 +103,7 @@ class FTP: debugging = 0 host = '' port = FTP_PORT
- maxline = MAXLINE
sock = None
file = None
welcome = None
@@ -180,7 +183,9 @@ class FTP:
Internal: return one line from the server, stripping CRLF.
def getline(self): Raise EOFError if the connection is closed
line = self.file.readline()[](#l1.24)
line = self.file.readline(self.maxline + 1)[](#l1.25)
if len(line) > self.maxline:[](#l1.26)
raise Error("got more than %d bytes" % self.maxline)[](#l1.27) if self.debugging > 1:[](#l1.28) print '*get*', self.sanitize(line)[](#l1.29) if not line: raise EOFError[](#l1.30)
@@ -432,7 +437,9 @@ class FTP: conn = self.transfercmd(cmd) fp = conn.makefile('rb') while 1:
line = fp.readline()[](#l1.35)
line = fp.readline(self.maxline + 1)[](#l1.36)
if len(line) > self.maxline:[](#l1.37)
raise Error("got more than %d bytes" % self.maxline)[](#l1.38) if self.debugging > 2: print '*retr*', repr(line)[](#l1.39) if not line:[](#l1.40) break[](#l1.41)
@@ -485,7 +492,9 @@ class FTP: self.voidcmd('TYPE A') conn = self.transfercmd(cmd) while 1:
buf = fp.readline()[](#l1.46)
buf = fp.readline(self.maxline + 1)[](#l1.47)
if len(buf) > self.maxline:[](#l1.48)
raise Error("got more than %d bytes" % self.maxline)[](#l1.49) if not buf: break[](#l1.50) if buf[-2:] != CRLF:[](#l1.51) if buf[-1] in CRLF: buf = buf[:-1][](#l1.52)
@@ -710,7 +719,9 @@ else: fp = conn.makefile('rb') try: while 1:
line = fp.readline()[](#l1.57)
line = fp.readline(self.maxline + 1)[](#l1.58)
if len(line) > self.maxline:[](#l1.59)
raise Error("got more than %d bytes" % self.maxline)[](#l1.60) if self.debugging > 2: print '*retr*', repr(line)[](#l1.61) if not line:[](#l1.62) break[](#l1.63)
@@ -748,7 +759,9 @@ else: conn = self.transfercmd(cmd) try: while 1:
buf = fp.readline()[](#l1.68)
buf = fp.readline(self.maxline + 1)[](#l1.69)
if len(buf) > self.maxline:[](#l1.70)
raise Error("got more than %d bytes" % self.maxline)[](#l1.71) if not buf: break[](#l1.72) if buf[-2:] != CRLF:[](#l1.73) if buf[-1] in CRLF: buf = buf[:-1][](#l1.74)
@@ -905,7 +918,9 @@ class Netrc: fp = open(filename, "r") in_macro = 0 while 1:
line = fp.readline()[](#l1.79)
line = fp.readline(self.maxline + 1)[](#l1.80)
if len(line) > self.maxline:[](#l1.81)
raise Error("got more than %d bytes" % self.maxline)[](#l1.82) if not line: break[](#l1.83) if in_macro and line.strip():[](#l1.84) macro_lines.append(line)[](#l1.85)
--- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -65,6 +65,7 @@ class DummyFTPHandler(asynchat.async_cha self.last_received_data = '' self.next_response = '' self.rest = None
self.next_retr_data = RETR_DATA[](#l2.7) self.push('220 welcome')[](#l2.8)
def collect_incoming_data(self, data): @@ -189,7 +190,7 @@ class DummyFTPHandler(asynchat.async_cha offset = int(self.rest) else: offset = 0
self.dtp.push(RETR_DATA[offset:])[](#l2.15)
self.dtp.push(self.next_retr_data[offset:])[](#l2.16) self.dtp.close_when_done()[](#l2.17) self.rest = None[](#l2.18)
@@ -203,6 +204,11 @@ class DummyFTPHandler(asynchat.async_cha self.dtp.push(NLST_DATA) self.dtp.close_when_done()
- def cmd_setlongretr(self, arg):
# For testing. Next RETR will return long line.[](#l2.25)
self.next_retr_data = 'x' * int(arg)[](#l2.26)
self.push('125 setlongretr ok')[](#l2.27)
+ class DummyFTPServer(asyncore.dispatcher, threading.Thread): @@ -558,6 +564,20 @@ class TestFTPClass(TestCase): # IPv4 is in use, just make sure send_epsv has not been used self.assertEqual(self.server.handler.last_received_cmd, 'pasv')
- def test_line_too_long(self):
self.assertRaises(ftplib.Error, self.client.sendcmd,[](#l2.37)
'x' * self.client.maxline * 2)[](#l2.38)
- def test_retrlines_too_long(self):
self.client.sendcmd('SETLONGRETR %d' % (self.client.maxline * 2))[](#l2.41)
received = [][](#l2.42)
self.assertRaises(ftplib.Error,[](#l2.43)
self.client.retrlines, 'retr', received.append)[](#l2.44)
- def test_storlines_too_long(self):
f = StringIO.StringIO('x' * self.client.maxline * 2)[](#l2.47)
self.assertRaises(ftplib.Error, self.client.storlines, 'stor', f)[](#l2.48)
+ class TestIPv6Environment(TestCase):
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -37,6 +37,10 @@ Core and Builtins Library ------- +- Issue #16038: CVE-2013-1752: ftplib: Limit amount of data read by