X Tutup
Skip to content

Commit fea1be4

Browse files
author
neal.norwitz
committed
Security patches from Apple: prevent int overflow when allocating memory
git-svn-id: http://svn.python.org/projects/python/trunk@65335 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent 1327869 commit fea1be4

File tree

13 files changed

+258
-29
lines changed

13 files changed

+258
-29
lines changed

Lib/test/seq_tests.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -306,11 +306,13 @@ def test_repeat(self):
306306
self.assertEqual(id(s), id(s*1))
307307

308308
def test_bigrepeat(self):
309-
x = self.type2test([0])
310-
x *= 2**16
311-
self.assertRaises(MemoryError, x.__mul__, 2**16)
312-
if hasattr(x, '__imul__'):
313-
self.assertRaises(MemoryError, x.__imul__, 2**16)
309+
import sys
310+
if sys.maxint <= 2147483647:
311+
x = self.type2test([0])
312+
x *= 2**16
313+
self.assertRaises(MemoryError, x.__mul__, 2**16)
314+
if hasattr(x, '__imul__'):
315+
self.assertRaises(MemoryError, x.__imul__, 2**16)
314316

315317
def test_subscript(self):
316318
a = self.type2test([10, 11])

Lib/test/test_bigmem.py

Lines changed: 110 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from test import test_support
2-
from test.test_support import bigmemtest, _1G, _2G
2+
from test.test_support import bigmemtest, _1G, _2G, _4G, precisionbigmemtest
33

44
import unittest
55
import operator
@@ -54,6 +54,22 @@ def test_center(self, size):
5454
self.assertEquals(s[lpadsize:-rpadsize], SUBSTR)
5555
self.assertEquals(s.strip(), SUBSTR.strip())
5656

57+
@precisionbigmemtest(size=_2G - 1, memuse=1)
58+
def test_center_unicode(self, size):
59+
SUBSTR = u' abc def ghi'
60+
try:
61+
s = SUBSTR.center(size)
62+
except OverflowError:
63+
pass # acceptable on 32-bit
64+
else:
65+
self.assertEquals(len(s), size)
66+
lpadsize = rpadsize = (len(s) - len(SUBSTR)) // 2
67+
if len(s) % 2:
68+
lpadsize += 1
69+
self.assertEquals(s[lpadsize:-rpadsize], SUBSTR)
70+
self.assertEquals(s.strip(), SUBSTR.strip())
71+
del s
72+
5773
@bigmemtest(minsize=_2G, memuse=2)
5874
def test_count(self, size):
5975
SUBSTR = ' abc def ghi'
@@ -70,10 +86,51 @@ def test_decode(self, size):
7086
s = '.' * size
7187
self.assertEquals(len(s.decode('utf-8')), size)
7288

89+
def basic_encode_test(self, size, enc, c=u'.', expectedsize=None):
90+
if expectedsize is None:
91+
expectedsize = size
92+
93+
s = c * size
94+
self.assertEquals(len(s.encode(enc)), expectedsize)
95+
7396
@bigmemtest(minsize=_2G + 2, memuse=3)
7497
def test_encode(self, size):
75-
s = u'.' * size
76-
self.assertEquals(len(s.encode('utf-8')), size)
98+
return self.basic_encode_test(size, 'utf-8')
99+
100+
@precisionbigmemtest(size=_4G / 6 + 2, memuse=2)
101+
def test_encode_raw_unicode_escape(self, size):
102+
try:
103+
return self.basic_encode_test(size, 'raw_unicode_escape')
104+
except MemoryError:
105+
pass # acceptable on 32-bit
106+
107+
@precisionbigmemtest(size=_4G / 5 + 70, memuse=3)
108+
def test_encode_utf7(self, size):
109+
try:
110+
return self.basic_encode_test(size, 'utf7')
111+
except MemoryError:
112+
pass # acceptable on 32-bit
113+
114+
@precisionbigmemtest(size=_4G / 4 + 5, memuse=6)
115+
def test_encode_utf32(self, size):
116+
try:
117+
return self.basic_encode_test(size, 'utf32', expectedsize=4*size+4)
118+
except MemoryError:
119+
pass # acceptable on 32-bit
120+
121+
@precisionbigmemtest(size=_2G-1, memuse=2)
122+
def test_decodeascii(self, size):
123+
return self.basic_encode_test(size, 'ascii', c='A')
124+
125+
@precisionbigmemtest(size=_4G / 5, memuse=6+2)
126+
def test_unicode_repr_oflw(self, size):
127+
try:
128+
s = u"\uAAAA"*size
129+
r = repr(s)
130+
except MemoryError:
131+
pass # acceptable on 32-bit
132+
else:
133+
self.failUnless(s == eval(r))
77134

