Skip to content

Commit c8ed4ff

Browse files
committed
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.
1 parent 0cc3ea6 commit c8ed4ff

17 files changed

+327
-38
lines changed

Include/pymem.h

+8-4
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,18 @@ PyAPI_FUNC(void) PyMem_Free(void *);
8686
*/
8787

8888
#define PyMem_New(type, n) \
89-
( (type *) PyMem_Malloc((n) * sizeof(type)) )
89+
( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
90+
( (type *) PyMem_Malloc((n) * sizeof(type)) ) )
9091
#define PyMem_NEW(type, n) \
91-
( (type *) PyMem_MALLOC((n) * sizeof(type)) )
92+
( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
93+
( (type *) PyMem_MALLOC((n) * sizeof(type)) ) )
9294

9395
#define PyMem_Resize(p, type, n) \
94-
( (p) = (type *) PyMem_Realloc((p), (n) * sizeof(type)) )
96+
( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
97+
( (p) = (type *) PyMem_Realloc((p), (n) * sizeof(type)) ) )
9598
#define PyMem_RESIZE(p, type, n) \
96-
( (p) = (type *) PyMem_REALLOC((p), (n) * sizeof(type)) )
99+
( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \
100+
( (p) = (type *) PyMem_REALLOC((p), (n) * sizeof(type)) ) )
97101

98102
/* In order to avoid breaking old code mixing PyObject_{New, NEW} with
99103
PyMem_{Del, DEL} and PyMem_{Free, FREE}, the PyMem "release memory"

Include/pyport.h

+11
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,17 @@ typedef struct fd_set {
616616
#error "LONG_BIT definition appears wrong for platform (bad gcc/glibc config?)."
617617
#endif
618618

619+
/* Largest possible value of size_t.
620+
SIZE_MAX is part of C99, so it might be defined on some
621+
platforms. If it is not defined, (size_t)-1 is a portable
622+
definition for C89, due to the way signed->unsigned
623+
conversion is defined. */
624+
#ifdef SIZE_MAX
625+
#define PY_SIZE_MAX SIZE_MAX
626+
#else
627+
#define PY_SIZE_MAX ((size_t)-1)
628+
#endif
629+
619630
#ifdef __cplusplus
620631
}
621632
#endif

Misc/NEWS

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ What's New in Python 2.4.5c1?
1313
Core and builtins
1414
-----------------
1515

16+
- Added checks for integer overflows, contributed by Google. Some are
17+
only available if asserts are left in the code, in cases where they
18+
can't be triggered from Python code.
19+
1620
- patch #1630975: Fix crash when replacing sys.stdout in sitecustomize.py
1721

1822
Extension Modules

Modules/_csv.c

