Skip to content

Commit eb0c778

Browse files
author
gregory.p.smith
committed
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. git-svn-id: http://svn.python.org/projects/python/trunk@65182 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent c3a5892 commit eb0c778

File tree

7 files changed

+59
-14
lines changed

7 files changed

+59
-14
lines changed

Doc/c-api/memory.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,9 @@ The following type-oriented macros are provided for convenience. Note that
136136

137137
Same as :cfunc:`PyMem_Realloc`, but the memory block is resized to ``(n *
138138
sizeof(TYPE))`` bytes. Returns a pointer cast to :ctype:`TYPE\*`. On return,
139-
*p* will be a pointer to the new memory area, or *NULL* in the event of failure.
139+
*p* will be a pointer to the new memory area, or *NULL* in the event of
140+
failure. This is a C preprocessor macro; p is always reassigned. Save
141+
the original value of p to avoid losing memory when handling errors.
140142

141143

142144
.. cfunction:: void PyMem_Del(void *p)

Include/pymem.h

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,12 @@ PyAPI_FUNC(void) PyMem_Free(void *);
6969
for malloc(0), which would be treated as an error. Some platforms
7070
would return a pointer with no memory behind it, which would break
7171
pymalloc. To solve these problems, allocate an extra byte. */
72-
#define PyMem_MALLOC(n) malloc((n) ? (n) : 1)
73-
#define PyMem_REALLOC(p, n) realloc((p), (n) ? (n) : 1)
72+
/* Returns NULL to indicate error if a negative size or size larger than
73+
Py_ssize_t can represent is supplied. Helps prevents security holes. */
74+
#define PyMem_MALLOC(n) (((n) < 0 || (n) > PY_SSIZE_T_MAX) ? NULL \
75+
: malloc((n) ? (n) : 1))
76+
#define PyMem_REALLOC(p, n) (((n) < 0 || (n) > PY_SSIZE_T_MAX) ? NULL \
77+
: realloc((p), (n) ? (n) : 1))
7478
#define PyMem_FREE free
7579

7680
#endif /* PYMALLOC_DEBUG */
@@ -79,24 +83,31 @@ PyAPI_FUNC(void) PyMem_Free(void *);
7983
* Type-oriented memory interface
8084
* ==============================
8185
*
82-
* These are carried along for historical reasons. There's rarely a good
83-
* reason to use them anymore (you can just as easily do the multiply and
84-
* cast yourself).
86+
* Allocate memory for n objects of the given type. Returns a new pointer
87+
* or NULL if the request was too large or memory allocation failed. Use
88+
* these macros rather than doing the multiplication yourself so that proper
89+
* overflow checking is always done.
8590
*/
8691