78135
@bigmemtest(minsize=_2G, memuse=2)
79136
def test_endswith(self, size):
@@ -459,6 +516,11 @@ def test_repr_large(self, size):
459516
self.assertEquals(s.count('\\'), size)
460517
self.assertEquals(s.count('0'), size * 2)
461518

519+
@bigmemtest(minsize=2**32 / 5, memuse=6+2)
520+
def test_unicode_repr(self, size):
521+
s = u"\uAAAA" * size
522+
self.failUnless(len(repr(s)) > size)
523+
462524
# This test is meaningful even with size < 2G, as long as the
463525
# doubled string is > 2G (but it tests more if both are > 2G :)
464526
@bigmemtest(minsize=_1G + 2, memuse=3)
@@ -642,6 +704,35 @@ def test_repeat_small(self, size):
642704
def test_repeat_large(self, size):
643705
return self.basic_test_repeat(size)
644706

707+
@bigmemtest(minsize=_1G - 1, memuse=12)
708+
def test_repeat_large_2(self, size):
709+
return self.basic_test_repeat(size)
710+
711+
@precisionbigmemtest(size=_1G - 1, memuse=9)
712+
def test_from_2G_generator(self, size):
713+
try:
714+
t = tuple(xrange(size))
715+
except MemoryError:
716+
pass # acceptable on 32-bit
717+
else:
718+
count = 0
719+
for item in t:
720+
self.assertEquals(item, count)
721+
count += 1
722+
self.assertEquals(count, size)
723+
724+
@precisionbigmemtest(size=_1G - 25, memuse=9)
725+
def test_from_almost_2G_generator(self, size):
726+
try:
727+
t = tuple(xrange(size))
728+
count = 0
729+
for item in t:
730+
self.assertEquals(item, count)
731+
count += 1
732+
self.assertEquals(count, size)
733+
except MemoryError:
734+
pass # acceptable, expected on 32-bit
735+
645736
# Like test_concat, split in two.
646737
def basic_test_repr(self, size):
647738
t = (0,) * size
@@ -957,8 +1048,23 @@ def test_sort(self, size):
9571048
self.assertEquals(l[:10], [1] * 10)
9581049
self.assertEquals(l[-10:], [5] * 10)
9591050

1051+
class BufferTest(unittest.TestCase):
1052+
1053+
@precisionbigmemtest(size=_1G, memuse=4)
1054+
def test_repeat(self, size):
1055+
try:
1056+
b = buffer("AAAA")*size
1057+
except MemoryError:
1058+
pass # acceptable on 32-bit
1059+
else:
1060+
count = 0
1061+
for c in b:
1062+
self.assertEquals(c, 'A')
1063+
count += 1
1064+
self.assertEquals(count, size*4)
1065+
9601066
def test_main():
961-
test_support.run_unittest(StrTest, TupleTest, ListTest)
1067+
test_support.run_unittest(StrTest, TupleTest, ListTest, BufferTest)
9621068

9631069
if __name__ == '__main__':
9641070
if len(sys.argv) > 1:

