pkgsrc-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Python 2.4 & 2.5 vulnerable, Patches inside



Python 2.4 and 2.5 are vulnerable to a bunch of overflows.
I attached the Apple patches, it would be nice if you could add them to
the package ASAP.
Yes, I know, 8 patches is a lot…

-- 
Jonathan
Index: Python-2.4.4/Objects/unicodeobject.c
===================================================================
--- Python-2.4.4.orig/Objects/unicodeobject.c
+++ Python-2.4.4/Objects/unicodeobject.c
@@ -186,6 +186,11 @@ PyUnicodeObject *_PyUnicode_New(int leng
         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_
     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 *
 {
     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 *
        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_
     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_
        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_EncodeRawUnicodeEsca
     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 *se
         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)
Index: Python-2.4.4/Objects/tupleobject.c
===================================================================
--- Python-2.4.4.orig/Objects/tupleobject.c
+++ Python-2.4.4/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;
Index: Python-2.4.4/Objects/bufferobject.c
===================================================================
--- Python-2.4.4.orig/Objects/bufferobject.c
+++ Python-2.4.4/Objects/bufferobject.c
@@ -384,6 +384,10 @@ buffer_repeat(PyBufferObject *self, int 
                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;
Index: Python-2.4.4/Objects/stringobject.c
===================================================================
--- Python-2.4.4.orig/Objects/stringobject.c
+++ Python-2.4.4/Objects/stringobject.c
@@ -69,6 +69,11 @@ PyString_FromStringAndSize(const char *s
                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
                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)
Index: Python-2.4.4/Misc/NEWS
===================================================================
--- Python-2.4.4.orig/Misc/NEWS
+++ Python-2.4.4/Misc/NEWS
@@ -23,6 +23,8 @@ What's New in Python 2.4.4c1?
 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
Index: Python-2.4.4/Modules/mmapmodule.c
===================================================================
--- Python-2.4.4.orig/Modules/mmapmodule.c
+++ Python-2.4.4/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);
Index: Python-2.4.4/Modules/stropmodule.c
===================================================================
--- Python-2.4.4.orig/Modules/stropmodule.c
+++ Python-2.4.4/Modules/stropmodule.c
@@ -214,6 +214,13 @@ strop_joinfields(PyObject *self, PyObjec
                                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, PyObjec
                        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);
Index: Python-2.4.4/Modules/gcmodule.c
===================================================================
--- Python-2.4.4.orig/Modules/gcmodule.c
+++ Python-2.4.4/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
 {
        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();
r65262 | neal.norwitz | 2008-07-28 07:22:45 +0200 (Mon, 28 Jul 2008) | 11 lines

Backport r65182.  This change modified from using the unsigned max value
to the signed max value similar to 2.5 and trunk.

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
all been updated to perform better checks and places in the code that
would previously leak memory on the error path when such an allocation
failed have been fixed.


Index: Python-2.4.4/Include/pymem.h
===================================================================
--- Python-2.4.4.orig/Include/pymem.h
+++ Python-2.4.4/Include/pymem.h
@@ -66,8 +66,12 @@ PyAPI_FUNC(void) PyMem_Free(void *);
    for malloc(0), which would be treated as an error. Some platforms
    would return a pointer with no memory behind it, which would break
    pymalloc. To solve these problems, allocate an extra byte. */
-#define PyMem_MALLOC(n)         malloc((n) ? (n) : 1)
-#define PyMem_REALLOC(p, n)     realloc((p), (n) ? (n) : 1)
+/* Returns NULL to indicate error if a negative size or size larger than
+   Py_ssize_t can represent is supplied.  Helps prevents security holes. */
+#define PyMem_MALLOC(n)                (((n) < 0 || (n) > INT_MAX) ? NULL \
+                               : malloc((n) ? (n) : 1))
+#define PyMem_REALLOC(p, n)    (((n) < 0 || (n) > INT_MAX) ? NULL \
+                               : realloc((p), (n) ? (n) : 1))
 
 #endif /* PYMALLOC_DEBUG */
 
@@ -80,24 +84,31 @@ PyAPI_FUNC(void) PyMem_Free(void *);
  * Type-oriented memory interface
  * ==============================
  *
- * These are carried along for historical reasons.  There's rarely a good
- * reason to use them anymore (you can just as easily do the multiply and
- * cast yourself).
+ * Allocate memory for n objects of the given type.  Returns a new pointer
+ * or NULL if the request was too large or memory allocation failed.  Use
+ * these macros rather than doing the multiplication yourself so that proper
+ * overflow checking is always done.
  */
 
 #define PyMem_New(type, n) \
-  ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
+  ( ((n) > INT_MAX / sizeof(type)) ? NULL : \
        ( (type *) PyMem_Malloc((n) * sizeof(type)) ) )
 #define PyMem_NEW(type, n) \
-  ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
+  ( ((n) > INT_MAX / sizeof(type)) ? NULL : \
        ( (type *) PyMem_MALLOC((n) * sizeof(type)) ) )
 
+/*
+ * The value of (p) is always clobbered by this macro regardless of success.
+ * The caller MUST check if (p) is NULL afterwards and deal with the memory
+ * error if so.  This means the original value of (p) MUST be saved for the
+ * caller's memory error handler to not lose track of it.
+ */
 #define PyMem_Resize(p, type, n) \
-  ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
-       ( (p) = (type *) PyMem_Realloc((p), (n) * sizeof(type)) ) )
+  ( (p) = ((n) > INT_MAX / sizeof(type)) ? NULL : \
+       (type *) PyMem_Realloc((p), (n) * sizeof(type)) )
 #define PyMem_RESIZE(p, type, n) \
