From b93d7d52b5f0b91fe36615fae417e6f15e6b95a3 Mon Sep 17 00:00:00 2001 From: Neal Norwitz Date: Thu, 31 Jul 2008 17:04:32 +0000 Subject: [PATCH] Security patches from Apple: prevent int overflow when allocating memory --- Misc/NEWS | 2 ++ Modules/gcmodule.c | 7 +++++- Modules/mmapmodule.c | 2 +- Modules/stropmodule.c | 15 +++++++++++++ Objects/bufferobject.c | 4 ++++ Objects/stringobject.c | 18 ++++++++++++++- Objects/tupleobject.c | 5 +++-- Objects/unicodeobject.c | 49 ++++++++++++++++++++++++++++++++--------- 8 files changed, 87 insertions(+), 15 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS index 517849208cfe..7b504b328bd9 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,8 @@ What's New in Python 2.4.5c1? Core and builtins ----------------- +- Apply security patches from Apple. + - Issue #2620: Overflow checking when allocating or reallocating memory was not always being done properly in some python types and extension modules. PyMem_MALLOC, PyMem_REALLOC, PyMem_NEW and PyMem_RESIZE have diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index e8971b0d2b64..c9ba42910513 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1249,7 +1249,10 @@ PyObject * _PyObject_GC_Malloc(size_t basicsize) { PyObject *op; - PyGC_Head *g = PyObject_MALLOC(sizeof(PyGC_Head) + basicsize); + PyGC_Head *g; + if (basicsize > INT_MAX - sizeof(PyGC_Head)) + return PyErr_NoMemory(); + g = PyObject_MALLOC(sizeof(PyGC_Head) + basicsize); if (g == NULL) return PyErr_NoMemory(); g->gc.gc_refs = GC_UNTRACKED; @@ -1291,6 +1294,8 @@ _PyObject_GC_Resize(PyVarObject *op, int nitems) { const size_t basicsize = _PyObject_VAR_SIZE(op->ob_type, nitems); PyGC_Head *g = AS_GC(op); + if (basicsize > INT_MAX - sizeof(PyGC_Head)) + return (PyVarObject *)PyErr_NoMemory(); g = PyObject_REALLOC(g, sizeof(PyGC_Head) + basicsize); if (g == NULL) return (PyVarObject *)PyErr_NoMemory(); diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index ac647bfadb18..7bcf4c8a8b0e 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -223,7 +223,7 @@ mmap_read_method(mmap_object *self, return(NULL); /* silently 'adjust' out-of-range requests */ - if ((self->pos + num_bytes) > self->size) { + if (num_bytes > self->size - self->pos) { num_bytes -= (self->pos+num_bytes) - self->size; } result = Py_BuildValue("s#", self->data+self->pos, num_bytes); diff --git a/Modules/stropmodule.c b/Modules/stropmodule.c index e0d686b1a39b..6528eb18e8cf 100644 --- a/Modules/stropmodule.c +++ b/Modules/stropmodule.c @@ -214,6 +214,13 @@ strop_joinfields(PyObject *self, PyObject *args) return NULL; } slen = PyString_GET_SIZE(item); + if (slen > INT_MAX - reslen || + seplen > INT_MAX - reslen - seplen) { + PyErr_SetString(PyExc_OverflowError, + "input too long"); + Py_DECREF(res); + return NULL; + } while (reslen + slen + seplen >= sz) { if (_PyString_Resize(&res, sz * 2) < 0) return NULL; @@ -251,6 +258,14 @@ strop_joinfields(PyObject *self, PyObject *args) return NULL; } slen = PyString_GET_SIZE(item); + if (slen > INT_MAX - reslen || + seplen > INT_MAX - reslen - seplen) { + PyErr_SetString(PyExc_OverflowError, + "input too long"); + Py_DECREF(res); + Py_XDECREF(item); + return NULL; + } while (reslen + slen + seplen >= sz) { if (_PyString_Resize(&res, sz * 2) < 0) { Py_DECREF(item); diff --git a/Objects/bufferobject.c b/Objects/bufferobject.c index 53bcb1e94ccb..9639e8aa4145 100644 --- a/Objects/bufferobject.c +++ b/Objects/bufferobject.c @@ -384,6 +384,10 @@ buffer_repeat(PyBufferObject *self, int count) count = 0; if (!get_buf(self, &ptr, &size)) return NULL; + if (count > INT_MAX / size) { + PyErr_SetString(PyExc_MemoryError, "result too large"); + return NULL; + } ob = PyString_FromStringAndSize(NULL, size * count); if ( ob == NULL ) return NULL; diff --git a/Objects/stringobject.c b/Objects/stringobject.c index 7395010e1629..ee1c3bf8257e 100644 --- a/Objects/stringobject.c +++ b/Objects/stringobject.c @@ -69,6 +69,11 @@ PyString_FromStringAndSize(const char *str, int size) return (PyObject *)op; } + if (size > INT_MAX - sizeof(PyStringObject)) { + PyErr_SetString(PyExc_OverflowError, "string is too large"); + return NULL; + } + /* Inline PyObject_NewVar */ op = (PyStringObject *)PyObject_MALLOC(sizeof(PyStringObject) + size); if (op == NULL) @@ -104,7 +109,7 @@ PyString_FromString(const char *str) assert(str != NULL); size = strlen(str); - if (size > INT_MAX) { + if (size > INT_MAX - sizeof(PyStringObject)) { PyErr_SetString(PyExc_OverflowError, "string is too long for a Python string"); return NULL; @@ -907,7 +912,18 @@ string_concat(register PyStringObject *a, register PyObject *bb) Py_INCREF(a); return (PyObject *)a; } + /* Check that string sizes are not negative, to prevent an + overflow in cases where we are passed incorrectly-created + strings with negative lengths (due to a bug in other code). + */ size = a->ob_size + b->ob_size; + if (a->ob_size < 0 || b->ob_size < 0 || + a->ob_size > INT_MAX - b->ob_size) { + PyErr_SetString(PyExc_OverflowError, + "strings are too large to concat"); + return NULL; + } + /* Inline PyObject_NewVar */ op = (PyStringObject *)PyObject_MALLOC(sizeof(PyStringObject) + size); if (op == NULL) diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 74b905626c17..bb0cd66538af 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -60,11 +60,12 @@ PyTuple_New(register int size) int nbytes = size * sizeof(PyObject *); /* Check for overflow */ if (nbytes / sizeof(PyObject *) != (size_t)size || - (nbytes += sizeof(PyTupleObject) - sizeof(PyObject *)) - <= 0) + (nbytes > INT_MAX - sizeof(PyTupleObject) - sizeof(PyObject *))) { return PyErr_NoMemory(); } + nbytes += sizeof(PyTupleObject) - sizeof(PyObject *); + op = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, size); if (op == NULL) return NULL; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 880b9ac612db..b29e7ff5442e 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -186,6 +186,11 @@ PyUnicodeObject *_PyUnicode_New(int length) return unicode_empty; } + /* Ensure we won't overflow the size. */ + if (length > ((INT_MAX / sizeof(Py_UNICODE)) - 1)) { + return (PyUnicodeObject *)PyErr_NoMemory(); + } + /* Unicode freelist & memory allocation */ if (unicode_freelist) { unicode = unicode_freelist; @@ -1040,6 +1045,9 @@ PyObject *PyUnicode_EncodeUTF7(const Py_UNICODE *s, char * out; char * start; + if (cbAllocated / 5 != size) + return PyErr_NoMemory(); + if (size == 0) return PyString_FromStringAndSize(NULL, 0); @@ -1638,6 +1646,7 @@ PyUnicode_EncodeUTF16(const Py_UNICODE *s, { PyObject *v; unsigned char *p; + int nsize, bytesize; #ifdef Py_UNICODE_WIDE int i, pairs; #else @@ -1662,8 +1671,15 @@ PyUnicode_EncodeUTF16(const Py_UNICODE *s, if (s[i] >= 0x10000) pairs++; #endif - v = PyString_FromStringAndSize(NULL, - 2 * (size + pairs + (byteorder == 0))); + /* 2 * (size + pairs + (byteorder == 0)) */ + if (size > INT_MAX || + size > INT_MAX - pairs - (byteorder == 0)) + return PyErr_NoMemory(); + nsize = (size + pairs + (byteorder == 0)); + bytesize = nsize * 2; + if (bytesize / 2 != nsize) + return PyErr_NoMemory(); + v = PyString_FromStringAndSize(NULL, bytesize); if (v == NULL) return NULL; @@ -1977,6 +1993,11 @@ PyObject *unicodeescape_string(const Py_UNICODE *s, char *p; static const char *hexdigit = "0123456789abcdef"; +#ifdef Py_UNICODE_WIDE + const int expandsize = 10; +#else + const int expandsize = 6; +#endif /* Initial allocation is based on the longest-possible unichr escape. @@ -1992,13 +2013,12 @@ PyObject *unicodeescape_string(const Py_UNICODE *s, escape. */ + if (size > (INT_MAX - 2 - 1) / expandsize) + return PyErr_NoMemory(); + repr = PyString_FromStringAndSize(NULL, 2 -#ifdef Py_UNICODE_WIDE - + 10*size -#else - + 6*size -#endif + + expandsize*size + 1); if (repr == NULL) return NULL; @@ -2239,12 +2259,16 @@ PyObject *PyUnicode_EncodeRawUnicodeEscape(const Py_UNICODE *s, char *q; static const char *hexdigit = "0123456789abcdef"; - #ifdef Py_UNICODE_WIDE - repr = PyString_FromStringAndSize(NULL, 10 * size); + const int expandsize = 10; #else - repr = PyString_FromStringAndSize(NULL, 6 * size); + const int expandsize = 6; #endif + + if (size > INT_MAX / expandsize) + return PyErr_NoMemory(); + + repr = PyString_FromStringAndSize(NULL, expandsize * size); if (repr == NULL) return NULL; if (size == 0) @@ -4289,6 +4313,11 @@ PyUnicodeObject *pad(PyUnicodeObject *self, return self; } + if (left > INT_MAX - self->length || + right > INT_MAX - (left + self->length)) { + PyErr_SetString(PyExc_OverflowError, "padded string is too long"); + return NULL; + } u = _PyUnicode_New(left + self->length + right); if (u) { if (left) -- 2.47.3