From 3641a74e1c03ce153042d2c21639e5b6b9604f3b Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 11 Jul 2013 22:20:47 +0300 Subject: Issue #17872: Fix a segfault in marshal.load() when input stream returns more bytes than requested. --- Lib/test/test_marshal.py | 12 ++++++++++++ Misc/NEWS | 3 +++ Python/marshal.c | 35 ++++++++++++++++++++--------------- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py index 025b53c..7e37f39 100644 --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -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 diff --git a/Misc/NEWS b/Misc/NEWS index ea221cb..3ff4d3e 100644 --- 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. diff --git a/Python/marshal.c b/Python/marshal.c index 23764cc..a0e527f 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -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; } -- cgit v0.12