+10
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,10 @@ parse_grow_buff(ReaderObj *self)
470470
self->field = PyMem_Malloc(self->field_size);
471471
}
472472
else {
473+
if (self->field_size > INT_MAX / 2) {
474+
PyErr_NoMemory();
475+
return 0;
476+
}
473477
self->field_size *= 2;
474478
self->field = PyMem_Realloc(self->field, self->field_size);
475479
}
@@ -1003,6 +1007,12 @@ join_append_data(WriterObj *self, char *field, int quote_empty,
10031007
static int
10041008
join_check_rec_size(WriterObj *self, int rec_len)
10051009
{
1010+
1011+
if (rec_len < 0 || rec_len > INT_MAX - MEM_INCR) {
1012+
PyErr_NoMemory();
1013+
return 0;
1014+
}
1015+
10061016
if (rec_len > self->rec_size) {
10071017
if (self->rec_size == 0) {
10081018
self->rec_size = (rec_len / MEM_INCR + 1) * MEM_INCR;

Modules/arraymodule.c

+33-1
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,9 @@ array_concat(arrayobject *a, PyObject *bb)
651651
PyErr_BadArgument();
652652
return NULL;
653653
}
654+
if (a->ob_size > INT_MAX - b->ob_size) {
655+
return PyErr_NoMemory();
656+
}
654657
size = a->ob_size + b->ob_size;
655658
np = (arrayobject *) newarrayobject(&Arraytype, size, a->ob_descr);
656659
if (np == NULL) {
@@ -673,6 +676,9 @@ array_repeat(arrayobject *a, int n)
673676
int nbytes;
674677
if (n < 0)
675678
n = 0;
679+
if ((a->ob_size != 0) && (n > INT_MAX / a->ob_size)) {
680+
return PyErr_NoMemory();
681+
}
676682
size = a->ob_size * n;
677683
np = (arrayobject *) newarrayobject(&Arraytype, size, a->ob_descr);
678684
if (np == NULL)
@@ -817,6 +823,11 @@ array_do_extend(arrayobject *self, PyObject *bb)
817823
"can only extend with array of same kind");
818824
return -1;
819825
}
826+
if ((self->ob_size > INT_MAX - b->ob_size) ||
827+
((self->ob_size + b->ob_size) > INT_MAX / self->ob_descr->itemsize)) {
828+
PyErr_NoMemory();
829+
return -1;
830+
}
820831
size = self->ob_size + b->ob_size;
821832
PyMem_RESIZE(self->ob_item, char, size*self->ob_descr->itemsize);
822833
if (self->ob_item == NULL) {
@@ -858,6 +869,10 @@ array_inplace_repeat(arrayobject *self, int n)
858869
if (n < 0)
859870
n = 0;
860871
items = self->ob_item;
872+
if ((self->ob_descr->itemsize != 0) &&
873+
(self->ob_size > INT_MAX / self->ob_descr->itemsize)) {
874+
return PyErr_NoMemory();
875+
}
861876
size = self->ob_size * self->ob_descr->itemsize;
862877
if (n == 0) {
863878
PyMem_FREE(items);
@@ -866,6 +881,9 @@ array_inplace_repeat(arrayobject *self, int n)
866881
self->allocated = 0;
867882
}
868883
else {
884+
if (size > INT_MAX / n) {
885+
return PyErr_NoMemory();
886+
}
869887
PyMem_Resize(items, char, n * size);
870888
if (items == NULL)
871889
return PyErr_NoMemory();
@@ -1278,6 +1296,9 @@ array_fromlist(arrayobject *self, PyObject *list)
12781296
if ((*self->ob_descr->setitem)(self,
12791297
self->ob_size - n + i, v) != 0) {
12801298
self->ob_size -= n;
1299+
if (itemsize && (self->ob_size > INT_MAX / itemsize)) {
1300+
return PyErr_NoMemory();
1301+
}
12811302
PyMem_RESIZE(item, char,
12821303
self->ob_size * itemsize);
12831304
self->ob_item = item;
@@ -1337,6 +1358,10 @@ array_fromstring(arrayobject *self, PyObject *args)
13371358
n = n / itemsize;
13381359
if (n > 0) {
13391360
char *item = self->ob_item;
1361+
if ((n > INT_MAX - self->ob_size) ||
1362+
((self->ob_size + n) > INT_MAX / itemsize)) {
1363+
return PyErr_NoMemory();
1364+
}
13401365
PyMem_RESIZE(item, char, (self->ob_size + n) * itemsize);
13411366
if (item == NULL) {
13421367
PyErr_NoMemory();
@@ -1362,8 +1387,12 @@ values,as if it had been read from a file using the fromfile() method).");
13621387
static PyObject *
13631388
array_tostring(arrayobject *self, PyObject *unused)
13641389
{
1365-
return PyString_FromStringAndSize(self->ob_item,
1390+
if (self->ob_size <= INT_MAX / self->ob_descr->itemsize) {
1391+
return PyString_FromStringAndSize(self->ob_item,
13661392
self->ob_size * self->ob_descr->itemsize);
1393+
} else {
1394+
return PyErr_NoMemory();
1395+
}
13671396
}
13681397

13691398
PyDoc_STRVAR(tostring_doc,
@@ -1391,6 +1420,9 @@ array_fromunicode(arrayobject *self, PyObject *args)
13911420
}
13921421
if (n > 0) {
13931422
Py_UNICODE *item = (Py_UNICODE *) self->ob_item;
1423+
if (self->ob_size > INT_MAX - n) {
1424+
return PyErr_NoMemory();
1425+
}
13941426
PyMem_RESIZE(item, Py_UNICODE, self->ob_size + n);
13951427
if (item == NULL) {
13961428
PyErr_NoMemory();

Modules/audioop.c

+44-12
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,7 @@ static PyObject *
674674
audioop_tostereo(PyObject *self, PyObject *args)
675675
{
676676
signed char *cp, *ncp;
677-
int len, size, val1, val2, val = 0;
677+
int len, new_len, size, val1, val2, val = 0;
678678
double fac1, fac2, fval, maxval;
679679
PyObject *rv;
680680
int i;
@@ -690,7 +690,14 @@ audioop_tostereo(PyObject *self, PyObject *args)
690690
return 0;
691691
}
692692

693-
rv = PyString_FromStringAndSize(NULL, len*2);
693+
new_len = len*2;
694+
if (new_len < 0) {
695+
PyErr_SetString(PyExc_MemoryError,
696+
"not enough memory for output buffer");
697+
return 0;
698+
}
699+
700+
rv = PyString_FromStringAndSize(NULL, new_len);
694701
if ( rv == 0 )
695702
return 0;
696703
ncp = (signed char *)PyString_AsString(rv);
@@ -853,7 +860,7 @@ audioop_lin2lin(PyObject *self, PyObject *args)
853860
{
854861
signed char *cp;
855862
unsigned char *ncp;
856-
int len, size, size2, val = 0;
863+
int len, new_len, size, size2, val = 0;
857864
PyObject *rv;
858865
int i, j;
859866

@@ -867,7 +874,13 @@ audioop_lin2lin(PyObject *self, PyObject *args)
867874
return 0;
868875
}
869876

870-
rv = PyString_FromStringAndSize(NULL, (len/size)*size2);
877+
new_len = (len/size)*size2;
878+
if (new_len < 0) {
879+
PyErr_SetString(PyExc_MemoryError,
880+
"not enough memory for output buffer");
881+
return 0;
882+
}
883+
rv = PyString_FromStringAndSize(NULL, new_len);
871884
if ( rv == 0 )
872885
return 0;
873886
ncp = (unsigned char *)PyString_AsString(rv);
@@ -903,6 +916,7 @@ audioop_ratecv(PyObject *self, PyObject *args)
903916
int chan, d, *prev_i, *cur_i, cur_o;
904917
PyObject *state, *samps, *str, *rv = NULL;
905918
int bytes_per_frame;
919+
size_t alloc_size;
906920

907921
weightA = 1;
908922
weightB = 0;
@@ -944,8 +958,14 @@ audioop_ratecv(PyObject *self, PyObject *args)
944958
inrate /= d;
945959
outrate /= d;
946960

947-
prev_i = (int *) malloc(nchannels * sizeof(int));
948-
cur_i = (int *) malloc(nchannels * sizeof(int));
961+
alloc_size = sizeof(int) * (unsigned)nchannels;
962+
if (alloc_size < nchannels) {
963+
PyErr_SetString(PyExc_MemoryError,
964+
"not enough memory for output buffer");
965+
return 0;
966+
}
967+
prev_i = (int *) malloc(alloc_size);
968+
cur_i = (int *) malloc(alloc_size);
949969
if (prev_i == NULL || cur_i == NULL) {
950970
(void) PyErr_NoMemory();
951971
goto exit;
@@ -1116,7 +1136,7 @@ audioop_ulaw2lin(PyObject *self, PyObject *args)
11161136
unsigned char *cp;
11171137
unsigned char cval;
11181138
signed char *ncp;
1119-
int len, size, val;
1139+
int len, new_len, size, val;
11201140
PyObject *rv;
11211141
int i;
11221142

@@ -1129,12 +1149,18 @@ audioop_ulaw2lin(PyObject *self, PyObject *args)
11291149
return 0;
11301150
}
11311151

1132-
rv = PyString_FromStringAndSize(NULL, len*size);
1152+
new_len = len*size;
1153+
if (new_len < 0) {
1154+
PyErr_SetString(PyExc_MemoryError,
1155+
"not enough memory for output buffer");
1156+
return 0;
1157+
}
1158+
rv = PyString_FromStringAndSize(NULL, new_len);
11331159
if ( rv == 0 )
11341160
return 0;
11351161
ncp = (signed char *)PyString_AsString(rv);
11361162

1137-
for ( i=0; i < len*size; i += size ) {
1163+
for ( i=0; i < new_len; i += size ) {
11381164
cval = *cp++;
11391165
val = st_ulaw_to_linear(cval);
11401166

@@ -1259,7 +1285,7 @@ audioop_adpcm2lin(PyObject *self, PyObject *args)
12591285
{
12601286
signed char *cp;
12611287
signed char *ncp;
1262-
int len, size, valpred, step, delta, index, sign, vpdiff;
1288+
int len, new_len, size, valpred, step, delta, index, sign, vpdiff;
12631289
PyObject *rv, *str, *state;
12641290
int i, inputbuffer = 0, bufferstep;
12651291

@@ -1281,15 +1307,21 @@ audioop_adpcm2lin(PyObject *self, PyObject *args)
12811307
} else if ( !PyArg_Parse(state, "(ii)", &valpred, &index) )
12821308
return 0;
12831309

1284-
str = PyString_FromStringAndSize(NULL, len*size*2);
1310+
new_len = len*size*2;
1311+
if (new_len < 0) {
1312+
PyErr_SetString(PyExc_MemoryError,
1313+
"not enough memory for output buffer");
1314+
return 0;
1315+
}
1316+
str = PyString_FromStringAndSize(NULL, new_len);
12851317
if ( str == 0 )
12861318
return 0;
12871319
ncp = (signed char *)PyString_AsString(str);
12881320

12891321
step = stepsizeTable[index];
12901322
bufferstep = 0;
12911323

1292-
for ( i=0; i < len*size*2; i += size ) {
1324+
for ( i=0; i < new_len; i += size ) {
12931325
/* Step 1 - get the delta value and compute next index */
12941326
if ( bufferstep ) {
12951327
delta = inputbuffer & 0xf;

0 commit comments

Comments
 (0)