Commit db9f3355 authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #27599: Fixed buffer overrun in binascii.b2a_qp() and binascii.a2b_qp().

parent 17e73aec
...@@ -178,37 +178,106 @@ class BinASCIITest(unittest.TestCase): ...@@ -178,37 +178,106 @@ class BinASCIITest(unittest.TestCase):
self.assertEqual(binascii.unhexlify(self.type2test(t)), u) self.assertEqual(binascii.unhexlify(self.type2test(t)), u)
def test_qp(self): def test_qp(self):
binascii.a2b_qp(data=b"", header=False) # Keyword arguments allowed type2test = self.type2test
a2b_qp = binascii.a2b_qp
b2a_qp = binascii.b2a_qp
a2b_qp(data=b"", header=False) # Keyword arguments allowed
# A test for SF bug 534347 (segfaults without the proper fix) # A test for SF bug 534347 (segfaults without the proper fix)
try: try:
binascii.a2b_qp(b"", **{1:1}) a2b_qp(b"", **{1:1})
except TypeError: except TypeError:
pass pass
else: else:
self.fail("binascii.a2b_qp(**{1:1}) didn't raise TypeError") self.fail("binascii.a2b_qp(**{1:1}) didn't raise TypeError")
self.assertEqual(binascii.a2b_qp(b"= "), b"= ") self.assertEqual(a2b_qp(type2test(b"=")), b"")
self.assertEqual(binascii.a2b_qp(b"=="), b"=") self.assertEqual(a2b_qp(type2test(b"= ")), b"= ")
self.assertEqual(binascii.a2b_qp(b"=AX"), b"=AX") self.assertEqual(a2b_qp(type2test(b"==")), b"=")
self.assertRaises(TypeError, binascii.b2a_qp, foo="bar") self.assertEqual(a2b_qp(type2test(b"=\nAB")), b"AB")
self.assertEqual(binascii.a2b_qp(b"=00\r\n=00"), b"\x00\r\n\x00") self.assertEqual(a2b_qp(type2test(b"=\r\nAB")), b"AB")
self.assertEqual( self.assertEqual(a2b_qp(type2test(b"=\rAB")), b"") # ?
binascii.b2a_qp(b"\xff\r\n\xff\n\xff"), self.assertEqual(a2b_qp(type2test(b"=\rAB\nCD")), b"CD") # ?
self.assertEqual(a2b_qp(type2test(b"=AB")), b"\xab")
self.assertEqual(a2b_qp(type2test(b"=ab")), b"\xab")
self.assertEqual(a2b_qp(type2test(b"=AX")), b"=AX")
self.assertEqual(a2b_qp(type2test(b"=XA")), b"=XA")
self.assertEqual(a2b_qp(type2test(b"=AB")[:-1]), b"=A")
self.assertEqual(a2b_qp(type2test(b'_')), b'_')
self.assertEqual(a2b_qp(type2test(b'_'), header=True), b' ')
self.assertRaises(TypeError, b2a_qp, foo="bar")
self.assertEqual(a2b_qp(type2test(b"=00\r\n=00")), b"\x00\r\n\x00")
self.assertEqual(b2a_qp(type2test(b"\xff\r\n\xff\n\xff")),
b"=FF\r\n=FF\r\n=FF") b"=FF\r\n=FF\r\n=FF")
self.assertEqual( self.assertEqual(b2a_qp(type2test(b"0"*75+b"\xff\r\n\xff\r\n\xff")),
binascii.b2a_qp(b"0"*75+b"\xff\r\n\xff\r\n\xff"),
b"0"*75+b"=\r\n=FF\r\n=FF\r\n=FF") b"0"*75+b"=\r\n=FF\r\n=FF\r\n=FF")
self.assertEqual(binascii.b2a_qp(b'\0\n'), b'=00\n') self.assertEqual(b2a_qp(type2test(b'\x7f')), b'=7F')
self.assertEqual(binascii.b2a_qp(b'\0\n', quotetabs=True), b'=00\n') self.assertEqual(b2a_qp(type2test(b'=')), b'=3D')
self.assertEqual(binascii.b2a_qp(b'foo\tbar\t\n'), b'foo\tbar=09\n')
self.assertEqual(binascii.b2a_qp(b'foo\tbar\t\n', quotetabs=True), self.assertEqual(b2a_qp(type2test(b'_')), b'_')
b'foo=09bar=09\n') self.assertEqual(b2a_qp(type2test(b'_'), header=True), b'=5F')
self.assertEqual(b2a_qp(type2test(b'x y'), header=True), b'x_y')
self.assertEqual(binascii.b2a_qp(b'.'), b'=2E') self.assertEqual(b2a_qp(type2test(b'x '), header=True), b'x=20')
self.assertEqual(binascii.b2a_qp(b'.\n'), b'=2E\n') self.assertEqual(b2a_qp(type2test(b'x y'), header=True, quotetabs=True),
self.assertEqual(binascii.b2a_qp(b'a.\n'), b'a.\n') b'x=20y')
self.assertEqual(b2a_qp(type2test(b'x\ty'), header=True), b'x\ty')
self.assertEqual(b2a_qp(type2test(b' ')), b'=20')
self.assertEqual(b2a_qp(type2test(b'\t')), b'=09')
self.assertEqual(b2a_qp(type2test(b' x')), b' x')
self.assertEqual(b2a_qp(type2test(b'\tx')), b'\tx')
self.assertEqual(b2a_qp(type2test(b' x')[:-1]), b'=20')
self.assertEqual(b2a_qp(type2test(b'\tx')[:-1]), b'=09')
self.assertEqual(b2a_qp(type2test(b'\0')), b'=00')
self.assertEqual(b2a_qp(type2test(b'\0\n')), b'=00\n')
self.assertEqual(b2a_qp(type2test(b'\0\n'), quotetabs=True), b'=00\n')
self.assertEqual(b2a_qp(type2test(b'x y\tz')), b'x y\tz')
self.assertEqual(b2a_qp(type2test(b'x y\tz'), quotetabs=True),
b'x=20y=09z')
self.assertEqual(b2a_qp(type2test(b'x y\tz'), istext=False),
b'x y\tz')
self.assertEqual(b2a_qp(type2test(b'x \ny\t\n')),
b'x=20\ny=09\n')
self.assertEqual(b2a_qp(type2test(b'x \ny\t\n'), quotetabs=True),
b'x=20\ny=09\n')
self.assertEqual(b2a_qp(type2test(b'x \ny\t\n'), istext=False),
b'x =0Ay\t=0A')
self.assertEqual(b2a_qp(type2test(b'x \ry\t\r')),
b'x \ry\t\r')
self.assertEqual(b2a_qp(type2test(b'x \ry\t\r'), quotetabs=True),
b'x=20\ry=09\r')
self.assertEqual(b2a_qp(type2test(b'x \ry\t\r'), istext=False),
b'x =0Dy\t=0D')
self.assertEqual(b2a_qp(type2test(b'x \r\ny\t\r\n')),
b'x=20\r\ny=09\r\n')
self.assertEqual(b2a_qp(type2test(b'x \r\ny\t\r\n'), quotetabs=True),
b'x=20\r\ny=09\r\n')
self.assertEqual(b2a_qp(type2test(b'x \r\ny\t\r\n'), istext=False),
b'x =0D=0Ay\t=0D=0A')
self.assertEqual(b2a_qp(type2test(b'x \r\n')[:-1]), b'x \r')
self.assertEqual(b2a_qp(type2test(b'x\t\r\n')[:-1]), b'x\t\r')
self.assertEqual(b2a_qp(type2test(b'x \r\n')[:-1], quotetabs=True),
b'x=20\r')
self.assertEqual(b2a_qp(type2test(b'x\t\r\n')[:-1], quotetabs=True),
b'x=09\r')
self.assertEqual(b2a_qp(type2test(b'x \r\n')[:-1], istext=False),
b'x =0D')
self.assertEqual(b2a_qp(type2test(b'x\t\r\n')[:-1], istext=False),
b'x\t=0D')
self.assertEqual(b2a_qp(type2test(b'.')), b'=2E')
self.assertEqual(b2a_qp(type2test(b'.\n')), b'=2E\n')
self.assertEqual(b2a_qp(type2test(b'.\r')), b'=2E\r')
self.assertEqual(b2a_qp(type2test(b'.\0')), b'=2E=00')
self.assertEqual(b2a_qp(type2test(b'a.\n')), b'a.\n')
self.assertEqual(b2a_qp(type2test(b'.a')[:-1]), b'=2E')
def test_empty_string(self): def test_empty_string(self):
# A test for SF bug #1022953. Make sure SystemError is not raised. # A test for SF bug #1022953. Make sure SystemError is not raised.
......
...@@ -71,6 +71,7 @@ Core and Builtins ...@@ -71,6 +71,7 @@ Core and Builtins
Library Library
------- -------
- Issue #27599: Fixed buffer overrun in binascii.b2a_qp() and binascii.a2b_qp().
- Issue #19003:m email.generator now replaces only \r and/or \n line - Issue #19003:m email.generator now replaces only \r and/or \n line
endings, per the RFC, instead of all unicode line endings. endings, per the RFC, instead of all unicode line endings.
......
...@@ -1290,7 +1290,8 @@ binascii_a2b_qp_impl(PyObject *module, Py_buffer *data, int header) ...@@ -1290,7 +1290,8 @@ binascii_a2b_qp_impl(PyObject *module, Py_buffer *data, int header)
odata[out++] = '='; odata[out++] = '=';
in++; in++;
} }
else if (((ascii_data[in] >= 'A' && ascii_data[in] <= 'F') || else if ((in + 1 < datalen) &&
((ascii_data[in] >= 'A' && ascii_data[in] <= 'F') ||
(ascii_data[in] >= 'a' && ascii_data[in] <= 'f') || (ascii_data[in] >= 'a' && ascii_data[in] <= 'f') ||
(ascii_data[in] >= '0' && ascii_data[in] <= '9')) && (ascii_data[in] >= '0' && ascii_data[in] <= '9')) &&
((ascii_data[in+1] >= 'A' && ascii_data[in+1] <= 'F') || ((ascii_data[in+1] >= 'A' && ascii_data[in+1] <= 'F') ||
...@@ -1388,7 +1389,8 @@ binascii_b2a_qp_impl(PyObject *module, Py_buffer *data, int quotetabs, ...@@ -1388,7 +1389,8 @@ binascii_b2a_qp_impl(PyObject *module, Py_buffer *data, int quotetabs,
(databuf[in] == '=') || (databuf[in] == '=') ||
(header && databuf[in] == '_') || (header && databuf[in] == '_') ||
((databuf[in] == '.') && (linelen == 0) && ((databuf[in] == '.') && (linelen == 0) &&
(databuf[in+1] == '\n' || databuf[in+1] == '\r' || databuf[in+1] == 0)) || (in + 1 == datalen || databuf[in+1] == '\n' ||
databuf[in+1] == '\r' || databuf[in+1] == 0)) ||
(!istext && ((databuf[in] == '\r') || (databuf[in] == '\n'))) || (!istext && ((databuf[in] == '\r') || (databuf[in] == '\n'))) ||
((databuf[in] == '\t' || databuf[in] == ' ') && (in + 1 == datalen)) || ((databuf[in] == '\t' || databuf[in] == ' ') && (in + 1 == datalen)) ||
((databuf[in] < 33) && ((databuf[in] < 33) &&
...@@ -1464,13 +1466,13 @@ binascii_b2a_qp_impl(PyObject *module, Py_buffer *data, int quotetabs, ...@@ -1464,13 +1466,13 @@ binascii_b2a_qp_impl(PyObject *module, Py_buffer *data, int quotetabs,
(databuf[in] == '=') || (databuf[in] == '=') ||
(header && databuf[in] == '_') || (header && databuf[in] == '_') ||
((databuf[in] == '.') && (linelen == 0) && ((databuf[in] == '.') && (linelen == 0) &&
(databuf[in+1] == '\n' || databuf[in+1] == '\r' || databuf[in+1] == 0)) || (in + 1 == datalen || databuf[in+1] == '\n' ||
databuf[in+1] == '\r' || databuf[in+1] == 0)) ||
(!istext && ((databuf[in] == '\r') || (databuf[in] == '\n'))) || (!istext && ((databuf[in] == '\r') || (databuf[in] == '\n'))) ||
((databuf[in] == '\t' || databuf[in] == ' ') && (in + 1 == datalen)) || ((databuf[in] == '\t' || databuf[in] == ' ') && (in + 1 == datalen)) ||
((databuf[in] < 33) && ((databuf[in] < 33) &&
(databuf[in] != '\r') && (databuf[in] != '\n') && (databuf[in] != '\r') && (databuf[in] != '\n') &&
(quotetabs || (quotetabs || ((databuf[in] != '\t') && (databuf[in] != ' ')))))
(!quotetabs && ((databuf[in] != '\t') && (databuf[in] != ' '))))))
{ {
if ((linelen + 3 )>= MAXLINESIZE) { if ((linelen + 3 )>= MAXLINESIZE) {
odata[out++] = '='; odata[out++] = '=';
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment