155 lines
5.3 KiB
Diff
155 lines
5.3 KiB
Diff
Index: Include/pymem.h
|
|
================================================================================
|
|
--- Include/pymem.h
|
|
+++ Include/pymem.h
|
|
@@ -67,8 +67,12 @@
|
|
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 @@
|
|
* 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.
|
|
--- Modules/almodule.c
|
|
+++ Modules/almodule.c
|
|
@@ -1633,9 +1633,11 @@
|
|
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;
|
|
}
|
|
--- Modules/arraymodule.c
|
|
+++ Modules/arraymodule.c
|
|
@@ -816,6 +816,7 @@
|
|
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,8 +832,10 @@
|
|
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) {
|
|
+ self->ob_item = old_item;
|
|
PyObject_Del(self);
|
|
PyErr_NoMemory();
|
|
return -1;
|
|
@@ -886,7 +889,7 @@
|
|
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;
|
|
--- Modules/selectmodule.c
|
|
+++ Modules/selectmodule.c
|
|
@@ -349,10 +349,12 @@
|
|
{
|
|
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;
|
|
}
|
|
--- Objects/obmalloc.c
|
|
+++ Objects/obmalloc.c
|
|
@@ -727,6 +727,15 @@
|
|
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 @@
|
|
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 */
|