-
-
Notifications
You must be signed in to change notification settings - Fork 33.8k
Closed as not planned
Closed as not planned
Copy link
Labels
interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
Description
What happened?
longrangeiter_setstate clips the stale index by assigning state = r->len without taking a new reference. The PoC replaces r->len with a custom int subclass whose __mul__ re-enters __setstate__, and the inner call swaps r->len for a plain int and decrefs the old object. When control returns to the outer frame it still writes to self.busy on the freed subclass, triggering a use-after-free.
Proof of Concept:
# shrinked version
it = iter(range(1 << 65))
class Evil(int):
def __mul__(self, _):
it.__setstate__(0)
return 0
class Injector(int):
def __rsub__(self, _):
return Evil(10)
it.__setstate__(Injector(0))
it.__setstate__(20)Affected Versions
| Python Version | Status | Exit Code |
|---|---|---|
Python 3.9.24+ (heads/3.9:111bbc15b26, Oct 28 2025, 16:51:20) |
OK | 0 |
Python 3.10.19+ (heads/3.10:014261980b1, Oct 28 2025, 16:52:08) [Clang 18.1.3 (1ubuntu1)] |
OK | 0 |
Python 3.11.14+ (heads/3.11:88f3f5b5f11, Oct 28 2025, 16:53:08) [Clang 18.1.3 (1ubuntu1)] |
OK | 0 |
Python 3.12.12+ (heads/3.12:8cb2092bd8c, Oct 28 2025, 16:54:14) [Clang 18.1.3 (1ubuntu1)] |
ASAN | 1 |
Python 3.13.9+ (heads/3.13:9c8eade20c6, Oct 28 2025, 16:55:18) [Clang 18.1.3 (1ubuntu1)] |
ASAN | 1 |
Python 3.14.0+ (heads/3.14:2e216728038, Oct 28 2025, 16:56:16) [Clang 18.1.3 (1ubuntu1)] |
ASAN | 1 |
Python 3.15.0a1+ (heads/main:f5394c257ce, Oct 28 2025, 19:29:54) [GCC 13.3.0] |
ASAN | 1 |
Vulnerable Code
static PyObject *
longrangeiter_setstate(PyObject *op, PyObject *state)
{
longrangeiterobject *r = (longrangeiterobject*)op;
PyObject *zero = _PyLong_GetZero(); // borrowed reference
int cmp;
/* clip the value */
cmp = PyObject_RichCompareBool(state, zero, Py_LT);
if (cmp < 0)
return NULL;
if (cmp > 0) {
state = zero;
}
else {
cmp = PyObject_RichCompareBool(r->len, state, Py_LT);
if (cmp < 0)
return NULL;
if (cmp > 0)
/* Bug: Cache the runtime object ptr without increasing its reference. */
state = r->len;
}
PyObject *product = PyNumber_Multiply(state, r->step);
if (product == NULL)
return NULL;
PyObject *new_start = PyNumber_Add(r->start, product);
Py_DECREF(product);
if (new_start == NULL)
return NULL;
PyObject *new_len = PyNumber_Subtract(r->len, state);
if (new_len == NULL) {
Py_DECREF(new_start);
return NULL;
}
PyObject *tmp = r->start;
r->start = new_start;
Py_SETREF(r->len, new_len);
Py_DECREF(tmp);
Py_RETURN_NONE;
}Sanitizer Output
=================================================================
==1942344==ERROR: AddressSanitizer: heap-use-after-free on address 0x5080000cd958 at pc 0x5cf7cd207671 bp 0x7ffc3984e920 sp 0x7ffc3984e910
READ of size 8 at 0x5080000cd958 thread T0
#0 0x5cf7cd207670 in _Py_TYPE Include/object.h:277
#1 0x5cf7cd207670 in Py_IS_TYPE Include/object.h:302
#2 0x5cf7cd207670 in binary_op1 Objects/abstract.c:947
#3 0x5cf7cd207777 in binary_op Objects/abstract.c:1005
#4 0x5cf7cd20ad3a in PyNumber_Subtract Objects/abstract.c:1126
#5 0x5cf7cd3320c1 in longrangeiter_setstate Objects/rangeobject.c:1070
#6 0x5cf7cd25d473 in method_vectorcall_O Objects/descrobject.c:476
#7 0x5cf7cd23de7f in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169
#8 0x5cf7cd23df72 in PyObject_Vectorcall Objects/call.c:327
#9 0x5cf7cd4bc056 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620
#10 0x5cf7cd4ffe54 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121
#11 0x5cf7cd500148 in _PyEval_Vector Python/ceval.c:2001
#12 0x5cf7cd5003f8 in PyEval_EvalCode Python/ceval.c:884
#13 0x5cf7cd5f7507 in run_eval_code_obj Python/pythonrun.c:1365
#14 0x5cf7cd5f7723 in run_mod Python/pythonrun.c:1459
#15 0x5cf7cd5f857a in pyrun_file Python/pythonrun.c:1293
#16 0x5cf7cd5fb220 in _PyRun_SimpleFileObject Python/pythonrun.c:521
#17 0x5cf7cd5fb4f6 in _PyRun_AnyFileObject Python/pythonrun.c:81
#18 0x5cf7cd64c74d in pymain_run_file_obj Modules/main.c:410
#19 0x5cf7cd64c9b4 in pymain_run_file Modules/main.c:429
#20 0x5cf7cd64e1b2 in pymain_run_python Modules/main.c:691
#21 0x5cf7cd64e842 in Py_RunMain Modules/main.c:772
#22 0x5cf7cd64ea2e in pymain_main Modules/main.c:802
#23 0x5cf7cd64edb3 in Py_BytesMain Modules/main.c:826
#24 0x5cf7cd0d2645 in main Programs/python.c:15
#25 0x7176a1c2a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#26 0x7176a1c2a28a in __libc_start_main_impl ../csu/libc-start.c:360
#27 0x5cf7cd0d2574 in _start (/home/jackfromeast/Desktop/entropy/targets/grammar-afl++-latest/targets/cpython/python+0x2dd574) (BuildId: 202d5dbb945f6d5f5a66ad50e2688d56affd6ecb)
0x5080000cd958 is located 56 bytes inside of 96-byte region [0x5080000cd920,0x5080000cd980)
freed by thread T0 here:
#0 0x7176a20fc4d8 in free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:52
#1 0x5cf7cd30496d in _PyMem_RawFree Objects/obmalloc.c:91
#2 0x5cf7cd306cd9 in _PyMem_DebugRawFree Objects/obmalloc.c:2955
#3 0x5cf7cd306d1a in _PyMem_DebugFree Objects/obmalloc.c:3100
#4 0x5cf7cd32f06c in PyObject_Free Objects/obmalloc.c:1522
#5 0x5cf7cd56dcf7 in PyObject_GC_Del Python/gc.c:2435
#6 0x5cf7cd2b1f3a in long_dealloc Objects/longobject.c:3668
#7 0x5cf7cd367663 in subtype_dealloc Objects/typeobject.c:2852
#8 0x5cf7cd2fb481 in _Py_Dealloc Objects/object.c:3200
#9 0x5cf7cd56392f in Py_DECREF_MORTAL Include/internal/pycore_object.h:450
#10 0x5cf7cd5639e5 in PyStackRef_XCLOSE Include/internal/pycore_stackref.h:736
#11 0x5cf7cd564a86 in _PyFrame_ClearLocals Python/frame.c:101
#12 0x5cf7cd564c7e in _PyFrame_ClearExceptCode Python/frame.c:126
#13 0x5cf7cd4a8bcd in clear_thread_frame Python/ceval.c:1826
#14 0x5cf7cd4acc31 in _PyEval_FrameClearAndPop Python/ceval.c:1850
#15 0x5cf7cd4f34c9 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:10403
#16 0x5cf7cd4ffe54 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121
#17 0x5cf7cd500148 in _PyEval_Vector Python/ceval.c:2001
#18 0x5cf7cd23d9b8 in _PyFunction_Vectorcall Objects/call.c:413
#19 0x5cf7cd35056b in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169
#20 0x5cf7cd350680 in vectorcall_unbound Objects/typeobject.c:3033
#21 0x5cf7cd36cef4 in vectorcall_maybe Objects/typeobject.c:3130
#22 0x5cf7cd370819 in slot_nb_multiply Objects/typeobject.c:10397
#23 0x5cf7cd207613 in binary_op1 Objects/abstract.c:966
#24 0x5cf7cd20bc64 in PyNumber_Multiply Objects/abstract.c:1170
#25 0x5cf7cd33204d in longrangeiter_setstate Objects/rangeobject.c:1063
#26 0x5cf7cd25d473 in method_vectorcall_O Objects/descrobject.c:476
#27 0x5cf7cd23de7f in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169
#28 0x5cf7cd23df72 in PyObject_Vectorcall Objects/call.c:327
#29 0x5cf7cd4bc056 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620
previously allocated by thread T0 here:
#0 0x7176a20fd9c7 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
#1 0x5cf7cd305284 in _PyMem_RawMalloc Objects/obmalloc.c:63
#2 0x5cf7cd304655 in _PyMem_DebugRawAlloc Objects/obmalloc.c:2887
#3 0x5cf7cd3046bd in _PyMem_DebugRawMalloc Objects/obmalloc.c:2920
#4 0x5cf7cd305f3b in _PyMem_DebugMalloc Objects/obmalloc.c:3085
#5 0x5cf7cd32ef28 in PyObject_Malloc Objects/obmalloc.c:1493
#6 0x5cf7cd36103b in _PyObject_MallocWithType Include/internal/pycore_object_alloc.h:46
#7 0x5cf7cd36103b in _PyType_AllocNoTrack Objects/typeobject.c:2504
#8 0x5cf7cd3611c7 in PyType_GenericAlloc Objects/typeobject.c:2535
#9 0x5cf7cd2c00a1 in long_subtype_new Objects/longobject.c:6047
#10 0x5cf7cd2bfd4a in long_new_impl Objects/longobject.c:5986
#11 0x5cf7cd2c0474 in long_new Objects/clinic/longobject.c.h:69
#12 0x5cf7cd364d4e in tp_new_wrapper Objects/typeobject.c:10142
#13 0x5cf7cd2f11a4 in cfunction_call Objects/methodobject.c:564
#14 0x5cf7cd23dc71 in _PyObject_MakeTpCall Objects/call.c:242
#15 0x5cf7cd23df19 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:167
#16 0x5cf7cd23df72 in PyObject_Vectorcall Objects/call.c:327
#17 0x5cf7cd4bc056 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620
#18 0x5cf7cd4ffe54 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121
#19 0x5cf7cd500148 in _PyEval_Vector Python/ceval.c:2001
#20 0x5cf7cd23d9b8 in _PyFunction_Vectorcall Objects/call.c:413
#21 0x5cf7cd240b54 in _PyObject_VectorcallDictTstate Objects/call.c:135
#22 0x5cf7cd240f79 in _PyObject_Call_Prepend Objects/call.c:504
#23 0x5cf7cd355dcc in slot_tp_new Objects/typeobject.c:10853
#24 0x5cf7cd364346 in type_call Objects/typeobject.c:2448
#25 0x5cf7cd23dc71 in _PyObject_MakeTpCall Objects/call.c:242
#26 0x5cf7cd23df19 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:167
#27 0x5cf7cd23df72 in PyObject_Vectorcall Objects/call.c:327
#28 0x5cf7cd4bc056 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620
#29 0x5cf7cd4ffe54 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121
#30 0x5cf7cd500148 in _PyEval_Vector Python/ceval.c:2001
SUMMARY: AddressSanitizer: heap-use-after-free Include/object.h:277 in _Py_TYPE
Shadow bytes around the buggy address:
0x5080000cd680: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fd
0x5080000cd700: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 fa
0x5080000cd780: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 fa
0x5080000cd800: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 fa
0x5080000cd880: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 fa
=>0x5080000cd900: fa fa fa fa fd fd fd fd fd fd fd[fd]fd fd fd fd
0x5080000cd980: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x5080000cda00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x5080000cda80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x5080000cdb00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x5080000cdb80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==1942344==ABORTING
Metadata
Metadata
Assignees
Labels
interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump