]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #17872: Fix a segfault in marshal.load() when input stream returns
authorSerhiy Storchaka <storchaka@gmail.com>
Thu, 11 Jul 2013 19:20:47 +0000 (22:20 +0300)
committerSerhiy Storchaka <storchaka@gmail.com>
Thu, 11 Jul 2013 19:20:47 +0000 (22:20 +0300)
more bytes than requested.

Lib/test/test_marshal.py
Misc/NEWS
Python/marshal.c

index 025b53ccbeb510b7a90dbdf8531f4c5a8817a7a5..7e37f39c6a74d94a1bda3523d7730b72af6bb8ce 100644 (file)
@@ -2,6 +2,7 @@
 
 from test import support
 import array
+import io
 import marshal
 import sys
 import unittest
@@ -279,6 +280,17 @@ class BugsTestCase(unittest.TestCase):
         unicode_string = 'T'
         self.assertRaises(TypeError, marshal.loads, unicode_string)
 
+    def test_bad_reader(self):
+        class BadReader(io.BytesIO):
+            def read(self, n=-1):
+                b = super().read(n)
+                if n is not None and n > 4:
+                    b += b' ' * 10**6
+                return b
+        for value in (1.0, 1j, b'0123456789', '0123456789'):
+            self.assertRaises(ValueError, marshal.load,
+                              BadReader(marshal.dumps(value)))
+
 LARGE_SIZE = 2**31
 pointer_size = 8 if sys.maxsize > 0xFFFFFFFF else 4
 
index ea221cb805056488b95caf6b4bd078c1e6a2b312..3ff4d3e35f28b39377e48fe3025b5898437a9063 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,9 @@ What's New in Python 3.3.3 release candidate 1?
 Core and Builtins
 -----------------
 
+- Issue #17872: Fix a segfault in marshal.load() when input stream returns
+  more bytes than requested.
+
 - Issue #18426: Fix NULL pointer dereference in C extension import when
   PyModule_GetDef() returns an error.
 
index 23764ccb7e2748cb31258222692be73c93d54575..a0e527fc8313cf4d474a322ca5e1c7371cc1a3d7 100644 (file)
@@ -490,8 +490,17 @@ r_string(char *s, Py_ssize_t n, RFILE *p)
             else {
                 read = PyBytes_GET_SIZE(data);
                 if (read > 0) {
-                    ptr = PyBytes_AS_STRING(data);
-                    memcpy(s, ptr, read);
+                    if (read > n) {
+                        PyErr_Format(PyExc_ValueError,
+                                    "read() returned too much data: "
+                                    "%zd bytes requested, %zd returned",
+                                    n, read);
+                        read = -1;
+                    }
+                    else {
+                        ptr = PyBytes_AS_STRING(data);
+                        memcpy(s, ptr, read);
+                    }
                 }
             }
             Py_DECREF(data);
@@ -733,11 +742,13 @@ r_object(RFILE *p)
             double dx;
             retval = NULL;
             n = r_byte(p);
-            if (n == EOF || r_string(buf, n, p) != n) {
+            if (n == EOF) {
                 PyErr_SetString(PyExc_EOFError,
                     "EOF read where object expected");
                 break;
             }
+            if (r_string(buf, n, p) != n)
+                break;
             buf[n] = '\0';
             dx = PyOS_string_to_double(buf, NULL, NULL);
             if (dx == -1.0 && PyErr_Occurred())
@@ -751,8 +762,6 @@ r_object(RFILE *p)
             unsigned char buf[8];
             double x;
             if (r_string((char*)buf, 8, p) != 8) {
-                PyErr_SetString(PyExc_EOFError,
-                    "EOF read where object expected");
                 retval = NULL;
                 break;
             }
@@ -771,21 +780,25 @@ r_object(RFILE *p)
             Py_complex c;
             retval = NULL;
             n = r_byte(p);
-            if (n == EOF || r_string(buf, n, p) != n) {
+            if (n == EOF) {
                 PyErr_SetString(PyExc_EOFError,
                     "EOF read where object expected");
                 break;
             }
+            if (r_string(buf, n, p) != n)
+                break;
             buf[n] = '\0';
             c.real = PyOS_string_to_double(buf, NULL, NULL);
             if (c.real == -1.0 && PyErr_Occurred())
                 break;
             n = r_byte(p);
-            if (n == EOF || r_string(buf, n, p) != n) {
+            if (n == EOF) {
                 PyErr_SetString(PyExc_EOFError,
                     "EOF read where object expected");
                 break;
             }
+            if (r_string(buf, n, p) != n)
+                break;
             buf[n] = '\0';
             c.imag = PyOS_string_to_double(buf, NULL, NULL);
             if (c.imag == -1.0 && PyErr_Occurred())
@@ -799,8 +812,6 @@ r_object(RFILE *p)
             unsigned char buf[8];
             Py_complex c;
             if (r_string((char*)buf, 8, p) != 8) {
-                PyErr_SetString(PyExc_EOFError,
-                    "EOF read where object expected");
                 retval = NULL;
                 break;
             }
@@ -810,8 +821,6 @@ r_object(RFILE *p)
                 break;
             }
             if (r_string((char*)buf, 8, p) != 8) {
-                PyErr_SetString(PyExc_EOFError,
-                    "EOF read where object expected");
                 retval = NULL;
                 break;
             }
@@ -842,8 +851,6 @@ r_object(RFILE *p)
         }
         if (r_string(PyBytes_AS_STRING(v), n, p) != n) {
             Py_DECREF(v);
-            PyErr_SetString(PyExc_EOFError,
-                            "EOF read where object expected");
             retval = NULL;
             break;
         }
@@ -871,8 +878,6 @@ r_object(RFILE *p)
         }
         if (r_string(buffer, n, p) != n) {
             PyMem_DEL(buffer);
-            PyErr_SetString(PyExc_EOFError,
-                "EOF read where object expected");
             retval = NULL;
             break;
         }