Lib/test/test_strop.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,25 @@ def test_data_attributes(self):
115115
strop.uppercase
116116
strop.whitespace
117117

118+
@test_support.precisionbigmemtest(size=test_support._2G - 1, memuse=5)
119+
def test_stropjoin_huge_list(self, size):
120+
a = "A" * size
121+
try:
122+
r = strop.join([a, a], a)
123+
except OverflowError:
124+
pass
125+
else:
126+
self.assertEquals(len(r), len(a) * 3)
127+
128+
@test_support.precisionbigmemtest(size=test_support._2G - 1, memuse=1)
129+
def test_stropjoin_huge_tup(self, size):
130+
a = "A" * size
131+
try:
132+
r = strop.join((a, a), a)
133+
except OverflowError:
134+
pass # acceptable on 32-bit
135+
else:
136+
self.assertEquals(len(r), len(a) * 3)
118137

119138
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'
120139

Lib/test/test_support.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ def import_module(name, deprecated=False):
6767
use_resources = None # Flag set to [] by regrtest.py
6868
max_memuse = 0 # Disable bigmem tests (they will still be run with
6969
# small sizes, to make sure they work.)
70+
real_max_memuse = 0
7071

7172
# _original_stdout is meant to hold stdout at the time regrtest began.
7273
# This may be "the real" stdout, or IDLE's emulation of stdout, or whatever.
@@ -611,12 +612,14 @@ def inner(*args, **kwds):
611612
_1M = 1024*1024
612613
_1G = 1024 * _1M
613614
_2G = 2 * _1G
615+
_4G = 4 * _1G
614616

615617
MAX_Py_ssize_t = sys.maxsize
616618