-  ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
-       ( (p) = (type *) PyMem_REALLOC((p), (n) * sizeof(type)) ) )
+  ( (p) = ((n) > INT_MAX / sizeof(type)) ? NULL : \
+       (type *) PyMem_REALLOC((p), (n) * sizeof(type)) )
 
 /* In order to avoid breaking old code mixing PyObject_{New, NEW} with
    PyMem_{Del, DEL} and PyMem_{Free, FREE}, the PyMem "release memory"
Index: Python-2.4.4/Objects/obmalloc.c
===================================================================
--- Python-2.4.4.orig/Objects/obmalloc.c
+++ Python-2.4.4/Objects/obmalloc.c
@@ -585,6 +585,15 @@ PyObject_Malloc(size_t nbytes)
        uint size;
 
        /*
+        * Limit ourselves to INT_MAX bytes to prevent security holes.
+        * Most python internals blindly use a signed Py_ssize_t to track
+        * things without checking for overflows or negatives.
+        * As size_t is unsigned, checking for nbytes < 0 is not required.
+        */
+       if (nbytes > INT_MAX)
+               return NULL;
+
+       /*
         * This implicitly redirects malloc(0).
         */
        if ((nbytes - 1) < SMALL_REQUEST_THRESHOLD) {
@@ -814,6 +823,15 @@ PyObject_Realloc(void *p, size_t nbytes)
        if (p == NULL)
                return PyObject_Malloc(nbytes);
 
+       /*
+        * Limit ourselves to INT_MAX bytes to prevent security holes.
+        * Most python internals blindly use a signed Py_ssize_t to track
+        * things without checking for overflows or negatives.
+        * As size_t is unsigned, checking for nbytes < 0 is not required.
+        */
+       if (nbytes > INT_MAX)
+               return NULL;
+
        pool = POOL_ADDR(p);
        if (Py_ADDRESS_IN_RANGE(p, pool)) {
                /* We're in charge of this block */
Index: Python-2.4.4/Misc/NEWS
===================================================================
--- Python-2.4.4.orig/Misc/NEWS
+++ Python-2.4.4/Misc/NEWS
@@ -23,6 +23,13 @@ What's New in Python 2.4.4c1?
 Core and builtins
 -----------------
 
+- 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
+  all been updated to perform better checks and places in the code that
+  would previously leak memory on the error path when such an allocation
+  failed have been fixed.
+
 - Added checks for integer overflows, contributed by Google. Some are
   only available if asserts are left in the code, in cases where they
   can't be triggered from Python code.
Index: Python-2.4.4/Modules/almodule.c
===================================================================
--- Python-2.4.4.orig/Modules/almodule.c
+++ Python-2.4.4/Modules/almodule.c
@@ -1633,9 +1633,11 @@ al_QueryValues(PyObject *self, PyObject 
        if (nvals < 0)
                goto cleanup;
        if (nvals > setsize) {
+               ALvalue *old_return_set = return_set;
                setsize = nvals;
                PyMem_RESIZE(return_set, ALvalue, setsize);
                if (return_set == NULL) {
+                       return_set = old_return_set;
                        PyErr_NoMemory();
                        goto cleanup;
                }
Index: Python-2.4.4/Modules/arraymodule.c
===================================================================
--- Python-2.4.4.orig/Modules/arraymodule.c
+++ Python-2.4.4/Modules/arraymodule.c
@@ -814,6 +814,7 @@ static int
 array_do_extend(arrayobject *self, PyObject *bb)
 {
        int size;
+       char *old_item;
 
        if (!array_Check(bb))
                return array_iter_extend(self, bb);
@@ -829,10 +830,11 @@ array_do_extend(arrayobject *self, PyObj
                        return -1;
        }
        size = self->ob_size + b->ob_size;
+       old_item = self->ob_item;
         PyMem_RESIZE(self->ob_item, char, size*self->ob_descr->itemsize);
         if (self->ob_item == NULL) {
-                PyObject_Del(self);
-                PyErr_NoMemory();
+               self->ob_item = old_item;
+               PyErr_NoMemory();
                return -1;
         }
        memcpy(self->ob_item + self->ob_size*self->ob_descr->itemsize,
@@ -884,7 +886,7 @@ array_inplace_repeat(arrayobject *self, 
                        if (size > INT_MAX / n) {
                                return PyErr_NoMemory();
                        }
-                       PyMem_Resize(items, char, n * size);
+                       PyMem_RESIZE(items, char, n * size);
                        if (items == NULL)
                                return PyErr_NoMemory();
                        p = items;
Index: Python-2.4.4/Modules/selectmodule.c
===================================================================
--- Python-2.4.4.orig/Modules/selectmodule.c
+++ Python-2.4.4/Modules/selectmodule.c
@@ -342,10 +342,12 @@ update_ufd_array(pollObject *self)
 {
        int i, pos;
        PyObject *key, *value;
+        struct pollfd *old_ufds = self->ufds;
 
        self->ufd_len = PyDict_Size(self->dict);
-       PyMem_Resize(self->ufds, struct pollfd, self->ufd_len);
+       PyMem_RESIZE(self->ufds, struct pollfd, self->ufd_len);
        if (self->ufds == NULL) {
+                self->ufds = old_ufds;
                PyErr_NoMemory();
                return 0;
        }
r61180 | martin.v.loewis | 2008-03-02 20:20:32 +0100 (Sun, 02 Mar 2008) | 5 
lines

Backport of r60793:
Added checks for integer overflows, contributed by Google. Some are
only available if asserts are left in the code, in cases where they
can't be triggered from Python code.

Index: Python-2.4.4/Python/bltinmodule.c
===================================================================
--- Python-2.4.4.orig/Python/bltinmodule.c
+++ Python-2.4.4/Python/bltinmodule.c
@@ -2376,11 +2376,43 @@ filterstring(PyObject *func, PyObject *s
                                        PyString_AS_STRING(item)[0];
                        } else {
                                /* do we need more space? */
-                               int need = j + reslen + len-i-1;
+                               int need = j;
+
+                               /* calculate space requirements while checking 
for overflow */
+                               if (need > INT_MAX - reslen) {
+                                       Py_DECREF(item);
+                                       goto Fail_1;
+                               }
+
+                               need += reslen;
+
+                               if (need > INT_MAX - len) {
+                                       Py_DECREF(item);
+                                       goto Fail_1;
+                               }
+
+                               need += len;
+
+                               if (need <= i) {
+                                       Py_DECREF(item);
+                                       goto Fail_1;
+                               }
+
+                               need = need - i - 1;
+
+                               assert(need >= 0);
+                               assert(outlen >= 0);
+
                                if (need > outlen) {
                                        /* overallocate, to avoid reallocations 
*/
-                                       if (need<2*outlen)
+                                       if (outlen > INT_MAX / 2) {
+                                               Py_DECREF(item);
+                                               return NULL;
+                                       }
+
+                                       if (need<2*outlen) {
                                                need = 2*outlen;
+          }
                                        if (_PyString_Resize(&result, need)) {
                                                Py_DECREF(item);
                                                return NULL;
@@ -2472,11 +2504,31 @@ filterunicode(PyObject *func, PyObject *
                        else {
                                /* do we need more space? */
                                int need = j + reslen + len - i - 1;
+
+                               /* check that didnt overflow */
+                               if ((j > INT_MAX - reslen) ||
+                                       ((j + reslen) > INT_MAX - len) ||
+                                               ((j + reslen + len) < i) ||
+                                                       ((j + reslen + len - i) 
<= 0)) {
+                                       Py_DECREF(item);
+                                       return NULL;
+                               }
+
+                               assert(need >= 0);
+                               assert(outlen >= 0);
+
                                if (need > outlen) {
                                        /* overallocate, 
                                           to avoid reallocations */
-                                       if (need < 2 * outlen)
-                                               need = 2 * outlen;
+                                       if (need < 2 * outlen) {
+                                               if (outlen > INT_MAX / 2) {
+                                                       Py_DECREF(item);
+                                                       return NULL;
+                                               } else {
+                                                       need = 2 * outlen;
+                                               }
+                                       }
+
                                        if (PyUnicode_Resize(
                                                &result, need) < 0) {
                                                Py_DECREF(item);
Index: Python-2.4.4/Include/pyport.h
===================================================================
--- Python-2.4.4.orig/Include/pyport.h
+++ Python-2.4.4/Include/pyport.h
@@ -616,6 +616,17 @@ typedef    struct fd_set {
 #error "LONG_BIT definition appears wrong for platform (bad gcc/glibc 
config?)."
 #endif
 
+/* Largest possible value of size_t.
+   SIZE_MAX is part of C99, so it might be defined on some
+   platforms. If it is not defined, (size_t)-1 is a portable
+   definition for C89, due to the way signed->unsigned
+   conversion is defined. */
+#ifdef SIZE_MAX
+#define PY_SIZE_MAX SIZE_MAX
+#else
+#define PY_SIZE_MAX ((size_t)-1)
+#endif
+
 #ifdef __cplusplus
 }
 #endif
Index: Python-2.4.4/Include/pymem.h
===================================================================
--- Python-2.4.4.orig/Include/pymem.h
+++ Python-2.4.4/Include/pymem.h
@@ -86,14 +86,18 @@ PyAPI_FUNC(void) PyMem_Free(void *);
  */
 
 #define PyMem_New(type, n) \
-       ( (type *) PyMem_Malloc((n) * sizeof(type)) )
+  ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
+       ( (type *) PyMem_Malloc((n) * sizeof(type)) ) )
 #define PyMem_NEW(type, n) \
-       ( (type *) PyMem_MALLOC((n) * sizeof(type)) )
+  ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
+       ( (type *) PyMem_MALLOC((n) * sizeof(type)) ) )
 
 #define PyMem_Resize(p, type, n) \
-       ( (p) = (type *) PyMem_Realloc((p), (n) * sizeof(type)) )
+  ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
+       ( (p) = (type *) PyMem_Realloc((p), (n) * sizeof(type)) ) )
 #define PyMem_RESIZE(p, type, n) \
-       ( (p) = (type *) PyMem_REALLOC((p), (n) * sizeof(type)) )
+  ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
+       ( (p) = (type *) PyMem_REALLOC((p), (n) * sizeof(type)) ) )
 
 /* In order to avoid breaking old code mixing PyObject_{New, NEW} with
    PyMem_{Del, DEL} and PyMem_{Free, FREE}, the PyMem "release memory"
Index: Python-2.4.4/Objects/bufferobject.c
===================================================================
--- Python-2.4.4.orig/Objects/bufferobject.c
+++ Python-2.4.4/Objects/bufferobject.c
@@ -167,6 +167,10 @@ PyBuffer_New(int size)
                                "size must be zero or positive");
                return NULL;
        }
+       if (sizeof(*b) > INT_MAX - size) {
+               /* unlikely */
+               return PyErr_NoMemory();
+       }
        /* Inline PyObject_New */
        o = PyObject_MALLOC(sizeof(*b) + size);
        if ( o == NULL )
@@ -355,6 +359,8 @@ buffer_concat(PyBufferObject *self, PyOb
        if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
                return NULL;
 
+       assert(count <= PY_SIZE_MAX - size);
+
        ob = PyString_FromStringAndSize(NULL, size + count);
        p = PyString_AS_STRING(ob);
        memcpy(p, ptr1, size);
Index: Python-2.4.4/Objects/listobject.c
===================================================================
--- Python-2.4.4.orig/Objects/listobject.c
+++ Python-2.4.4/Objects/listobject.c
@@ -45,7 +45,16 @@ list_resize(PyListObject *self, int news
         * system realloc().
         * The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
         */
-       new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
+       new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);
+
+       /* check for integer overflow */
+       if (new_allocated > PY_SIZE_MAX - newsize) {
+               PyErr_NoMemory();
+               return -1;
+       } else {
+               new_allocated += newsize;
+       }
+
        if (newsize == 0)
                new_allocated = 0;
        items = self->ob_item;
@@ -92,8 +101,9 @@ PyList_New(int size)
                return NULL;
        }
        nbytes = size * sizeof(PyObject *);
-       /* Check for overflow */
-       if (nbytes / sizeof(PyObject *) != (size_t)size)
+       /* Check for overflow without an actual overflow,
+        *  which can cause compiler to optimise out */
+       if (size > PY_SIZE_MAX / sizeof(PyObject *))
                return PyErr_NoMemory();
        if (num_free_lists) {
                num_free_lists--;
@@ -1372,6 +1382,10 @@ merge_getmem(MergeState *ms, int need)
         * we don't care what's in the block.
         */
        merge_freemem(ms);
+       if (need > INT_MAX / sizeof(PyObject*)) {
+               PyErr_NoMemory();
+               return -1;
+       }
        ms->a = (PyObject **)PyMem_Malloc(need * sizeof(PyObject*));
        if (ms->a) {
                ms->alloced = need;
@@ -2550,6 +2564,8 @@ list_ass_subscript(PyListObject* self, P
                                step = -step;
                        }
 
+                       assert(slicelength <= PY_SIZE_MAX / sizeof(PyObject*));
+
                        garbage = (PyObject**)
                                PyMem_MALLOC(slicelength*sizeof(PyObject*));
                        if (!garbage) {
Index: Python-2.4.4/Misc/NEWS
===================================================================
--- Python-2.4.4.orig/Misc/NEWS
+++ Python-2.4.4/Misc/NEWS
@@ -23,6 +23,10 @@ What's New in Python 2.4.4c1?
 Core and builtins
 -----------------
 
+- Added checks for integer overflows, contributed by Google. Some are
+  only available if asserts are left in the code, in cases where they
+  can't be triggered from Python code.
+
 - Bug #1456209: In some obscure cases it was possible for a class with a
   custom ``__eq__()`` method to confuse dict internals when class instances
   were used as a dict's keys and the ``__eq__()`` method mutated the dict.
Index: Python-2.4.4/Parser/node.c
===================================================================
--- Python-2.4.4.orig/Parser/node.c
+++ Python-2.4.4/Parser/node.c
@@ -91,6 +91,9 @@ PyNode_AddChild(register node *n1, int t
        if (current_capacity < 0 || required_capacity < 0)
                return E_OVERFLOW;
        if (current_capacity < required_capacity) {
+               if (required_capacity > PY_SIZE_MAX / sizeof(node)) {
+                       return E_NOMEM;
+               }
                n = n1->n_child;
                n = (node *) PyObject_REALLOC(n,
                                              required_capacity * sizeof(node));
Index: Python-2.4.4/Modules/rgbimgmodule.c
===================================================================
--- Python-2.4.4.orig/Modules/rgbimgmodule.c
+++ Python-2.4.4/Modules/rgbimgmodule.c
@@ -269,7 +269,7 @@ longimagedata(PyObject *self, PyObject *
        Py_Int32 *starttab = NULL, *lengthtab = NULL;
        FILE *inf = NULL;
        IMAGE image;
-       int y, z, tablen;
+       int y, z, tablen, new_size;
        int xsize, ysize, zsize;
        int bpp, rle, cur, badorder;
        int rlebuflen;
@@ -306,9 +306,15 @@ longimagedata(PyObject *self, PyObject *
         }
        if (rle) {
                tablen = ysize * zsize * sizeof(Py_Int32);
+               rlebuflen = (int) (1.05 * xsize +10);
+               if ((tablen / sizeof(Py_Int32)) != (ysize * zsize) ||
+                   rlebuflen < 0) {
+                       PyErr_NoMemory();
+                       goto finally;
+               }
+
                starttab = (Py_Int32 *)malloc(tablen);
                lengthtab = (Py_Int32 *)malloc(tablen);
-               rlebuflen = (int) (1.05 * xsize +10);
                rledat = (unsigned char *)malloc(rlebuflen);
                if (!starttab || !lengthtab || !rledat) {
                        PyErr_NoMemory();
@@ -336,8 +342,14 @@ longimagedata(PyObject *self, PyObject *
 
                fseek(inf, 512 + 2 * tablen, SEEK_SET);
                cur = 512 + 2 * tablen;
+               new_size = xsize * ysize + TAGLEN;
+               if (new_size < 0 || (new_size * sizeof(Py_Int32)) < 0) {
+                       PyErr_NoMemory();
+                       goto finally;
+               }
+
                rv = PyString_FromStringAndSize((char *)NULL,
-                                     (xsize * ysize + TAGLEN) * 
sizeof(Py_Int32));
+                                     new_size * sizeof(Py_Int32));
                if (rv == NULL)
                        goto finally;
 
@@ -405,8 +417,14 @@ longimagedata(PyObject *self, PyObject *
                        copybw((Py_Int32 *) base, xsize * ysize);
        }
        else {
+               new_size = xsize * ysize + TAGLEN;
+               if (new_size < 0 || (new_size * sizeof(Py_Int32)) < 0) {
+                       PyErr_NoMemory();
+                       goto finally;
+               }
+
                rv = PyString_FromStringAndSize((char *) 0,
-                                          
(xsize*ysize+TAGLEN)*sizeof(Py_Int32));
+                                               new_size*sizeof(Py_Int32));
                if (rv == NULL)
                        goto finally;
 
@@ -595,10 +613,16 @@ longstoimage(PyObject *self, PyObject *a
                return NULL;
        }
        tablen = ysize * zsize * sizeof(Py_Int32);
+       rlebuflen = (int) (1.05 * xsize + 10);
+
+       if ((tablen / sizeof(Py_Int32)) != (ysize * zsize) ||
+           rlebuflen < 0 || (xsize * sizeof(Py_Int32)) < 0) {
+               PyErr_NoMemory();
+               goto finally;
+       }
 
        starttab = (Py_Int32 *)malloc(tablen);
        lengthtab = (Py_Int32 *)malloc(tablen);
-       rlebuflen = (int) (1.05 * xsize + 10);
        rlebuf = (unsigned char *)malloc(rlebuflen);
        lumbuf = (unsigned char *)malloc(xsize * sizeof(Py_Int32));
        if (!starttab || !lengthtab || !rlebuf || !lumbuf) {
Index: Python-2.4.4/Modules/datetimemodule.c
===================================================================
--- Python-2.4.4.orig/Modules/datetimemodule.c
+++ Python-2.4.4/Modules/datetimemodule.c
@@ -1111,6 +1111,8 @@ format_utcoffset(char *buf, size_t bufle
        char sign;
        int none;
 
+       assert(buflen >= 1);
+
        offset = call_utcoffset(tzinfo, tzinfoarg, &none);
        if (offset == -1 && PyErr_Occurred())
                return -1;
@@ -1188,6 +1190,11 @@ wrap_strftime(PyObject *object, PyObject
         * a new format.  Since computing the replacements for those codes
         * is expensive, don't unless they're actually used.
         */
+       if (PyString_Size(format) > INT_MAX - 1) {
+               PyErr_NoMemory();
+               goto Done;
+       }
+
        totalnew = PyString_Size(format) + 1;   /* realistic if no %z/%Z */
        newfmt = PyString_FromStringAndSize(NULL, totalnew);
        if (newfmt == NULL) goto Done;
Index: Python-2.4.4/Modules/cjkcodecs/multibytecodec.c
===================================================================
--- Python-2.4.4.orig/Modules/cjkcodecs/multibytecodec.c
+++ Python-2.4.4/Modules/cjkcodecs/multibytecodec.c
@@ -100,12 +100,16 @@ get_errorcallback(const char *errors)
 static int
 expand_encodebuffer(MultibyteEncodeBuffer *buf, int esize)
 {
-       int orgpos, orgsize;
+       int orgpos, orgsize, incsize;
 
        orgpos = (int)((char*)buf->outbuf - PyString_AS_STRING(buf->outobj));
        orgsize = PyString_GET_SIZE(buf->outobj);
-       if (_PyString_Resize(&buf->outobj, orgsize + (
-           esize < (orgsize >> 1) ? (orgsize >> 1) | 1 : esize)) == -1)
+       incsize = (esize < (orgsize >> 1) ? (orgsize >> 1) | 1 : esize);
+
+       if (orgsize > INT_MAX - incsize)
+               return -1;
+
+       if (_PyString_Resize(&buf->outobj, orgsize + incsize) == -1)
                return -1;
 
        buf->outbuf = (unsigned char *)PyString_AS_STRING(buf->outobj) +orgpos;
@@ -416,6 +420,12 @@ multibytecodec_encode(MultibyteCodec *co
        buf.excobj = NULL;
        buf.inbuf = buf.inbuf_top = *data;
        buf.inbuf_end = buf.inbuf_top + datalen;
+
+       if (datalen > (INT_MAX - 16) / 2) {
+               PyErr_NoMemory();
+               goto errorexit;
+       }
+
        buf.outobj = PyString_FromStringAndSize(NULL, datalen * 2 + 16);
        if (buf.outobj == NULL)
                goto errorexit;
@@ -725,6 +735,10 @@ mbstreamreader_iread(MultibyteStreamRead
                        PyObject *ctr;
                        char *ctrdata;
 
+                       if (PyString_GET_SIZE(cres) > INT_MAX - 
self->pendingsize) {
+                               PyErr_NoMemory();
+                               goto errorexit;
+            }
                        rsize = PyString_GET_SIZE(cres) + self->pendingsize;
                        ctr = PyString_FromStringAndSize(NULL, rsize);
                        if (ctr == NULL)
Index: Python-2.4.4/Modules/arraymodule.c
===================================================================
--- Python-2.4.4.orig/Modules/arraymodule.c
+++ Python-2.4.4/Modules/arraymodule.c
@@ -651,6 +651,9 @@ array_concat(arrayobject *a, PyObject *b
                PyErr_BadArgument();
                return NULL;
        }
+       if (a->ob_size > INT_MAX - b->ob_size) {
+               return PyErr_NoMemory();
+       }
        size = a->ob_size + b->ob_size;
        np = (arrayobject *) newarrayobject(&Arraytype, size, a->ob_descr);
        if (np == NULL) {
@@ -673,6 +676,9 @@ array_repeat(arrayobject *a, int n)
        int nbytes;
        if (n < 0)
                n = 0;
+       if ((a->ob_size != 0) && (n > INT_MAX / a->ob_size)) {
+               return PyErr_NoMemory();
+       }
        size = a->ob_size * n;
        np = (arrayobject *) newarrayobject(&Arraytype, size, a->ob_descr);
        if (np == NULL)
@@ -817,6 +823,11 @@ array_do_extend(arrayobject *self, PyObj
                             "can only extend with array of same kind");
                return -1;
        }
+       if ((self->ob_size > INT_MAX - b->ob_size) ||
+               ((self->ob_size + b->ob_size) > INT_MAX / 
self->ob_descr->itemsize)) {
+                       PyErr_NoMemory();
+                       return -1;
+       }
        size = self->ob_size + b->ob_size;
         PyMem_RESIZE(self->ob_item, char, size*self->ob_descr->itemsize);
         if (self->ob_item == NULL) {
@@ -858,6 +869,10 @@ array_inplace_repeat(arrayobject *self, 
                if (n < 0)
                        n = 0;
                items = self->ob_item;
+               if ((self->ob_descr->itemsize != 0) &&
+                       (self->ob_size > INT_MAX / self->ob_descr->itemsize)) {
+                       return PyErr_NoMemory();
+               }
                size = self->ob_size * self->ob_descr->itemsize;
                if (n == 0) {
                        PyMem_FREE(items);
@@ -866,6 +881,9 @@ array_inplace_repeat(arrayobject *self, 
                        self->allocated = 0;
                }
                else {
+                       if (size > INT_MAX / n) {
+                               return PyErr_NoMemory();
+                       }
                        PyMem_Resize(items, char, n * size);
                        if (items == NULL)
                                return PyErr_NoMemory();
@@ -1278,6 +1296,9 @@ array_fromlist(arrayobject *self, PyObje
                        if ((*self->ob_descr->setitem)(self,
                                        self->ob_size - n + i, v) != 0) {
                                self->ob_size -= n;
+                               if (itemsize && (self->ob_size > INT_MAX / 
itemsize)) {
+                                       return PyErr_NoMemory();
+                               }
                                PyMem_RESIZE(item, char,
                                                  self->ob_size * itemsize);
                                self->ob_item = item;
@@ -1337,6 +1358,10 @@ array_fromstring(arrayobject *self, PyOb
        n = n / itemsize;
        if (n > 0) {
                char *item = self->ob_item;
+               if ((n > INT_MAX - self->ob_size) ||
+                       ((self->ob_size + n) > INT_MAX / itemsize)) {
+                               return PyErr_NoMemory();
+               }
                PyMem_RESIZE(item, char, (self->ob_size + n) * itemsize);
                if (item == NULL) {
                        PyErr_NoMemory();
@@ -1362,8 +1387,12 @@ values,as if it had been read from a fil
 static PyObject *
 array_tostring(arrayobject *self, PyObject *unused)
 {
-       return PyString_FromStringAndSize(self->ob_item,
+       if (self->ob_size <= INT_MAX / self->ob_descr->itemsize) {
+               return PyString_FromStringAndSize(self->ob_item,
                                    self->ob_size * self->ob_descr->itemsize);
+       } else {
+               return PyErr_NoMemory();
+       }
 }
 
 PyDoc_STRVAR(tostring_doc,
@@ -1391,6 +1420,9 @@ array_fromunicode(arrayobject *self, PyO
        }
        if (n > 0) {
                Py_UNICODE *item = (Py_UNICODE *) self->ob_item;
+               if (self->ob_size > INT_MAX - n) {
+                       return PyErr_NoMemory();
+               }
                PyMem_RESIZE(item, Py_UNICODE, self->ob_size + n);
                if (item == NULL) {
                        PyErr_NoMemory();
Index: Python-2.4.4/Modules/cStringIO.c
===================================================================
--- Python-2.4.4.orig/Modules/cStringIO.c
+++ Python-2.4.4/Modules/cStringIO.c
@@ -121,6 +121,7 @@ PyDoc_STRVAR(IO_getval__doc__,
 static PyObject *
 IO_cgetval(PyObject *self) {
         UNLESS (IO__opencheck(IOOOBJECT(self))) return NULL;
+       assert(IOOOBJECT(self)->pos >= 0);
         return PyString_FromStringAndSize(((IOobject*)self)->buf,
                                           ((IOobject*)self)->pos);
 }
@@ -139,6 +140,7 @@ IO_getval(IOobject *self, PyObject *args
         }
         else
                   s=self->string_size;
+        assert(self->pos >= 0);
         return PyString_FromStringAndSize(self->buf, s);
 }
 
@@ -158,6 +160,8 @@ IO_cread(PyObject *self, char **output, 
         int l;
 
         UNLESS (IO__opencheck(IOOOBJECT(self))) return -1;
+        assert(IOOOBJECT(self)->pos >= 0);
+        assert(IOOOBJECT(self)->string_size >= 0);
         l = ((IOobject*)self)->string_size - ((IOobject*)self)->pos;  
         if (n < 0 || n > l) {
                 n = l;
@@ -197,6 +201,11 @@ IO_creadline(PyObject *self, char **outp
 
         *output=((IOobject*)self)->buf + ((IOobject*)self)->pos;
         l = n - ((IOobject*)self)->buf - ((IOobject*)self)->pos;
+
+        assert(IOOOBJECT(self)->pos <= INT_MAX - l);
+        assert(IOOOBJECT(self)->pos >= 0);
+        assert(IOOOBJECT(self)->string_size >= 0);
+
         ((IOobject*)self)->pos += l;
         return l;
 }
@@ -215,6 +224,7 @@ IO_readline(IOobject *self, PyObject *ar
                 n -= m;
                 self->pos -= m;
         }
+        assert(IOOOBJECT(self)->pos >= 0);
         return PyString_FromStringAndSize(output, n);
 }
 
@@ -277,6 +287,7 @@ IO_tell(IOobject *self, PyObject *unused
 
         UNLESS (IO__opencheck(self)) return NULL;
 
+        assert(self->pos >= 0);
         return PyInt_FromLong(self->pos);
 }
 
Index: Python-2.4.4/Modules/stropmodule.c
===================================================================
--- Python-2.4.4.orig/Modules/stropmodule.c
+++ Python-2.4.4/Modules/stropmodule.c
@@ -576,7 +576,7 @@ strop_expandtabs(PyObject *self, PyObjec
        char* e;
        char* p;
        char* q;
-       int i, j;
+       int i, j, old_j;
        PyObject* out;
        char* string;
        int stringlen;
@@ -593,12 +593,18 @@ strop_expandtabs(PyObject *self, PyObjec
        }
 
        /* First pass: determine size of output string */
-       i = j = 0; /* j: current column; i: total of previous lines */
+       i = j = old_j = 0; /* j: current column; i: total of previous lines */
        e = string + stringlen;
        for (p = string; p < e; p++) {
-               if (*p == '\t')
+               if (*p == '\t') {
                        j += tabsize - (j%tabsize);
-               else {
+                       if (old_j > j) {
+                               PyErr_SetString(PyExc_OverflowError,
+                                               "new string is too long");
+                               return NULL;
+                       }
+                       old_j = j;
+               } else {
                        j++;
                        if (*p == '\n') {
                                i += j;
@@ -607,6 +613,11 @@ strop_expandtabs(PyObject *self, PyObjec
                }
        }
 
+       if ((i + j) < 0) {
+               PyErr_SetString(PyExc_OverflowError, "new string is too long");
+               return NULL;
+       }
+
        /* Second pass: create output string and fill it */
        out = PyString_FromStringAndSize(NULL, i+j);
        if (out == NULL)
Index: Python-2.4.4/Modules/binascii.c
===================================================================
--- Python-2.4.4.orig/Modules/binascii.c
+++ Python-2.4.4/Modules/binascii.c
@@ -194,6 +194,8 @@ binascii_a2b_uu(PyObject *self, PyObject
        if ( !PyArg_ParseTuple(args, "t#:a2b_uu", &ascii_data, &ascii_len) )
                return NULL;
 
+       assert(ascii_len >= 0);
+
        /* First byte: binary data length (in bytes) */
        bin_len = (*ascii_data++ - ' ') & 077;
        ascii_len--;
@@ -347,6 +349,11 @@ binascii_a2b_base64(PyObject *self, PyOb
        if ( !PyArg_ParseTuple(args, "t#:a2b_base64", &ascii_data, &ascii_len) )
                return NULL;
 
+       assert(ascii_len >= 0);
+
+       if (ascii_len > INT_MAX - 3)
+               return PyErr_NoMemory();
+
        bin_len = ((ascii_len+3)/4)*3; /* Upper bound, corrected later */
 
        /* Allocate the buffer */
@@ -436,6 +443,9 @@ binascii_b2a_base64(PyObject *self, PyOb
 
        if ( !PyArg_ParseTuple(args, "s#:b2a_base64", &bin_data, &bin_len) )
                return NULL;
+
+       assert(bin_len >= 0);
+
        if ( bin_len > BASE64_MAXBIN ) {
                PyErr_SetString(Error, "Too much data for base64 line");
                return NULL;
@@ -491,6 +501,11 @@ binascii_a2b_hqx(PyObject *self, PyObjec
        if ( !PyArg_ParseTuple(args, "t#:a2b_hqx", &ascii_data, &len) )
                return NULL;
 
+       assert(len >= 0);
+
+       if (len > INT_MAX - 2)
+               return PyErr_NoMemory();
+
        /* Allocate a string that is too big (fixed later) 
           Add two to the initial length to prevent interning which
           would preclude subsequent resizing.  */
@@ -554,6 +569,11 @@ binascii_rlecode_hqx(PyObject *self, PyO
        if ( !PyArg_ParseTuple(args, "s#:rlecode_hqx", &in_data, &len) )
                return NULL;
 
+       assert(len >= 0);
+
+       if (len > INT_MAX / 2 - 2)
+               return PyErr_NoMemory();
+
        /* Worst case: output is twice as big as input (fixed later) */
        if ( (rv=PyString_FromStringAndSize(NULL, len*2+2)) == NULL )
                return NULL;
@@ -603,6 +623,11 @@ binascii_b2a_hqx(PyObject *self, PyObjec
        if ( !PyArg_ParseTuple(args, "s#:b2a_hqx", &bin_data, &len) )
                return NULL;
 
+       assert(len >= 0);
+
+       if (len > INT_MAX / 2 - 2)
+               return PyErr_NoMemory();
+
        /* Allocate a buffer that is at least large enough */
        if ( (rv=PyString_FromStringAndSize(NULL, len*2+2)) == NULL )
                return NULL;
@@ -641,9 +666,13 @@ binascii_rledecode_hqx(PyObject *self, P
        if ( !PyArg_ParseTuple(args, "s#:rledecode_hqx", &in_data, &in_len) )
                return NULL;
 
+       assert(in_len >= 0);
+
        /* Empty string is a special case */
        if ( in_len == 0 )
                return Py_BuildValue("s", "");
+       else if (in_len > INT_MAX / 2)
+               return PyErr_NoMemory();
 
        /* Allocate a buffer of reasonable size. Resized when needed */
        out_len = in_len*2;
@@ -669,6 +698,7 @@ binascii_rledecode_hqx(PyObject *self, P
 #define OUTBYTE(b) \
        do { \
                 if ( --out_len_left < 0 ) { \
+                         if ( out_len > INT_MAX / 2) return PyErr_NoMemory(); \
                          _PyString_Resize(&rv, 2*out_len); \
                          if ( rv == NULL ) return NULL; \
                          out_data = (unsigned char *)PyString_AsString(rv) \
@@ -737,7 +767,7 @@ binascii_crc_hqx(PyObject *self, PyObjec
        if ( !PyArg_ParseTuple(args, "s#i:crc_hqx", &bin_data, &len, &crc) )
                return NULL;
 
-       while(len--) {
+       while(len-- > 0) {
                crc=((crc<<8)&0xff00)^crctab_hqx[((crc>>8)&0xff)^*bin_data++];
        }
 
@@ -881,7 +911,7 @@ binascii_crc32(PyObject *self, PyObject 
        /* only want the trailing 32 bits */
        crc &= 0xFFFFFFFFUL;
 #endif
-       while (len--)
+       while (len-- > 0)
                crc = crc_32_tab[(crc ^ *bin_data++) & 0xffUL] ^ (crc >> 8);
                /* Note:  (crc >> 8) MUST zero fill on left */
 
@@ -911,6 +941,10 @@ binascii_hexlify(PyObject *self, PyObjec
        if (!PyArg_ParseTuple(args, "s#:b2a_hex", &argbuf, &arglen))
                return NULL;
 
+       assert(arglen >= 0);
+       if (arglen > INT_MAX / 2)
+               return PyErr_NoMemory();
+
        retval = PyString_FromStringAndSize(NULL, arglen*2);
        if (!retval)
                return NULL;
@@ -968,6 +1002,8 @@ binascii_unhexlify(PyObject *self, PyObj
        if (!PyArg_ParseTuple(args, "s#:a2b_hex", &argbuf, &arglen))
                return NULL;
 
+       assert(arglen >= 0);
+
        /* XXX What should we do about strings with an odd length?  Should
         * we add an implicit leading zero, or a trailing zero?  For now,
         * raise an exception.
Index: Python-2.4.4/Modules/audioop.c
===================================================================
--- Python-2.4.4.orig/Modules/audioop.c
+++ Python-2.4.4/Modules/audioop.c
@@ -674,7 +674,7 @@ static PyObject *
 audioop_tostereo(PyObject *self, PyObject *args)
 {
        signed char *cp, *ncp;
-       int len, size, val1, val2, val = 0;
+       int len, new_len, size, val1, val2, val = 0;
        double fac1, fac2, fval, maxval;
        PyObject *rv;
        int i;
@@ -690,7 +690,14 @@ audioop_tostereo(PyObject *self, PyObjec
                return 0;
        }
     
-       rv = PyString_FromStringAndSize(NULL, len*2);
+       new_len = len*2;
+       if (new_len < 0) {
+               PyErr_SetString(PyExc_MemoryError,
+                               "not enough memory for output buffer");
+               return 0;
+       }
+
+       rv = PyString_FromStringAndSize(NULL, new_len);
        if ( rv == 0 )
                return 0;
        ncp = (signed char *)PyString_AsString(rv);
@@ -853,7 +860,7 @@ audioop_lin2lin(PyObject *self, PyObject
 {
        signed char *cp;
        unsigned char *ncp;
-       int len, size, size2, val = 0;
+       int len, new_len, size, size2, val = 0;
        PyObject *rv;
        int i, j;
 
@@ -867,7 +874,13 @@ audioop_lin2lin(PyObject *self, PyObject
                return 0;
        }
     
-       rv = PyString_FromStringAndSize(NULL, (len/size)*size2);
+       new_len = (len/size)*size2;
+       if (new_len < 0) {
+               PyErr_SetString(PyExc_MemoryError,
+                               "not enough memory for output buffer");
+               return 0;
+       }
+       rv = PyString_FromStringAndSize(NULL, new_len);
        if ( rv == 0 )
                return 0;
        ncp = (unsigned char *)PyString_AsString(rv);
@@ -903,6 +916,7 @@ audioop_ratecv(PyObject *self, PyObject 
        int chan, d, *prev_i, *cur_i, cur_o;
        PyObject *state, *samps, *str, *rv = NULL;
        int bytes_per_frame;
+       size_t alloc_size;
 
        weightA = 1;
        weightB = 0;
@@ -944,8 +958,14 @@ audioop_ratecv(PyObject *self, PyObject 
        inrate /= d;
        outrate /= d;
 
-       prev_i = (int *) malloc(nchannels * sizeof(int));
-       cur_i = (int *) malloc(nchannels * sizeof(int));
+       alloc_size = sizeof(int) * (unsigned)nchannels;
+       if (alloc_size < nchannels) {
+               PyErr_SetString(PyExc_MemoryError,
+                               "not enough memory for output buffer");
+               return 0;
+       }
+       prev_i = (int *) malloc(alloc_size);
+       cur_i = (int *) malloc(alloc_size);
        if (prev_i == NULL || cur_i == NULL) {
                (void) PyErr_NoMemory();
                goto exit;
@@ -1116,7 +1136,7 @@ audioop_ulaw2lin(PyObject *self, PyObjec
        unsigned char *cp;
        unsigned char cval;
        signed char *ncp;
-       int len, size, val;
+       int len, new_len, size, val;
        PyObject *rv;
        int i;
 
@@ -1129,12 +1149,18 @@ audioop_ulaw2lin(PyObject *self, PyObjec
                return 0;
        }
     
-       rv = PyString_FromStringAndSize(NULL, len*size);
+       new_len = len*size;
+       if (new_len < 0) {
+               PyErr_SetString(PyExc_MemoryError,
+                       "not enough memory for output buffer");
+               return 0;
+       }
+       rv = PyString_FromStringAndSize(NULL, new_len);
        if ( rv == 0 )
                return 0;
        ncp = (signed char *)PyString_AsString(rv);
     
-       for ( i=0; i < len*size; i += size ) {
+       for ( i=0; i < new_len; i += size ) {
                cval = *cp++;
                val = st_ulaw_to_linear(cval);
        
@@ -1259,7 +1285,7 @@ audioop_adpcm2lin(PyObject *self, PyObje
 {
        signed char *cp;
        signed char *ncp;
-       int len, size, valpred, step, delta, index, sign, vpdiff;
+       int len, new_len, size, valpred, step, delta, index, sign, vpdiff;
        PyObject *rv, *str, *state;
        int i, inputbuffer = 0, bufferstep;
 
@@ -1281,7 +1307,13 @@ audioop_adpcm2lin(PyObject *self, PyObje
        } else if ( !PyArg_Parse(state, "(ii)", &valpred, &index) )
                return 0;
     
-       str = PyString_FromStringAndSize(NULL, len*size*2);
+       new_len = len*size*2;
+       if (new_len < 0) {
+               PyErr_SetString(PyExc_MemoryError,
+                               "not enough memory for output buffer");
+               return 0;
+       }
+       str = PyString_FromStringAndSize(NULL, new_len);
        if ( str == 0 )
                return 0;
        ncp = (signed char *)PyString_AsString(str);
@@ -1289,7 +1321,7 @@ audioop_adpcm2lin(PyObject *self, PyObje
        step = stepsizeTable[index];
        bufferstep = 0;
     
-       for ( i=0; i < len*size*2; i += size ) {
+       for ( i=0; i < new_len; i += size ) {
                /* Step 1 - get the delta value and compute next index */
                if ( bufferstep ) {
                        delta = inputbuffer & 0xf;
Index: Python-2.4.4/Modules/cPickle.c
===================================================================
--- Python-2.4.4.orig/Modules/cPickle.c
+++ Python-2.4.4/Modules/cPickle.c
@@ -3419,6 +3419,14 @@ load_binstring(Unpicklerobject *self)
        if (self->read_func(self, &s, 4) < 0) return -1;
 
        l = calc_binint(s, 4);
+       if (l < 0) {
+               /* Corrupt or hostile pickle -- we never write one like
+                * this.
+                */
+               PyErr_SetString(UnpicklingError,
+                               "BINSTRING pickle has negative byte count");
+               return -1;
+       }
 
        if (self->read_func(self, &s, l) < 0)
                return -1;
@@ -3486,6 +3494,14 @@ load_binunicode(Unpicklerobject *self)
        if (self->read_func(self, &s, 4) < 0) return -1;
 
        l = calc_binint(s, 4);
+       if (l < 0) {
+               /* Corrupt or hostile pickle -- we never write one like
+                * this.
+                */
+               PyErr_SetString(UnpicklingError,
+                               "BINUNICODE pickle has negative byte count");
+               return -1;
+       }
 
        if (self->read_func(self, &s, l) < 0)
                return -1;
Index: Python-2.4.4/Modules/_csv.c
===================================================================
--- Python-2.4.4.orig/Modules/_csv.c
+++ Python-2.4.4/Modules/_csv.c
@@ -470,6 +470,10 @@ parse_grow_buff(ReaderObj *self)
                self->field = PyMem_Malloc(self->field_size);
        }
        else {
+               if (self->field_size > INT_MAX / 2) {
+                       PyErr_NoMemory();
+                       return 0;
+               }
                self->field_size *= 2;
                self->field = PyMem_Realloc(self->field, self->field_size);
        }
@@ -1003,6 +1007,12 @@ join_append_data(WriterObj *self, char *
 static int
 join_check_rec_size(WriterObj *self, int rec_len)
 {
+
+       if (rec_len < 0 || rec_len > INT_MAX - MEM_INCR) {
+               PyErr_NoMemory();
+               return 0;
+       }
+
        if (rec_len > self->rec_size) {
                if (self->rec_size == 0) {
                        self->rec_size = (rec_len / MEM_INCR + 1) * MEM_INCR;
r63883 | gregory.p.smith | 2008-06-02 02:07:25 +0200 (Mon, 02 Jun 2008) | 5 
lines

- Issue #2588, #2589: Fix potential integer underflow and overflow
  conditions in the PyOS_vsnprintf C API function.

This is a backport of r63728 and r63734 from trunk.

Index: Python-2.4.4/Python/mysnprintf.c
===================================================================
--- Python-2.4.4.orig/Python/mysnprintf.c
+++ Python-2.4.4/Python/mysnprintf.c
@@ -54,18 +54,28 @@ int
 PyOS_vsnprintf(char *str, size_t size, const char  *format, va_list va)
 {
        int len;  /* # bytes written, excluding \0 */
-#ifndef HAVE_SNPRINTF
+#ifdef HAVE_SNPRINTF
+#define _PyOS_vsnprintf_EXTRA_SPACE 1
+#else
+#define _PyOS_vsnprintf_EXTRA_SPACE 512
        char *buffer;
 #endif
        assert(str != NULL);
        assert(size > 0);
        assert(format != NULL);
+       /* We take a size_t as input but return an int.  Sanity check
+        * our input so that it won't cause an overflow in the
+         * vsnprintf return value or the buffer malloc size.  */
+       if (size > INT_MAX - _PyOS_vsnprintf_EXTRA_SPACE) {
+               len = -666;
+               goto Done;
+       }
 
 #ifdef HAVE_SNPRINTF
        len = vsnprintf(str, size, format, va);
 #else
        /* Emulate it. */
-       buffer = PyMem_MALLOC(size + 512);
+       buffer = PyMem_MALLOC(size + _PyOS_vsnprintf_EXTRA_SPACE);
        if (buffer == NULL) {
                len = -666;
                goto Done;
@@ -75,7 +85,7 @@ PyOS_vsnprintf(char *str, size_t size, c
        if (len < 0)
                /* ignore the error */;
 
-       else if ((size_t)len >= size + 512)
+       else if ((size_t)len >= size + _PyOS_vsnprintf_EXTRA_SPACE)
                Py_FatalError("Buffer overflow in 
PyOS_snprintf/PyOS_vsnprintf");
 
        else {
@@ -86,8 +96,10 @@ PyOS_vsnprintf(char *str, size_t size, c
                str[to_copy] = '\0';
        }
        PyMem_FREE(buffer);
-Done:
 #endif
-       str[size-1] = '\0';
+Done:
+       if (size > 0)
+               str[size-1] = '\0';
        return len;
+#undef _PyOS_vsnprintf_EXTRA_SPACE
 }
Index: Python-2.5.2/Objects/unicodeobject.c
===================================================================
--- Python-2.5.2.orig/Objects/unicodeobject.c
+++ Python-2.5.2/Objects/unicodeobject.c
@@ -240,6 +240,11 @@ PyUnicodeObject *_PyUnicode_New(Py_ssize
         return unicode_empty;
     }
 
+    /* Ensure we won't overflow the size. */
+    if (length > ((PY_SSIZE_T_MAX / sizeof(Py_UNICODE)) - 1)) {
+        return (PyUnicodeObject *)PyErr_NoMemory();
+    }
+
     /* Unicode freelist & memory allocation */
     if (unicode_freelist) {
         unicode = unicode_freelist;
@@ -1102,6 +1107,9 @@ PyObject *PyUnicode_EncodeUTF7(const Py_
     char * out;
     char * start;
 
+    if (cbAllocated / 5 != size)
+        return PyErr_NoMemory();
+
     if (size == 0)
                return PyString_FromStringAndSize(NULL, 0);
 
@@ -1700,8 +1708,9 @@ PyUnicode_EncodeUTF16(const Py_UNICODE *
 {
     PyObject *v;
     unsigned char *p;
+    Py_ssize_t nsize, bytesize;
 #ifdef Py_UNICODE_WIDE
-    int i, pairs;
+    Py_ssize_t i, pairs;
 #else
     const int pairs = 0;
 #endif
@@ -1724,8 +1733,15 @@ PyUnicode_EncodeUTF16(const Py_UNICODE *
        if (s[i] >= 0x10000)
            pairs++;
 #endif
-    v = PyString_FromStringAndSize(NULL,
-                 2 * (size + pairs + (byteorder == 0)));
+    /* 2 * (size + pairs + (byteorder == 0)) */
+    if (size > PY_SSIZE_T_MAX ||
+       size > PY_SSIZE_T_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;
 
@@ -2053,6 +2069,11 @@ PyObject *unicodeescape_string(const Py_
     char *p;
 
     static const char *hexdigit = "0123456789abcdef";
+#ifdef Py_UNICODE_WIDE
+    const Py_ssize_t expandsize = 10;
+#else
+    const Py_ssize_t expandsize = 6;
+#endif
 
     /* Initial allocation is based on the longest-possible unichr
        escape.
@@ -2068,13 +2089,12 @@ PyObject *unicodeescape_string(const Py_
        escape.
     */
 
+    if (size > (PY_SSIZE_T_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;
@@ -2315,12 +2335,16 @@ PyObject *PyUnicode_EncodeRawUnicodeEsca
     char *q;
 
     static const char *hexdigit = "0123456789abcdef";
-
 #ifdef Py_UNICODE_WIDE
-    repr = PyString_FromStringAndSize(NULL, 10 * size);
+    const Py_ssize_t expandsize = 10;
 #else
-    repr = PyString_FromStringAndSize(NULL, 6 * size);
+    const Py_ssize_t expandsize = 6;
 #endif
+
+    if (size > PY_SSIZE_T_MAX / expandsize)
+       return PyErr_NoMemory();
+
+    repr = PyString_FromStringAndSize(NULL, expandsize * size);
     if (repr == NULL)
         return NULL;
     if (size == 0)
@@ -4730,6 +4754,11 @@ PyUnicodeObject *pad(PyUnicodeObject *se
         return self;
     }
 
+    if (left > PY_SSIZE_T_MAX - self->length ||
+       right > PY_SSIZE_T_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)
Index: Python-2.5.2/Objects/tupleobject.c
===================================================================
--- Python-2.5.2.orig/Objects/tupleobject.c
+++ Python-2.5.2/Objects/tupleobject.c
@@ -60,11 +60,12 @@ PyTuple_New(register Py_ssize_t size)
                Py_ssize_t nbytes = size * sizeof(PyObject *);
                /* Check for overflow */
                if (nbytes / sizeof(PyObject *) != (size_t)size ||
-                   (nbytes += sizeof(PyTupleObject) - sizeof(PyObject *))
-                   <= 0)
+                   (nbytes > PY_SSIZE_T_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;
Index: Python-2.5.2/Objects/bufferobject.c
===================================================================
--- Python-2.5.2.orig/Objects/bufferobject.c
+++ Python-2.5.2/Objects/bufferobject.c
@@ -427,6 +427,10 @@ buffer_repeat(PyBufferObject *self, Py_s
                count = 0;
        if (!get_buf(self, &ptr, &size, ANY_BUFFER))
                return NULL;
+       if (count > PY_SSIZE_T_MAX / size) {
+               PyErr_SetString(PyExc_MemoryError, "result too large");
+               return NULL;
+       }
        ob = PyString_FromStringAndSize(NULL, size * count);
        if ( ob == NULL )
                return NULL;
Index: Python-2.5.2/Objects/longobject.c
===================================================================
--- Python-2.5.2.orig/Objects/longobject.c
+++ Python-2.5.2/Objects/longobject.c
@@ -70,6 +70,8 @@ _PyLong_New(Py_ssize_t size)
                PyErr_NoMemory();
                return NULL;
        }
+       /* XXX(nnorwitz): This can overflow --
+          PyObject_NEW_VAR /  _PyObject_VAR_SIZE need to detect overflow */
        return PyObject_NEW_VAR(PyLongObject, &PyLong_Type, size);
 }
 
Index: Python-2.5.2/Objects/stringobject.c
===================================================================
--- Python-2.5.2.orig/Objects/stringobject.c
+++ Python-2.5.2/Objects/stringobject.c
@@ -76,6 +76,11 @@ PyString_FromStringAndSize(const char *s
                return (PyObject *)op;
        }
 
+       if (size > PY_SSIZE_T_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)
@@ -111,7 +116,7 @@ PyString_FromString(const char *str)
 
        assert(str != NULL);
        size = strlen(str);
-       if (size > PY_SSIZE_T_MAX) {
+       if (size > PY_SSIZE_T_MAX - sizeof(PyStringObject)) {
                PyErr_SetString(PyExc_OverflowError,
                        "string is too long for a Python string");
                return NULL;
@@ -972,14 +977,24 @@ string_concat(register PyStringObject *a
                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 (size < 0) {
+       if (a->ob_size < 0 || b->ob_size < 0 ||
+           a->ob_size > PY_SSIZE_T_MAX - b->ob_size) {
                PyErr_SetString(PyExc_OverflowError,
                                "strings are too large to concat");
                return NULL;
        }
          
        /* Inline PyObject_NewVar */
+       if (size > PY_SSIZE_T_MAX - sizeof(PyStringObject)) {
+               PyErr_SetString(PyExc_OverflowError,
+                               "strings are too large to concat");
+               return NULL;
+       }
        op = (PyStringObject *)PyObject_MALLOC(sizeof(PyStringObject) + size);
        if (op == NULL)
                return PyErr_NoMemory();
Index: Python-2.5.2/Misc/NEWS
===================================================================
--- Python-2.5.2.orig/Misc/NEWS
+++ Python-2.5.2/Misc/NEWS
@@ -32,6 +32,8 @@ What's New in Python 2.5.2c1?
 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
Index: Python-2.5.2/Lib/test/seq_tests.py
===================================================================
--- Python-2.5.2.orig/Lib/test/seq_tests.py
+++ Python-2.5.2/Lib/test/seq_tests.py
@@ -307,11 +307,13 @@ class CommonTest(unittest.TestCase):
             self.assertEqual(id(s), id(s*1))
 
     def test_bigrepeat(self):
-        x = self.type2test([0])
-        x *= 2**16
-        self.assertRaises(MemoryError, x.__mul__, 2**16)
-        if hasattr(x, '__imul__'):
-            self.assertRaises(MemoryError, x.__imul__, 2**16)
+        import sys
+        if sys.maxint <= 2147483647:
+            x = self.type2test([0])
+            x *= 2**16
+            self.assertRaises(MemoryError, x.__mul__, 2**16)
+            if hasattr(x, '__imul__'):
+                self.assertRaises(MemoryError, x.__imul__, 2**16)
 
     def test_subscript(self):
         a = self.type2test([10, 11])
Index: Python-2.5.2/Lib/test/test_strop.py
===================================================================
--- Python-2.5.2.orig/Lib/test/test_strop.py
+++ Python-2.5.2/Lib/test/test_strop.py
@@ -115,6 +115,25 @@ class StropFunctionTestCase(unittest.Tes
         strop.uppercase
         strop.whitespace
 
+    @test_support.precisionbigmemtest(size=test_support._2G - 1, memuse=5)
+    def test_stropjoin_huge_list(self, size):
+        a = "A" * size
+        try:
+            r = strop.join([a, a], a)
+        except OverflowError:
+            pass
+        else:
+            self.assertEquals(len(r), len(a) * 3)
+
+    @test_support.precisionbigmemtest(size=test_support._2G - 1, memuse=1)
+    def test_stropjoin_huge_tup(self, size):
+        a = "A" * size
+        try:
+            r = strop.join((a, a), a)
+        except OverflowError:
+            pass # acceptable on 32-bit
+        else:
+            self.assertEquals(len(r), len(a) * 3)
 
 transtable = 
'\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037
 
!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`xyzdefghijklmnopqrstuvwxyz{|}~\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377'
 
Index: Python-2.5.2/Lib/test/test_bigmem.py
===================================================================
--- Python-2.5.2.orig/Lib/test/test_bigmem.py
+++ Python-2.5.2/Lib/test/test_bigmem.py
@@ -1,5 +1,5 @@
 from test import test_support
-from test.test_support import bigmemtest, _1G, _2G
+from test.test_support import bigmemtest, _1G, _2G, _4G, precisionbigmemtest
 
 import unittest
 import operator
@@ -54,6 +54,22 @@ class StrTest(unittest.TestCase):
         self.assertEquals(s[lpadsize:-rpadsize], SUBSTR)
         self.assertEquals(s.strip(), SUBSTR.strip())
 
+    @precisionbigmemtest(size=_2G - 1, memuse=1)
+    def test_center_unicode(self, size):
+        SUBSTR = u' abc def ghi'
+        try:
+            s = SUBSTR.center(size)
+        except OverflowError:
+            pass # acceptable on 32-bit
+        else:
+            self.assertEquals(len(s), size)
+            lpadsize = rpadsize = (len(s) - len(SUBSTR)) // 2
+            if len(s) % 2:
+                lpadsize += 1
+            self.assertEquals(s[lpadsize:-rpadsize], SUBSTR)
+            self.assertEquals(s.strip(), SUBSTR.strip())
+            del s
+
     @bigmemtest(minsize=_2G, memuse=2)
     def test_count(self, size):
         SUBSTR = ' abc def ghi'
@@ -70,10 +86,44 @@ class StrTest(unittest.TestCase):
         s = '.' * size
         self.assertEquals(len(s.decode('utf-8')), size)
 
+    def basic_encode_test(self, size, enc, c=u'.', expectedsize=None):
+        if expectedsize is None:
+            expectedsize = size
+
+        s = c * size
+        self.assertEquals(len(s.encode(enc)), expectedsize)
+
     @bigmemtest(minsize=_2G + 2, memuse=3)
     def test_encode(self, size):
-        s = u'.' * size
-        self.assertEquals(len(s.encode('utf-8')), size)
+        return self.basic_encode_test(size, 'utf-8')
+
+    @precisionbigmemtest(size=_4G / 6 + 2, memuse=2)
+    def test_encode_raw_unicode_escape(self, size):
+        try:
+            return self.basic_encode_test(size, 'raw_unicode_escape')
+        except MemoryError:
+            pass # acceptable on 32-bit
+
+    @precisionbigmemtest(size=_4G / 5 + 70, memuse=3)
+    def test_encode_utf7(self, size):
+        try:
+            return self.basic_encode_test(size, 'utf7')
+        except MemoryError:
+            pass # acceptable on 32-bit
+
+    @precisionbigmemtest(size=_2G-1, memuse=2)
+    def test_decodeascii(self, size):
+        return self.basic_encode_test(size, 'ascii', c='A')
+
+    @precisionbigmemtest(size=_4G / 5, memuse=6+2)
+    def test_unicode_repr_oflw(self, size):
+        try:
+            s = u"\uAAAA"*size
+            r = repr(s)
+        except MemoryError:
+            pass # acceptable on 32-bit
+        else:
+            self.failUnless(s == eval(r))
 
     @bigmemtest(minsize=_2G, memuse=2)
     def test_endswith(self, size):
@@ -459,6 +509,11 @@ class StrTest(unittest.TestCase):
         self.assertEquals(s.count('\\'), size)
         self.assertEquals(s.count('0'), size * 2)
 
+    @bigmemtest(minsize=2**32 / 5, memuse=6+2)
+    def test_unicode_repr(self, size):
+        s = u"\uAAAA" * size
+        self.failUnless(len(repr(s)) > size)
+
     # This test is meaningful even with size < 2G, as long as the
     # doubled string is > 2G (but it tests more if both are > 2G :)
     @bigmemtest(minsize=_1G + 2, memuse=3)
@@ -642,6 +697,35 @@ class TupleTest(unittest.TestCase):
     def test_repeat_large(self, size):
         return self.basic_test_repeat(size)
 
+    @bigmemtest(minsize=_1G - 1, memuse=12)
+    def test_repeat_large_2(self, size):
+        return self.basic_test_repeat(size)
+
+    @precisionbigmemtest(size=_1G - 1, memuse=9)
+    def test_from_2G_generator(self, size):
+        try:
+            t = tuple(xrange(size))
+        except MemoryError:
+            pass # acceptable on 32-bit
+        else:
+            count = 0
+            for item in t:
+                self.assertEquals(item, count)
+                count += 1
+            self.assertEquals(count, size)
+
+    @precisionbigmemtest(size=_1G - 25, memuse=9)
+    def test_from_almost_2G_generator(self, size):
+        try:
+            t = tuple(xrange(size))
+            count = 0
+            for item in t:
+                self.assertEquals(item, count)
+                count += 1
+            self.assertEquals(count, size)
+        except MemoryError:
+            pass # acceptable, expected on 32-bit
+
     # Like test_concat, split in two.
     def basic_test_repr(self, size):
         t = (0,) * size
@@ -957,8 +1041,34 @@ class ListTest(unittest.TestCase):
         self.assertEquals(l[:10], [1] * 10)
         self.assertEquals(l[-10:], [5] * 10)
 
+class BufferTest(unittest.TestCase):
+
+    @precisionbigmemtest(size=_1G, memuse=4)
+    def test_repeat(self, size):
+        try:
+            b = buffer("AAAA")*size
+        except MemoryError:
+            pass # acceptable on 32-bit
+        else:
+            count = 0
+            for c in b:
+                self.assertEquals(c, 'A')
+                count += 1
+            self.assertEquals(count, size*4)
+
 def test_main():
-    test_support.run_unittest(StrTest, TupleTest, ListTest)
+    test_support.run_unittest(StrTest, TupleTest, ListTest, BufferTest)
+
+# Expected failures (crashers)
+# del StrTest.test_center_unicode
+del StrTest.test_decodeascii
+# del StrTest.test_encode_utf32
+# del StrTest.test_encode_utf7
+# del StrTest.test_encode_raw_unicode_escape
+#
+# del TupleTest.test_from_2G_generator
+#
+# del BufferTest.test_repeat
 
 if __name__ == '__main__':
     if len(sys.argv) > 1:
Index: Python-2.5.2/Lib/test/test_support.py
===================================================================
--- Python-2.5.2.orig/Lib/test/test_support.py
+++ Python-2.5.2/Lib/test/test_support.py
@@ -33,6 +33,7 @@ verbose = 1              # Flag set to 0
 use_resources = None     # Flag set to [] by regrtest.py
 max_memuse = 0           # Disable bigmem tests (they will still be run with
                          # small sizes, to make sure they work.)
+real_max_memuse = 0
 
 # _original_stdout is meant to hold stdout at the time regrtest began.
 # This may be "the real" stdout, or IDLE's emulation of stdout, or whatever.
@@ -323,6 +324,7 @@ def run_with_locale(catstr, *locales):
 _1M = 1024*1024
 _1G = 1024 * _1M
 _2G = 2 * _1G
+_4G = 4 * _1G
 
 # Hack to get at the maximum value an internal index can take.
 class _Dummy:
@@ -333,6 +335,7 @@ MAX_Py_ssize_t = _Dummy()[:]
 def set_memlimit(limit):
     import re
     global max_memuse
+    global real_max_memuse
     sizes = {
         'k': 1024,
         'm': _1M,
@@ -344,6 +347,7 @@ def set_memlimit(limit):
     if m is None:
         raise ValueError('Invalid memory limit %r' % (limit,))
     memlimit = int(float(m.group(1)) * sizes[m.group(3).lower()])
+    real_max_memuse = memlimit
     if memlimit > MAX_Py_ssize_t:
         memlimit = MAX_Py_ssize_t
     if memlimit < _2G - 1:
@@ -389,6 +393,27 @@ def bigmemtest(minsize, memuse, overhead
         return wrapper
     return decorator
 
+def precisionbigmemtest(size, memuse, overhead=5*_1M):
+    def decorator(f):
+        def wrapper(self):
+            if not real_max_memuse:
+                maxsize = 5147
+            else:
+                maxsize = size
+
+                if real_max_memuse and real_max_memuse < maxsize * memuse:
+                    if verbose:
+                        sys.stderr.write("Skipping %s because of memory "
+                                         "constraint\n" % (f.__name__,))
+                    return
+
+            return f(self, maxsize)
+        wrapper.size = size
+        wrapper.memuse = memuse
+        wrapper.overhead = overhead
+        return wrapper
+    return decorator
+
 def bigaddrspacetest(f):
     """Decorator for tests that fill the address space."""
     def wrapper(self):
Index: Python-2.5.2/Modules/mmapmodule.c
===================================================================
--- Python-2.5.2.orig/Modules/mmapmodule.c
+++ Python-2.5.2/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);
Index: Python-2.5.2/Modules/stropmodule.c
===================================================================
--- Python-2.5.2.orig/Modules/stropmodule.c
+++ Python-2.5.2/Modules/stropmodule.c
@@ -216,6 +216,13 @@ strop_joinfields(PyObject *self, PyObjec
                                return NULL;
                        }
                        slen = PyString_GET_SIZE(item);
+                       if (slen > PY_SSIZE_T_MAX - reslen ||
+                           seplen > PY_SSIZE_T_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;
@@ -253,6 +260,14 @@ strop_joinfields(PyObject *self, PyObjec
                        return NULL;
                }
                slen = PyString_GET_SIZE(item);
+               if (slen > PY_SSIZE_T_MAX - reslen ||
+                   seplen > PY_SSIZE_T_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);
Index: Python-2.5.2/Modules/gcmodule.c
===================================================================
--- Python-2.5.2.orig/Modules/gcmodule.c
+++ Python-2.5.2/Modules/gcmodule.c
@@ -1318,7 +1318,10 @@ PyObject *
 _PyObject_GC_Malloc(size_t basicsize)
 {
        PyObject *op;
-       PyGC_Head *g = (PyGC_Head *)PyObject_MALLOC(
+       PyGC_Head *g;
+       if (basicsize > PY_SSIZE_T_MAX - sizeof(PyGC_Head))
+               return PyErr_NoMemory();
+       g = (PyGC_Head *)PyObject_MALLOC(
                 sizeof(PyGC_Head) + basicsize);
        if (g == NULL)
                return PyErr_NoMemory();
@@ -1361,6 +1364,8 @@ _PyObject_GC_Resize(PyVarObject *op, Py_
 {
        const size_t basicsize = _PyObject_VAR_SIZE(op->ob_type, nitems);
        PyGC_Head *g = AS_GC(op);
+       if (basicsize > PY_SSIZE_T_MAX - sizeof(PyGC_Head))
+               return (PyVarObject *)PyErr_NoMemory();
        g = (PyGC_Head *)PyObject_REALLOC(g,  sizeof(PyGC_Head) + basicsize);
        if (g == NULL)
                return (PyVarObject *)PyErr_NoMemory();
Index: Python-2.5.2/Lib/test/test_hashlib.py
===================================================================
--- Python-2.5.2.orig/Lib/test/test_hashlib.py
+++ Python-2.5.2/Lib/test/test_hashlib.py
@@ -9,7 +9,7 @@
 import hashlib
 import unittest
 from test import test_support
-
+from test.test_support import _4G, precisionbigmemtest
 
 def hexstr(s):
     import string
@@ -55,7 +55,6 @@ class HashLibTestCase(unittest.TestCase)
             m2.update(aas + bees + cees)
             self.assertEqual(m1.digest(), m2.digest())
 
-
     def check(self, name, data, digest):
         # test the direct constructors
         computed = getattr(hashlib, name)(data).hexdigest()
@@ -74,7 +73,22 @@ class HashLibTestCase(unittest.TestCase)
     def test_case_md5_2(self):
         self.check('md5', 
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
                    'd174ab98d277d9f5a5611c2c9f419d9f')
-
+
+    @precisionbigmemtest(size=_4G + 5, memuse=1)
+    def test_case_md5_huge(self, size):
+        if size == _4G + 5:
+            try:
+                self.check('md5', 'A'*size, 'c9af2dff37468ce5dfee8f2cfc0a9c6d')
+            except OverflowError:
+                pass # 32-bit arch
+
+    @precisionbigmemtest(size=_4G - 1, memuse=1)
+    def test_case_md5_uintmax(self, size):
+        if size == _4G - 1:
+            try:
+                self.check('md5', 'A'*size, '28138d306ff1b8281f1a9067e1a1a2b3')
+            except OverflowError:
+                pass # 32-bit arch
 
     # use the three examples from Federal Information Processing Standards
     # Publication 180-1, Secure Hash Standard,  1995 April 17
Index: Python-2.5.2/Modules/_hashopenssl.c
===================================================================
--- Python-2.5.2.orig/Modules/_hashopenssl.c
+++ Python-2.5.2/Modules/_hashopenssl.c
@@ -19,6 +19,8 @@
 /* EVP is the preferred interface to hashing in OpenSSL */
 #include <openssl/evp.h>
 
+#define MUNCH_SIZE INT_MAX
+
 
 #ifndef HASH_OBJ_CONSTRUCTOR
 #define HASH_OBJ_CONSTRUCTOR 0
@@ -164,9 +166,18 @@ EVP_update(EVPobject *self, PyObject *ar
     if (!PyArg_ParseTuple(args, "s#:update", &cp, &len))
         return NULL;
 
+    if (len > 0 && len <= MUNCH_SIZE) {
     EVP_DigestUpdate(&self->ctx, cp, Py_SAFE_DOWNCAST(len, Py_ssize_t,
                                                       unsigned int));
-
+    } else {
+        Py_ssize_t offset = 0;
+        while (len) {
+            unsigned int process = len > MUNCH_SIZE ? MUNCH_SIZE : len;
+            EVP_DigestUpdate(&self->ctx, cp + offset, process);
+            len -= process;
+            offset += process;
+        }
+    }
     Py_INCREF(Py_None);
     return Py_None;
 }
@@ -255,10 +266,21 @@ EVP_tp_init(EVPobject *self, PyObject *a
     self->name = name_obj;
     Py_INCREF(self->name);
 
-    if (cp && len)
+    if (cp && len) {
+        if (len > 0 && len <= MUNCH_SIZE) {
         EVP_DigestUpdate(&self->ctx, cp, Py_SAFE_DOWNCAST(len, Py_ssize_t,
                                                           unsigned int));
-
+        } else {
+            Py_ssize_t offset = 0;
+            while (len) {
+                unsigned int process = len > MUNCH_SIZE ? MUNCH_SIZE : len;
+                EVP_DigestUpdate(&self->ctx, cp + offset, process);
+                len -= process;
+                offset += process;
+            }
+        }
+    }
+
     return 0;
 }
 #endif
@@ -328,7 +350,7 @@ static PyTypeObject EVPtype = {
 static PyObject *
 EVPnew(PyObject *name_obj,
        const EVP_MD *digest, const EVP_MD_CTX *initial_ctx,
-       const unsigned char *cp, unsigned int len)
+       const unsigned char *cp, Py_ssize_t len)
 {
     EVPobject *self;
 
@@ -346,8 +368,20 @@ EVPnew(PyObject *name_obj,
         EVP_DigestInit(&self->ctx, digest);
     }
 
-    if (cp && len)
-        EVP_DigestUpdate(&self->ctx, cp, len);
+    if (cp && len) {
+        if (len > 0 && len <= MUNCH_SIZE) {
+            EVP_DigestUpdate(&self->ctx, cp, Py_SAFE_DOWNCAST(len, Py_ssize_t,
+                                                              unsigned int));
+        } else {
+            Py_ssize_t offset = 0;
+            while (len) {
+                unsigned int process = len > MUNCH_SIZE ? MUNCH_SIZE : len;
+                EVP_DigestUpdate(&self->ctx, cp + offset, process);
+                len -= process;
+                offset += process;
+            }
+        }
+    }
 
     return (PyObject *)self;
 }
@@ -384,8 +418,7 @@ EVP_new(PyObject *self, PyObject *args, 
 
     digest = EVP_get_digestbyname(name);
 
-    return EVPnew(name_obj, digest, NULL, cp, Py_SAFE_DOWNCAST(len, Py_ssize_t,
-                                                               unsigned int));
+    return EVPnew(name_obj, digest, NULL, cp, len);
 }
 
 /*
@@ -410,7 +443,7 @@ EVP_new(PyObject *self, PyObject *args, 
                 CONST_ ## NAME ## _name_obj, \
                 NULL, \
                 CONST_new_ ## NAME ## _ctx_p, \
-                cp, Py_SAFE_DOWNCAST(len, Py_ssize_t, unsigned int)); \
+                cp, len); \
     }
 
 /* a PyMethodDef structure for the constructor */
r65261 | neal.norwitz | 2008-07-28 07:06:20 +0200 (Mon, 28 Jul 2008) | 10 lines

Backport code from r65182:

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
all been updated to perform better checks and places in the code that
would previously leak memory on the error path when such an allocation
failed have been fixed.

Index: Python-2.5.2/Include/pymem.h
===================================================================
--- Python-2.5.2.orig/Include/pymem.h
+++ Python-2.5.2/Include/pymem.h
@@ -67,8 +67,12 @@ PyAPI_FUNC(void) PyMem_Free(void *);
    for malloc(0), which would be treated as an error. Some platforms
    would return a pointer with no memory behind it, which would break
    pymalloc. To solve these problems, allocate an extra byte. */
-#define PyMem_MALLOC(n)         malloc((n) ? (n) : 1)
-#define PyMem_REALLOC(p, n)     realloc((p), (n) ? (n) : 1)
+/* Returns NULL to indicate error if a negative size or size larger than
+   Py_ssize_t can represent is supplied.  Helps prevents security holes. */
+#define PyMem_MALLOC(n)                (((n) < 0 || (n) > PY_SSIZE_T_MAX) ? 
NULL \
+                               : malloc((n) ? (n) : 1))
+#define PyMem_REALLOC(p, n)    (((n) < 0 || (n) > PY_SSIZE_T_MAX) ? NULL \
+                               : realloc((p), (n) ? (n) : 1))
 #define PyMem_FREE             free
 
 #endif /* PYMALLOC_DEBUG */
@@ -77,24 +81,31 @@ PyAPI_FUNC(void) PyMem_Free(void *);
  * Type-oriented memory interface
  * ==============================
  *
- * These are carried along for historical reasons.  There's rarely a good
- * reason to use them anymore (you can just as easily do the multiply and
- * cast yourself).
+ * Allocate memory for n objects of the given type.  Returns a new pointer
+ * or NULL if the request was too large or memory allocation failed.  Use
+ * these macros rather than doing the multiplication yourself so that proper
+ * overflow checking is always done.
  */
 
 #define PyMem_New(type, n) \
-  ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
+  ( ((n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \
        ( (type *) PyMem_Malloc((n) * sizeof(type)) ) )
 #define PyMem_NEW(type, n) \
-  ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
+  ( ((n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \
        ( (type *) PyMem_MALLOC((n) * sizeof(type)) ) )
 
+/*
+ * The value of (p) is always clobbered by this macro regardless of success.
+ * The caller MUST check if (p) is NULL afterwards and deal with the memory
+ * error if so.  This means the original value of (p) MUST be saved for the
+ * caller's memory error handler to not lose track of it.
+ */
 #define PyMem_Resize(p, type, n) \
-  ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
-       ( (p) = (type *) PyMem_Realloc((p), (n) * sizeof(type)) ) )
+  ( (p) = ((n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \
+       (type *) PyMem_Realloc((p), (n) * sizeof(type)) )
 #define PyMem_RESIZE(p, type, n) \
-  ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
-       ( (p) = (type *) PyMem_REALLOC((p), (n) * sizeof(type)) ) )
+  ( (p) = ((n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \
+       (type *) PyMem_REALLOC((p), (n) * sizeof(type)) )
 
 /* PyMem{Del,DEL} are left over from ancient days, and shouldn't be used
  * anymore.  They're just confusing aliases for PyMem_{Free,FREE} now.
Index: Python-2.5.2/Objects/obmalloc.c
===================================================================
--- Python-2.5.2.orig/Objects/obmalloc.c
+++ Python-2.5.2/Objects/obmalloc.c
@@ -727,6 +727,15 @@ PyObject_Malloc(size_t nbytes)
        uint size;
 
        /*
+        * Limit ourselves to PY_SSIZE_T_MAX bytes to prevent security holes.
+        * Most python internals blindly use a signed Py_ssize_t to track
+        * things without checking for overflows or negatives.
+        * As size_t is unsigned, checking for nbytes < 0 is not required.
+        */
+       if (nbytes > PY_SSIZE_T_MAX)
+               return NULL;
+
+       /*
         * This implicitly redirects malloc(0).
         */
        if ((nbytes - 1) < SMALL_REQUEST_THRESHOLD) {
@@ -1130,6 +1139,15 @@ PyObject_Realloc(void *p, size_t nbytes)
        if (p == NULL)
                return PyObject_Malloc(nbytes);
 
+       /*
+        * Limit ourselves to PY_SSIZE_T_MAX bytes to prevent security holes.
+        * Most python internals blindly use a signed Py_ssize_t to track
+        * things without checking for overflows or negatives.
+        * As size_t is unsigned, checking for nbytes < 0 is not required.
+        */
+       if (nbytes > PY_SSIZE_T_MAX)
+               return NULL;
+
        pool = POOL_ADDR(p);
        if (Py_ADDRESS_IN_RANGE(p, pool)) {
                /* We're in charge of this block */
Index: Python-2.5.2/Misc/NEWS
===================================================================
--- Python-2.5.2.orig/Misc/NEWS
+++ Python-2.5.2/Misc/NEWS
@@ -32,6 +32,13 @@ What's New in Python 2.5.2c1?
 Core and builtins
 -----------------
 
+- 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
+  all been updated to perform better checks and places in the code that
+  would previously leak memory on the error path when such an allocation
+  failed have been fixed.
+
 - Added checks for integer overflows, contributed by Google. Some are
   only available if asserts are left in the code, in cases where they
   can't be triggered from Python code.
Index: Python-2.5.2/Modules/almodule.c
===================================================================
--- Python-2.5.2.orig/Modules/almodule.c
+++ Python-2.5.2/Modules/almodule.c
@@ -1633,9 +1633,11 @@ al_QueryValues(PyObject *self, PyObject 
        if (nvals < 0)
                goto cleanup;
        if (nvals > setsize) {
+               ALvalue *old_return_set = return_set;
                setsize = nvals;
                PyMem_RESIZE(return_set, ALvalue, setsize);
                if (return_set == NULL) {
+                       return_set = old_return_set;
                        PyErr_NoMemory();
                        goto cleanup;
                }
Index: Python-2.5.2/Modules/arraymodule.c
===================================================================
--- Python-2.5.2.orig/Modules/arraymodule.c
+++ Python-2.5.2/Modules/arraymodule.c
@@ -816,6 +816,7 @@ static int
 array_do_extend(arrayobject *self, PyObject *bb)
 {
        Py_ssize_t size;
+       char *old_item;
 
        if (!array_Check(bb))
                return array_iter_extend(self, bb);
@@ -831,10 +832,11 @@ array_do_extend(arrayobject *self, PyObj
                        return -1;
        }
        size = self->ob_size + b->ob_size;
+       old_item = self->ob_item;
         PyMem_RESIZE(self->ob_item, char, size*self->ob_descr->itemsize);
         if (self->ob_item == NULL) {
-                PyObject_Del(self);
-                PyErr_NoMemory();
+               self->ob_item = old_item;
+               PyErr_NoMemory();
                return -1;
         }
        memcpy(self->ob_item + self->ob_size*self->ob_descr->itemsize,
@@ -886,7 +888,7 @@ array_inplace_repeat(arrayobject *self, 
                        if (size > PY_SSIZE_T_MAX / n) {
                                return PyErr_NoMemory();
                        }
-                       PyMem_Resize(items, char, n * size);
+                       PyMem_RESIZE(items, char, n * size);
                        if (items == NULL)
                                return PyErr_NoMemory();
                        p = items;
Index: Python-2.5.2/Modules/selectmodule.c
===================================================================
--- Python-2.5.2.orig/Modules/selectmodule.c
+++ Python-2.5.2/Modules/selectmodule.c
@@ -349,10 +349,12 @@ update_ufd_array(pollObject *self)
 {
        Py_ssize_t i, pos;
        PyObject *key, *value;
+        struct pollfd *old_ufds = self->ufds;
 
        self->ufd_len = PyDict_Size(self->dict);
-       PyMem_Resize(self->ufds, struct pollfd, self->ufd_len);
+       PyMem_RESIZE(self->ufds, struct pollfd, self->ufd_len);
        if (self->ufds == NULL) {
+                self->ufds = old_ufds;
                PyErr_NoMemory();
                return 0;
        }
r63883 | gregory.p.smith | 2008-06-02 02:07:25 +0200 (Mon, 02 Jun 2008) | 5 
lines

- Issue #2588, #2589: Fix potential integer underflow and overflow
  conditions in the PyOS_vsnprintf C API function.

This is a backport of r63728 and r63734 from trunk.

Index: Python-2.5.2/Python/mysnprintf.c
===================================================================
--- Python-2.5.2.orig/Python/mysnprintf.c
+++ Python-2.5.2/Python/mysnprintf.c
@@ -54,18 +54,28 @@ int
 PyOS_vsnprintf(char *str, size_t size, const char  *format, va_list va)
 {
        int len;  /* # bytes written, excluding \0 */
-#ifndef HAVE_SNPRINTF
+#ifdef HAVE_SNPRINTF
+#define _PyOS_vsnprintf_EXTRA_SPACE 1
+#else
+#define _PyOS_vsnprintf_EXTRA_SPACE 512
        char *buffer;
 #endif
        assert(str != NULL);
        assert(size > 0);
        assert(format != NULL);
+       /* We take a size_t as input but return an int.  Sanity check
+        * our input so that it won't cause an overflow in the
+         * vsnprintf return value or the buffer malloc size.  */
+       if (size > INT_MAX - _PyOS_vsnprintf_EXTRA_SPACE) {
+               len = -666;
+               goto Done;
+       }
 
 #ifdef HAVE_SNPRINTF
        len = vsnprintf(str, size, format, va);
 #else
        /* Emulate it. */
-       buffer = PyMem_MALLOC(size + 512);
+       buffer = PyMem_MALLOC(size + _PyOS_vsnprintf_EXTRA_SPACE);
        if (buffer == NULL) {
                len = -666;
                goto Done;
@@ -75,7 +85,7 @@ PyOS_vsnprintf(char *str, size_t size, c
        if (len < 0)
                /* ignore the error */;
 
-       else if ((size_t)len >= size + 512)
+       else if ((size_t)len >= size + _PyOS_vsnprintf_EXTRA_SPACE)
                Py_FatalError("Buffer overflow in 
PyOS_snprintf/PyOS_vsnprintf");
 
        else {
@@ -86,8 +96,10 @@ PyOS_vsnprintf(char *str, size_t size, c
                str[to_copy] = '\0';
        }
        PyMem_FREE(buffer);
-Done:
 #endif
-       str[size-1] = '\0';
+Done:
+       if (size > 0)
+               str[size-1] = '\0';
        return len;
+#undef _PyOS_vsnprintf_EXTRA_SPACE
 }
Index: Python-2.5.2/Misc/NEWS
===================================================================
--- Python-2.5.2.orig/Misc/NEWS
+++ Python-2.5.2/Misc/NEWS
@@ -109,6 +109,9 @@ Core and builtins
   threading.enumerate() list after the join() for a brief period until
   it actually exited.
 
+- Issue #2588, #2589: Fix potential integer underflow and overflow
+  conditions in the PyOS_vsnprintf C API function.
+
 
 Library
 -------

Attachment: signature.asc
Description: PGP signature



Home | Main Index | Thread Index | Old Index