[OE-core] [dizzy] [PATCH 2/2] python: Backport CVE-2013-1752 remaining patches
Tudor Florea
tudor.florea at enea.com
Wed Nov 18 13:58:41 UTC 2015
This back ported patch fixes CVE-2013-1752 for ftplib, imaplib, nntplib and poplib
Signed-off-by: Tudor Florea <tudor.florea at enea.com>
---
.../python-2.7.3-CVE-2013-1752-ftplib-fix.patch | 149 +++++++++++++++++++++
.../python-2.7.3-CVE-2013-1752-imaplib-fix.patch | 37 +++++
.../python-2.7.3-CVE-2013-1752-nntplib-fix.patch | 105 +++++++++++++++
.../python-2.7.3-CVE-2013-1752-poplib-fix.patch | 90 +++++++++++++
meta/recipes-devtools/python/python_2.7.3.bb | 4 +
5 files changed, 385 insertions(+)
create mode 100644 meta/recipes-devtools/python/python/python-2.7.3-CVE-2013-1752-ftplib-fix.patch
create mode 100644 meta/recipes-devtools/python/python/python-2.7.3-CVE-2013-1752-imaplib-fix.patch
create mode 100644 meta/recipes-devtools/python/python/python-2.7.3-CVE-2013-1752-nntplib-fix.patch
create mode 100644 meta/recipes-devtools/python/python/python-2.7.3-CVE-2013-1752-poplib-fix.patch
diff --git a/meta/recipes-devtools/python/python/python-2.7.3-CVE-2013-1752-ftplib-fix.patch b/meta/recipes-devtools/python/python/python-2.7.3-CVE-2013-1752-ftplib-fix.patch
new file mode 100644
index 0000000..97c890e
--- /dev/null
+++ b/meta/recipes-devtools/python/python/python-2.7.3-CVE-2013-1752-ftplib-fix.patch
@@ -0,0 +1,149 @@
+
+# HG changeset patch
+# User Serhiy Storchaka <storchaka at gmail.com>
+# Date 1382277427 -10800
+# Node ID 44ac81e6d584758ee56a865a7c18d82505be0643
+# Parent 625ece68d79a27d376889579c414ed4b2d8a2649
+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.
+
+diff --git a/Lib/ftplib.py b/Lib/ftplib.py
+--- 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.
+ # Raise EOFError if the connection is closed
+ def getline(self):
+- line = self.file.readline()
++ line = self.file.readline(self.maxline + 1)
++ if len(line) > self.maxline:
++ raise Error("got more than %d bytes" % self.maxline)
+ if self.debugging > 1:
+ print '*get*', self.sanitize(line)
+ if not line: raise EOFError
+@@ -432,7 +437,9 @@ class FTP:
+ conn = self.transfercmd(cmd)
+ fp = conn.makefile('rb')
+ while 1:
+- line = fp.readline()
++ line = fp.readline(self.maxline + 1)
++ if len(line) > self.maxline:
++ raise Error("got more than %d bytes" % self.maxline)
+ if self.debugging > 2: print '*retr*', repr(line)
+ if not line:
+ break
+@@ -485,7 +492,9 @@ class FTP:
+ self.voidcmd('TYPE A')
+ conn = self.transfercmd(cmd)
+ while 1:
+- buf = fp.readline()
++ buf = fp.readline(self.maxline + 1)
++ if len(buf) > self.maxline:
++ raise Error("got more than %d bytes" % self.maxline)
+ if not buf: break
+ if buf[-2:] != CRLF:
+ if buf[-1] in CRLF: buf = buf[:-1]
+@@ -710,7 +719,9 @@ else:
+ fp = conn.makefile('rb')
+ try:
+ while 1:
+- line = fp.readline()
++ line = fp.readline(self.maxline + 1)
++ if len(line) > self.maxline:
++ raise Error("got more than %d bytes" % self.maxline)
+ if self.debugging > 2: print '*retr*', repr(line)
+ if not line:
+ break
+@@ -748,7 +759,9 @@ else:
+ conn = self.transfercmd(cmd)
+ try:
+ while 1:
+- buf = fp.readline()
++ buf = fp.readline(self.maxline + 1)
++ if len(buf) > self.maxline:
++ raise Error("got more than %d bytes" % self.maxline)
+ if not buf: break
+ if buf[-2:] != CRLF:
+ if buf[-1] in CRLF: buf = buf[:-1]
+@@ -905,7 +918,9 @@ class Netrc:
+ fp = open(filename, "r")
+ in_macro = 0
+ while 1:
+- line = fp.readline()
++ line = fp.readline(self.maxline + 1)
++ if len(line) > self.maxline:
++ raise Error("got more than %d bytes" % self.maxline)
+ if not line: break
+ if in_macro and line.strip():
+ macro_lines.append(line)
+diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py
+--- 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
+ self.push('220 welcome')
+
+ 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:])
++ self.dtp.push(self.next_retr_data[offset:])
+ self.dtp.close_when_done()
+ self.rest = None
+
+@@ -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.
++ self.next_retr_data = 'x' * int(arg)
++ self.push('125 setlongretr ok')
++
+
+ 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,
++ 'x' * self.client.maxline * 2)
++
++ def test_retrlines_too_long(self):
++ self.client.sendcmd('SETLONGRETR %d' % (self.client.maxline * 2))
++ received = []
++ self.assertRaises(ftplib.Error,
++ self.client.retrlines, 'retr', received.append)
++
++ def test_storlines_too_long(self):
++ f = StringIO.StringIO('x' * self.client.maxline * 2)
++ self.assertRaises(ftplib.Error, self.client.storlines, 'stor', f)
++
+
+ class TestIPv6Environment(TestCase):
+
diff --git a/meta/recipes-devtools/python/python/python-2.7.3-CVE-2013-1752-imaplib-fix.patch b/meta/recipes-devtools/python/python/python-2.7.3-CVE-2013-1752-imaplib-fix.patch
new file mode 100644
index 0000000..f4bd84d
--- /dev/null
+++ b/meta/recipes-devtools/python/python/python-2.7.3-CVE-2013-1752-imaplib-fix.patch
@@ -0,0 +1,37 @@
+Upstream-Status: Backport
+
+CVE-2013-1752: Change use of readline in imaplib module to limit line length. Patch by Emil Lind.
+
+Signed-off-by: Tudor Florea <tudor.florea at enea.com>
+
+diff -r ce583eb0bec2 Lib/imaplib.py
+--- a/Lib/imaplib.py Thu Feb 21 20:17:54 2013 +0200
++++ b/Lib/imaplib.py Tue Feb 26 22:36:52 2013 +0100
+@@ -35,6 +35,15 @@
+ IMAP4_SSL_PORT = 993
+ AllowedVersions = ('IMAP4REV1', 'IMAP4') # Most recent first
+
++# Maximal line length when calling readline(). This is to prevent
++# reading arbitrary length lines. RFC 3501 and 2060 (IMAP 4rev1)
++# don't specify a line length. RFC 2683 however suggests limiting client
++# command lines to 1000 octets and server command lines to 8000 octets.
++# We have selected 10000 for some extra margin and since that is supposedly
++# also what UW and Panda IMAP does.
++_MAXLINE = 10000
++
++
+ # Commands
+
+ Commands = {
+@@ -237,7 +246,10 @@
+
+ def readline(self):
+ """Read line from remote."""
+- return self.file.readline()
++ line = self.file.readline(_MAXLINE + 1)
++ if len(line) > _MAXLINE:
++ raise self.error("got more than %d bytes" % _MAXLINE)
++ return line
+
+
+ def send(self, data):
diff --git a/meta/recipes-devtools/python/python/python-2.7.3-CVE-2013-1752-nntplib-fix.patch b/meta/recipes-devtools/python/python/python-2.7.3-CVE-2013-1752-nntplib-fix.patch
new file mode 100644
index 0000000..443e137
--- /dev/null
+++ b/meta/recipes-devtools/python/python/python-2.7.3-CVE-2013-1752-nntplib-fix.patch
@@ -0,0 +1,105 @@
+Upstream-Status: Backport
+
+CVE-2013-1752: nntplib: Limit maximum line lengths to 2048 to prevent
+readline() calls from consuming too much memory.
+Patch by Jyrki Pulliainen.
+
+Signed-off-by: Tudor Florea <tudor.florea at enea.com>
+
+diff -r 936621d33c38 Lib/nntplib.py
+--- a/Lib/nntplib.py Wed Feb 20 18:19:55 2013 -0500
++++ b/Lib/nntplib.py Mon Sep 30 23:42:09 2013 +0200
+@@ -37,6 +37,13 @@
+ "error_reply","error_temp","error_perm","error_proto",
+ "error_data",]
+
++# maximal line length when calling readline(). This is to prevent
++# reading arbitrary length 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 @@
+ 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 NNTPProtocolError('line too long')
+ if self.debugging > 1:
+ print '*get*', repr(line)
+ if not line: raise EOFError
+diff -r 936621d33c38 Lib/test/test_nntplib.py
+--- /dev/null Thu Jan 01 00:00:00 1970 +0000
++++ b/Lib/test/test_nntplib.py Mon Sep 30 23:42:09 2013 +0200
+@@ -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.NNTPProtocolError,
++ 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/meta/recipes-devtools/python/python/python-2.7.3-CVE-2013-1752-poplib-fix.patch b/meta/recipes-devtools/python/python/python-2.7.3-CVE-2013-1752-poplib-fix.patch
new file mode 100644
index 0000000..15a5a2c
--- /dev/null
+++ b/meta/recipes-devtools/python/python/python-2.7.3-CVE-2013-1752-poplib-fix.patch
@@ -0,0 +1,90 @@
+diff --git a/Lib/poplib.py b/Lib/poplib.py
+--- a/Lib/poplib.py
++++ b/Lib/poplib.py
+@@ -27,16 +27,22 @@ POP3_PORT = 110
+ # POP SSL PORT
+ POP3_SSL_PORT = 995
+
+ # Line terminators (we always output CRLF, but accept any of CRLF, LFCR, LF)
+ CR = '\r'
+ LF = '\n'
+ CRLF = CR+LF
+
++# maximal line length when calling readline(). This is to prevent
++# reading arbitrary length lines. RFC 1939 limits POP3 line length to
++# 512 characters, including CRLF. We have selected 2048 just to be on
++# the safe side.
++_MAXLINE = 2048
++
+
+ class POP3:
+
+ """This class supports both the minimal and optional command sets.
+ Arguments can be strings or integers (where appropriate)
+ (e.g.: retr(1) and retr('1') both work equally well.
+
+ Minimal Command Set:
+@@ -98,17 +104,19 @@ class POP3:
+ self._putline(line)
+
+
+ # Internal: return one line from the server, stripping CRLF.
+ # This is where all the CPU time of this module is consumed.
+ # Raise error_proto('-ERR EOF') if the connection is closed.
+
+ def _getline(self):
+- line = self.file.readline()
++ line = self.file.readline(_MAXLINE + 1)
++ if len(line) > _MAXLINE:
++ raise error_proto('line too long')
+ if self._debugging > 1: print '*get*', repr(line)
+ if not line: raise error_proto('-ERR EOF')
+ octets = len(line)
+ # server can send any combination of CR & LF
+ # however, 'readline()' returns lines ending in LF
+ # so only possibilities are ...LF, ...CRLF, CR...LF
+ if line[-2:] == CRLF:
+ return line[:-2], octets
+@@ -360,16 +368,18 @@ else:
+ self.buffer += localbuf
+
+ def _getline(self):
+ line = ""
+ renewline = re.compile(r'.*?\n')
+ match = renewline.match(self.buffer)
+ while not match:
+ self._fillBuffer()
++ if len(self.buffer) > _MAXLINE:
++ raise error_proto('line too long')
+ match = renewline.match(self.buffer)
+ line = match.group(0)
+ self.buffer = renewline.sub('' ,self.buffer, 1)
+ if self._debugging > 1: print '*get*', repr(line)
+
+ octets = len(line)
+ if line[-2:] == CRLF:
+ return line[:-2], octets
+diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py
+--- a/Lib/test/test_poplib.py
++++ b/Lib/test/test_poplib.py
+@@ -193,16 +193,20 @@ class TestPOP3Class(TestCase):
+ def test_retr(self):
+ expected = ('+OK 116 bytes',
+ ['From: postmaster at python.org', 'Content-Type: text/plain',
+ 'MIME-Version: 1.0', 'Subject: Dummy',
+ '', 'line1', 'line2', 'line3'],
+ 113)
+ self.assertEqual(self.client.retr('foo'), expected)
+
++ def test_too_long_lines(self):
++ self.assertRaises(poplib.error_proto, self.client._shortcmd,
++ 'echo +%s' % ((poplib._MAXLINE + 10) * 'a'))
++
+ def test_dele(self):
+ self.assertOK(self.client.dele('foo'))
+
+ def test_noop(self):
+ self.assertOK(self.client.noop())
+
+ def test_rpop(self):
+ self.assertOK(self.client.rpop('foo'))
diff --git a/meta/recipes-devtools/python/python_2.7.3.bb b/meta/recipes-devtools/python/python_2.7.3.bb
index d603587..9cfe0b4 100644
--- a/meta/recipes-devtools/python/python_2.7.3.bb
+++ b/meta/recipes-devtools/python/python_2.7.3.bb
@@ -41,6 +41,10 @@ SRC_URI += "\
file://python-2.7.3-CVE-2014-7185.patch \
file://python2.7.3-nossl3.patch \
file://python-2.7.3-CVE-2013-1752-httplib-fix.patch \
+ file://python-2.7.3-CVE-2013-1752-ftplib-fix.patch \
+ file://python-2.7.3-CVE-2013-1752-imaplib-fix.patch \
+ file://python-2.7.3-CVE-2013-1752-nntplib-fix.patch \
+ file://python-2.7.3-CVE-2013-1752-poplib-fix.patch \
"
S = "${WORKDIR}/Python-${PV}"
--
1.9.1
More information about the Openembedded-core
mailing list