8792
#define PyMem_New(type, n) \
88-
( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
93+
( ((n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \
8994
( (type *) PyMem_Malloc((n) * sizeof(type)) ) )
9095
#define PyMem_NEW(type, n) \
91-
( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
96+
( ((n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \
9297
( (type *) PyMem_MALLOC((n) * sizeof(type)) ) )
9398

99+
/*
100+
* The value of (p) is always clobbered by this macro regardless of success.
101+
* The caller MUST check if (p) is NULL afterwards and deal with the memory
102+
* error if so. This means the original value of (p) MUST be saved for the
103+
* caller's memory error handler to not lose track of it.
104+
*/
94105
#define PyMem_Resize(p, type, n) \
95-
( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
96-
( (p) = (type *) PyMem_Realloc((p), (n) * sizeof(type)) ) )
106+
( (p) = ((n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \
107+
(type *) PyMem_Realloc((p), (n) * sizeof(type)) )
97108
#define PyMem_RESIZE(p, type, n) \
98-
( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
99-
( (p) = (type *) PyMem_REALLOC((p), (n) * sizeof(type)) ) )
109+
( (p) = ((n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \
110+
(type *) PyMem_REALLOC((p), (n) * sizeof(type)) )
100111

101112
/* PyMem{Del,DEL} are left over from ancient days, and shouldn't be used
102113
* anymore. They're just confusing aliases for PyMem_{Free,FREE} now.

Misc/NEWS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ Core and Builtins
1616
the python debugger steps into a class statement: the free variables (local
1717
variables defined in an outer scope) would be deleted from the outer scope.
1818

19+
- Issue #2620: Overflow checking when allocating or reallocating memory
20+
was not always being done properly in some python types and extension
21+
modules. PyMem_MALLOC, PyMem_REALLOC, PyMem_NEW and PyMem_RESIZE have
22+
all been updated to perform better checks and places in the code that
23+
would previously leak memory on the error path when such an allocation
24+
failed have been fixed.
25+
1926
Library
2027
-------
2128

Modules/almodule.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1633,9 +1633,11 @@ al_QueryValues(PyObject *self, PyObject *args)
16331633
if (nvals < 0)
16341634
goto cleanup;
16351635
if (nvals > setsize) {
1636+
ALvalue *old_return_set = return_set;
16361637
setsize = nvals;
16371638
PyMem_RESIZE(return_set, ALvalue, setsize);
16381639
if (return_set == NULL) {
1640+
return_set = old_return_set;
16391641
PyErr_NoMemory();
16401642
goto cleanup;
16411643
}

Modules/arraymodule.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,7 @@ static int
815815
array_do_extend(arrayobject *self, PyObject *bb)
816816
{
817817
Py_ssize_t size;
818+
char *old_item;
818819

819820
if (!array_Check(bb))
820821
return array_iter_extend(self, bb);
@@ -830,8 +831,10 @@ array_do_extend(arrayobject *self, PyObject *bb)
830831
return -1;
831832
}
832833
size = Py_SIZE(self) + Py_SIZE(b);
834+
old_item = self->ob_item;
833835
PyMem_RESIZE(self->ob_item, char, size*self->ob_descr->itemsize);
834836
if (self->ob_item == NULL) {
837+
self->ob_item = old_item;
835838
PyErr_NoMemory();
836839
return -1;
837840
}
@@ -884,7 +887,7 @@ array_inplace_repeat(arrayobject *self, Py_ssize_t n)
884887
if (size > PY_SSIZE_T_MAX / n) {
885888
return PyErr_NoMemory();
886889
}
887-
PyMem_Resize(items, char, n * size);
890+
PyMem_RESIZE(items, char, n * size);
888891
if (items == NULL)
889892
return PyErr_NoMemory();
890893
p = items;

Modules/selectmodule.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,10 +349,12 @@ update_ufd_array(pollObject *self)
349349
{
350350
Py_ssize_t i, pos;
351351
PyObject *key, *value;
352+
struct pollfd *old_ufds = self->ufds;
352353

353354
self->ufd_len = PyDict_Size(self->dict);
354-
PyMem_Resize(self->ufds, struct pollfd, self->ufd_len);
355+
PyMem_RESIZE(self->ufds, struct pollfd, self->ufd_len);
355356
if (self->ufds == NULL) {
357+
self->ufds = old_ufds;
356358
PyErr_NoMemory();
357359
return 0;
358360
}

Objects/obmalloc.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,15 @@ PyObject_Malloc(size_t nbytes)
726726
poolp next;
727727
uint size;
728728

729+
/*
730+
* Limit ourselves to PY_SSIZE_T_MAX bytes to prevent security holes.
731+
* Most python internals blindly use a signed Py_ssize_t to track
732+
* things without checking for overflows or negatives.
733+
* As size_t is unsigned, checking for nbytes < 0 is not required.
734+
*/
735+
if (nbytes > PY_SSIZE_T_MAX)
736+
return NULL;
737+
729738
/*
730739
* This implicitly redirects malloc(0).
731740
*/
@@ -1130,6 +1139,15 @@ PyObject_Realloc(void *p, size_t nbytes)
11301139
if (p == NULL)
11311140
return PyObject_Malloc(nbytes);
11321141

1142+
/*
1143+
* Limit ourselves to PY_SSIZE_T_MAX bytes to prevent security holes.
1144+
* Most python internals blindly use a signed Py_ssize_t to track
1145+
* things without checking for overflows or negatives.
1146+
* As size_t is unsigned, checking for nbytes < 0 is not required.
1147+
*/
1148+
if (nbytes > PY_SSIZE_T_MAX)
1149+
return NULL;
1150+
11331151
pool = POOL_ADDR(p);
11341152
if (Py_ADDRESS_IN_RANGE(p, pool)) {
11351153
/* We're in charge of this block */

0 commit comments

Comments
 (0)