8000 Issue #16038: CVE-2013-1752: ftplib: Limit amount of data read by · python/cpython@c9cb18d · GitHub
[go: up one dir, main page]

Skip to content

Commit c9cb18d

Browse files
committed
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.
1 parent f0746ca commit c9cb18d

File tree

3 files changed

+43
-6
lines changed

3 files changed

+43
-6
lines changed

Lib/ftplib.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949

5050
# The standard FTP server control port
5151
FTP_PORT = 21
52+
# The sizehint parameter passed to readline() calls
53+
MAXLINE = 8192
5254

5355

5456
# Exception raised when an error or invalid response is received
@@ -96,6 +98,7 @@ class FTP:
9698
debugging = 0
9799
host = ''
98100
port = FTP_PORT
101+
maxline = MAXLINE
99102
sock = None
100103
file = None
101104
welcome = None
@@ -190,7 +193,9 @@ def putcmd(self, line):
190193
# Internal: return one line from the server, stripping CRLF.
191194
# Raise EOFError if the connection is closed
192195
def getline(self):
193-
line = self.file.readline()
196+
line = self.file.readline(self.maxline + 1)
197+
if len(line) > self.maxline:
198+
raise Error("got more than %d bytes" % self.maxline)
194199
if self.debugging > 1:
195200
print('*get*', self.sanitize(line))
196201
if not line: raise EOFError
@@ -444,7 +449,9 @@ def retrlines(self, cmd, callback = None):
444449
with self.transfercmd(cmd) as conn, \
445450
conn.makefile('r', encoding=self.encoding) as fp:
446451
while 1:
447-
line = fp.readline()
452+
line = fp.readline(self.maxline + 1)
453+
if len(line) > self.maxline:
454+
raise Error("got more than %d bytes" % self.maxline)
448455
if self.debugging > 2: print('*retr*', repr(line))
449456
if not line:
450457
break
@@ -494,7 +501,9 @@ def storlines(self, cmd, fp, callback=None):
494501
self.voidcmd('TYPE A')
495502
with self.transfercmd(cmd) as conn:
496503
while 1:
497-
buf = fp.readline()
504+
buf = fp.readline(self.maxline + 1)
505+
if len(buf) > self.maxline:
506+
raise Error("got more than %d bytes" % self.maxline)
498507
if not buf: break
499508
if buf[-2:] != B_CRLF:
500509
if buf[-1] in B_CRLF: buf = buf[:-1]
@@ -741,7 +750,9 @@ def retrlines(self, cmd, callback = None):
741750
fp = conn.makefile('r', encoding=self.encoding)
742751
try:
743752
while 1:
744-
line = fp.readline()
753+
line = fp.readline(self.maxline + 1)
754+
if len(line) > self.maxline:
755+
raise Error("got more than %d bytes" % self.maxline)
745756
if self.debugging > 2: print('*retr*', repr(line))
746757
if not line:
747758
break
@@ -779,7 +790,9 @@ def storlines(self, cmd, fp, callback=None):
779790
conn = self.transfercmd(cmd)
780791
try:
781792
while 1:
782-
buf = fp.readline()
793+
buf = fp.readline(self.maxline + 1)
794+
if len(buf) > self.maxline:
795+
raise Error("got more than %d bytes" % self.maxline)
783796
if not buf: break
784797
if buf[-2:] != B_CRLF:
785798
if buf[-1] in B_CRLF: buf = buf[:-1]

Lib/test/test_ftplib.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ def __init__(self, conn):
7070
self.last_received_data = ''
7171
self.next_response = ''
7272
self.rest = None
73+
self.next_retr_data = RETR_DATA
7374
self.push('220 welcome')
7475

7576
def collect_incoming_data(self, data):
@@ -199,7 +200,7 @@ def cmd_retr(self, arg):
199200
offset = int(self.rest)
200201
else:
201202
offset = 0
202-
self.dtp.push(RETR_DATA[offset:])
203+
self.dtp.push(self.next_retr_data[offset:])
203204
self.dtp.close_when_done()
204205
self.rest = None
205206

@@ -213,6 +214,11 @@ def cmd_nlst(self, arg):
213214
self.dtp.push(NLST_DATA)
214215
self.dtp.close_when_done()
215216

217+
def cmd_setlongretr(self, arg):
218+
# For testing. Next RETR will return long line.
219+
self.next_retr_data = 'x' * int(arg)
220+
self.push('125 setlongretr ok')
221+
216222

217223
class DummyFTPServer(asyncore.dispatcher, threading.Thread):
218224

@@ -628,6 +634,20 @@ def test_parse257(self):
628634
self.assertEqual(ftplib.parse257('257 "/foo/b""ar"'), '/foo/b"ar')
629635
self.assertEqual(ftplib.parse257('257 "/foo/b""ar" created'), '/foo/b"ar')
630636

637+
def test_line_too_long(self):
638+
self.assertRaises(ftplib.Error, self.client.sendcmd,
639+
'x' * self.client.maxline * 2)
640+
641+
def test_retrlines_too_long(self):
642+
self.client.sendcmd('SETLONGRETR %d' % (self.client.maxline * 2))
643+
received = []
644+
self.assertRaises(ftplib.Error,
645+
self.client.retrlines, 'retr', received.append)
646+
647+
def test_storlines_too_long(self):
648+
f = io.BytesIO(b'x' * self.client.maxline * 2)
649+
self.assertRaises(ftplib.Error, self.client.storlines, 'stor', f)
650+
631651

632652
class TestIPv6Environment(TestCase):
633653

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ What's New in Python 3.2.6?
1010
Library
1111
-------
1212

13+
- Issue #16038: CVE-2013-1752: ftplib: Limit amount of data read by
14+
limiting the call to readline(). Original patch by Michał
15+
Jastrzębski and Giampaolo Rodola.
16+
1317
- Issue #16037: HTTPMessage.readheaders() raises an HTTPException when more than
1418
100 headers are read. Adapted from patch by Jyrki Pulliainen.
1519

0 commit comments

Comments
 (0)
0