An interpreted, interactive, object-oriented programming language
CentOS Sources
2017-08-01 71084d584ff953f5463757ec6536406320560b4d
commit | author | age
f63228 1
CS 2 # HG changeset patch
3 # User Serhiy Storchaka <storchaka@gmail.com>
4 # Date 1382277427 -10800
5 # Node ID 44ac81e6d584758ee56a865a7c18d82505be0643
6 # Parent  625ece68d79a27d376889579c414ed4b2d8a2649
7 Issue #16038: CVE-2013-1752: ftplib: Limit amount of data read by
8 limiting the call to readline().  Original patch by Michał
9 Jastrzębski and Giampaolo Rodola.
10
11 diff --git a/Lib/ftplib.py b/Lib/ftplib.py
12 --- a/Lib/ftplib.py
13 +++ b/Lib/ftplib.py
14 @@ -55,6 +55,8 @@ MSG_OOB = 0x1                           
15  
16  # The standard FTP server control port
17  FTP_PORT = 21
18 +# The sizehint parameter passed to readline() calls
19 +MAXLINE = 8192
20  
21  
22  # Exception raised when an error or invalid response is received
23 @@ -101,6 +103,7 @@ class FTP:
24      debugging = 0
25      host = ''
26      port = FTP_PORT
27 +    maxline = MAXLINE
28      sock = None
29      file = None
30      welcome = None
31 @@ -180,7 +183,9 @@ class FTP:
32      # Internal: return one line from the server, stripping CRLF.
33      # Raise EOFError if the connection is closed
34      def getline(self):
35 -        line = self.file.readline()
36 +        line = self.file.readline(self.maxline + 1)
37 +        if len(line) > self.maxline:
38 +            raise Error("got more than %d bytes" % self.maxline)
39          if self.debugging > 1:
40              print '*get*', self.sanitize(line)
41          if not line: raise EOFError
42 @@ -432,7 +437,9 @@ class FTP:
43          conn = self.transfercmd(cmd)
44          fp = conn.makefile('rb')
45          while 1:
46 -            line = fp.readline()
47 +            line = fp.readline(self.maxline + 1)
48 +            if len(line) > self.maxline:
49 +                raise Error("got more than %d bytes" % self.maxline)
50              if self.debugging > 2: print '*retr*', repr(line)
51              if not line:
52                  break
53 @@ -485,7 +492,9 @@ class FTP:
54          self.voidcmd('TYPE A')
55          conn = self.transfercmd(cmd)
56          while 1:
57 -            buf = fp.readline()
58 +            buf = fp.readline(self.maxline + 1)
59 +            if len(buf) > self.maxline:
60 +                raise Error("got more than %d bytes" % self.maxline)
61              if not buf: break
62              if buf[-2:] != CRLF:
63                  if buf[-1] in CRLF: buf = buf[:-1]
64 @@ -710,7 +719,9 @@ else:
65              fp = conn.makefile('rb')
66              try:
67                  while 1:
68 -                    line = fp.readline()
69 +                    line = fp.readline(self.maxline + 1)
70 +                    if len(line) > self.maxline:
71 +                        raise Error("got more than %d bytes" % self.maxline)
72                      if self.debugging > 2: print '*retr*', repr(line)
73                      if not line:
74                          break
75 @@ -748,7 +759,9 @@ else:
76              conn = self.transfercmd(cmd)
77              try:
78                  while 1:
79 -                    buf = fp.readline()
80 +                    buf = fp.readline(self.maxline + 1)
81 +                    if len(buf) > self.maxline:
82 +                        raise Error("got more than %d bytes" % self.maxline)
83                      if not buf: break
84                      if buf[-2:] != CRLF:
85                          if buf[-1] in CRLF: buf = buf[:-1]
86 @@ -905,7 +918,9 @@ class Netrc:
87          fp = open(filename, "r")
88          in_macro = 0
89          while 1:
90 -            line = fp.readline()
91 +            line = fp.readline(self.maxline + 1)
92 +            if len(line) > self.maxline:
93 +                raise Error("got more than %d bytes" % self.maxline)
94              if not line: break
95              if in_macro and line.strip():
96                  macro_lines.append(line)
97 diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py
98 --- a/Lib/test/test_ftplib.py
99 +++ b/Lib/test/test_ftplib.py
100 @@ -65,6 +65,7 @@ class DummyFTPHandler(asynchat.async_cha
101          self.last_received_data = ''
102          self.next_response = ''
103          self.rest = None
104 +        self.next_retr_data = RETR_DATA
105          self.push('220 welcome')
106  
107      def collect_incoming_data(self, data):
108 @@ -189,7 +190,7 @@ class DummyFTPHandler(asynchat.async_cha
109              offset = int(self.rest)
110          else:
111              offset = 0
112 -        self.dtp.push(RETR_DATA[offset:])
113 +        self.dtp.push(self.next_retr_data[offset:])
114          self.dtp.close_when_done()
115          self.rest = None
116  
117 @@ -203,6 +204,11 @@ class DummyFTPHandler(asynchat.async_cha
118          self.dtp.push(NLST_DATA)
119          self.dtp.close_when_done()
120  
121 +    def cmd_setlongretr(self, arg):
122 +        # For testing. Next RETR will return long line.
123 +        self.next_retr_data = 'x' * int(arg)
124 +        self.push('125 setlongretr ok')
125 +
126  
127  class DummyFTPServer(asyncore.dispatcher, threading.Thread):
128  
129 @@ -558,6 +564,20 @@ class TestFTPClass(TestCase):
130          # IPv4 is in use, just make sure send_epsv has not been used
131          self.assertEqual(self.server.handler.last_received_cmd, 'pasv')
132  
133 +    def test_line_too_long(self):
134 +        self.assertRaises(ftplib.Error, self.client.sendcmd,
135 +                          'x' * self.client.maxline * 2)
136 +
137 +    def test_retrlines_too_long(self):
138 +        self.client.sendcmd('SETLONGRETR %d' % (self.client.maxline * 2))
139 +        received = []
140 +        self.assertRaises(ftplib.Error,
141 +                          self.client.retrlines, 'retr', received.append)
142 +
143 +    def test_storlines_too_long(self):
144 +        f = StringIO.StringIO('x' * self.client.maxline * 2)
145 +        self.assertRaises(ftplib.Error, self.client.storlines, 'stor', f)
146 +
147  
148  class TestIPv6Environment(TestCase):
149