617619
def set_memlimit(limit):
618620
import re
619621
global max_memuse
622+
global real_max_memuse
620623
sizes = {
621624
'k': 1024,
622625
'm': _1M,
@@ -628,6 +631,7 @@ def set_memlimit(limit):
628631
if m is None:
629632
raise ValueError('Invalid memory limit %r' % (limit,))
630633
memlimit = int(float(m.group(1)) * sizes[m.group(3).lower()])
634+
real_max_memuse = memlimit
631635
if memlimit > MAX_Py_ssize_t:
632636
memlimit = MAX_Py_ssize_t
633637
if memlimit < _2G - 1:
@@ -673,6 +677,27 @@ def wrapper(self):
673677
return wrapper
674678
return decorator
675679

680+
def precisionbigmemtest(size, memuse, overhead=5*_1M):
681+
def decorator(f):
682+
def wrapper(self):
683+
if not real_max_memuse:
684+
maxsize = 5147
685+
else:
686+
maxsize = size
687+
688+
if real_max_memuse and real_max_memuse < maxsize * memuse:
689+
if verbose:
690+
sys.stderr.write("Skipping %s because of memory "
691+
"constraint\n" % (f.__name__,))
692+
return
693+
694+
return f(self, maxsize)
695+
wrapper.size = size
696+
wrapper.memuse = memuse
697+
wrapper.overhead = overhead
698+
return wrapper
699+
return decorator
700+
676701
def bigaddrspacetest(f):
677702
"""Decorator for tests that fill the address space."""
678703
def wrapper(self):

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ What's New in Python 2.6 beta 3?
1212
Core and Builtins
1313
-----------------
1414

15+
- Apply security patches from Apple.
16+
1517
- Issue #2542: Now that issubclass() may call arbitrary code, ensure that
1618
PyErr_ExceptionMatches returns 0 when an exception occurs there.
1719

Modules/gcmodule.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1342,7 +1342,10 @@ PyObject *
13421342
_PyObject_GC_Malloc(size_t basicsize)
13431343
{
13441344
PyObject *op;
1345-
PyGC_Head *g = (PyGC_Head *)PyObject_MALLOC(
1345+
PyGC_Head *g;
1346+
if (basicsize > PY_SSIZE_T_MAX - sizeof(PyGC_Head))
1347+
return PyErr_NoMemory();
1348+
g = (PyGC_Head *)PyObject_MALLOC(
13461349
sizeof(PyGC_Head) + basicsize);
13471350
if (g == NULL)
13481351
return PyErr_NoMemory();
@@ -1385,6 +1388,8 @@ _PyObject_GC_Resize(PyVarObject *op, Py_ssize_t nitems)
13851388
{
13861389
const size_t basicsize = _PyObject_VAR_SIZE(Py_TYPE(op), nitems);
13871390
PyGC_Head *g = AS_GC(op);
1391+
if (basicsize > PY_SSIZE_T_MAX - sizeof(PyGC_Head))
1392+
return (PyVarObject *)PyErr_NoMemory();
13881393
g = (PyGC_Head *)PyObject_REALLOC(g, sizeof(PyGC_Head) + basicsize);
13891394
if (g == NULL)
13901395
return (PyVarObject *)PyErr_NoMemory();

Modules/mmapmodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ mmap_read_method(mmap_object *self,
239239
return(NULL);
240240

241241
/* silently 'adjust' out-of-range requests */
242-
if ((self->pos + num_bytes) > self->size) {
242+
if (num_bytes > self->size - self->pos) {
243243
num_bytes -= (self->pos+num_bytes) - self->size;
244244
}
245245
result = Py_BuildValue("s#", self->data+self->pos, num_bytes);

Modules/stropmodule.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,13 @@ strop_joinfields(PyObject *self, PyObject *args)
216216
return NULL;
217217
}
218218
slen = PyString_GET_SIZE(item);
219+
if (slen > PY_SSIZE_T_MAX - reslen ||
220+
seplen > PY_SSIZE_T_MAX - reslen - seplen) {
221+
PyErr_SetString(PyExc_OverflowError,
222+
"input too long");
223+
Py_DECREF(res);
224+
return NULL;
225+
}
219226
while (reslen + slen + seplen >= sz) {
220227
if (_PyString_Resize(&res, sz * 2) < 0)
221228
return NULL;
@@ -253,6 +260,14 @@ strop_joinfields(PyObject *self, PyObject *args)
253260
return NULL;
254261
}
255262
slen = PyString_GET_SIZE(item);
263+
if (slen > PY_SSIZE_T_MAX - reslen ||
264+
seplen > PY_SSIZE_T_MAX - reslen - seplen) {
265+
PyErr_SetString(PyExc_OverflowError,
266+
"input too long");
267+
Py_DECREF(res);
268+
Py_XDECREF(item);
269+
return NULL;
270+
}
256271
while (reslen + slen + seplen >= sz) {
257272
if (_PyString_Resize(&res, sz * 2) < 0) {
258273
Py_DECREF(item);

Objects/bufferobject.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,10 @@ buffer_repeat(PyBufferObject *self, Py_ssize_t count)
431431
count = 0;
432432
if (!get_buf(self, &ptr, &size, ANY_BUFFER))
433433
return NULL;
434+
if (count > PY_SSIZE_T_MAX / size) {
435+
PyErr_SetString(PyExc_MemoryError, "result too large");
436+
return NULL;
437+
}
434438
ob = PyString_FromStringAndSize(NULL, size * count);
435439
if ( ob == NULL )
436440
return NULL;

Objects/longobject.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ _PyLong_New(Py_ssize_t size)
7070
return NULL;
7171
}
7272
/* coverity[ampersand_in_size] */
73+
/* XXX(nnorwitz): This can overflow --
74+
PyObject_NEW_VAR / _PyObject_VAR_SIZE need to detect overflow */
7375
return PyObject_NEW_VAR(PyLongObject, &PyLong_Type, size);
7476
}
7577

0 commit comments

Comments
 (0)
X Tutup