-
-
Notifications
You must be signed in to change notification settings - Fork 33.8k
Open
Description
What happened?
_PyEval_LoadName consults frame.f_locals through PyMapping_GetOptionalItem, but it does so with the locals proxy still live; a crafted key can run frame.clear() inside its __eq__, freeing the locals dict while the lookup proceeds, so the name resolution continues to read the already-freed keys table and hits a use-after-free.
Proof of Concept:
def get_frame():
try: raise RuntimeError
except RuntimeError as e: return e.__traceback__.tb_frame
frame = get_frame()
proxy = frame.f_locals
class Fuse(str):
armed = False
__hash__ = str.__hash__
def __eq__(self, other):
if not Fuse.armed and other == "boom":
Fuse.armed = True
Fuse.frame.clear()
return True
Fuse.frame = frame
proxy[Fuse("boom")] = 0
exec("boom", {}, proxy)Affected Versions
Details
| 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)] |
OK | 0 |
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
Details
PyObject *
_PyEval_LoadName(PyThreadState *tstate, _PyInterpreterFrame *frame, PyObject *name)
{
PyObject *value;
if (frame->f_locals == NULL) {
_PyErr_SetString(tstate, PyExc_SystemError,
"no locals found");
return NULL;
}
/* Trigger the __eq__ which clear the frame->f_locals */
if (PyMapping_GetOptionalItem(frame->f_locals, name, &value) < 0) {
return NULL;
}
if (value != NULL) {
return value;
}
if (PyDict_GetItemRef(frame->f_globals, name, &value) < 0) {
return NULL;
}
if (value != NULL) {
return value;
}
if (PyMapping_GetOptionalItem(frame->f_builtins, name, &value) < 0) {
return NULL;
}
if (value == NULL) {
_PyEval_FormatExcCheckArg(
tstate, PyExc_NameError,
NAME_ERROR_MSG, name);
}
return value;
}Sanitizer Output
Details
=================================================================
==2195217==ERROR: AddressSanitizer: heap-use-after-free on address 0x50e00000deb0 at pc 0x59ec04e2e8cf bp 0x7ffecc9b6f20 sp 0x7ffecc9b6f10
READ of size 8 at 0x50e00000deb0 thread T0
#0 0x59ec04e2e8ce in compare_generic Objects/dictobject.c:1115
#1 0x59ec04e2e8ce in do_lookup Objects/dictobject.c:1010
#2 0x59ec04e2e8ce in dictkeys_generic_lookup Objects/dictobject.c:1129
#3 0x59ec04e2e8ce in _Py_dict_lookup Objects/dictobject.c:1295
#4 0x59ec04e3865e in _PyDict_GetItemRef_KnownHash Objects/dictobject.c:2421
#5 0x59ec04e3865e in PyDict_GetItemRef Objects/dictobject.c:2456
#6 0x59ec04dd2260 in framelocalsproxy_getitem Objects/frameobject.c:206
#7 0x59ec04d0eeba in PyObject_GetItem Objects/abstract.c:163
#8 0x59ec04d0eeba in PyMapping_GetOptionalItem Objects/abstract.c:215
#9 0x59ec050db89b in _PyEval_LoadName Python/ceval.c:3536
#10 0x59ec04c04c5e in _PyEval_EvalFrameDefault Python/generated_cases.c.h:9348
#11 0x59ec050dcad6 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121
#12 0x59ec050dcad6 in _PyEval_Vector Python/ceval.c:2001
#13 0x59ec050dcad6 in PyEval_EvalCode Python/ceval.c:884
#14 0x59ec0522216e in run_eval_code_obj Python/pythonrun.c:1365
#15 0x59ec0522216e in run_mod Python/pythonrun.c:1459
#16 0x59ec05228670 in _PyRun_StringFlagsWithName Python/pythonrun.c:1259
#17 0x59ec05228670 in PyRun_StringFlags Python/pythonrun.c:1271
#18 0x59ec050c6b09 in builtin_exec_impl Python/bltinmodule.c:1209
#19 0x59ec050c6b09 in builtin_exec Python/clinic/bltinmodule.c.h:571
#20 0x59ec04d5e3e7 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169
#21 0x59ec04d5e3e7 in PyObject_Vectorcall Objects/call.c:327
#22 0x59ec04c125a2 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620
#23 0x59ec050dcad6 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121
#24 0x59ec050dcad6 in _PyEval_Vector Python/ceval.c:2001
#25 0x59ec050dcad6 in PyEval_EvalCode Python/ceval.c:884
#26 0x59ec0522216e in run_eval_code_obj Python/pythonrun.c:1365
#27 0x59ec0522216e in run_mod Python/pythonrun.c:1459
#28 0x59ec05226e17 in pyrun_file Python/pythonrun.c:1293
#29 0x59ec05226e17 in _PyRun_SimpleFileObject Python/pythonrun.c:521
#30 0x59ec0522793c in _PyRun_AnyFileObject Python/pythonrun.c:81
#31 0x59ec0529ae3c in pymain_run_file_obj Modules/main.c:410
#32 0x59ec0529ae3c in pymain_run_file Modules/main.c:429
#33 0x59ec0529ae3c in pymain_run_python Modules/main.c:691
#34 0x59ec0529c71e in Py_RunMain Modules/main.c:772
#35 0x59ec0529c71e in pymain_main Modules/main.c:802
#36 0x59ec0529c71e in Py_BytesMain Modules/main.c:826
#37 0x7d3ef602a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#38 0x7d3ef602a28a in __libc_start_main_impl ../csu/libc-start.c:360
#39 0x59ec04c36634 in _start (/home/jackfromeast/Desktop/entropy/targets/grammar-afl++-latest/targets/cpython/python+0x206634) (BuildId: 4d105290d0ad566a4d6f4f7b2f05fbc9e317b533)
0x50e00000deb0 is located 48 bytes inside of 160-byte region [0x50e00000de80,0x50e00000df20)
freed by thread T0 here:
#0 0x7d3ef64fc4d8 in free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:52
#1 0x59ec04e2b3df in free_keys_object Objects/dictobject.c:823
#2 0x59ec04e2b3df in dictkeys_decref Objects/dictobject.c:473
#3 0x59ec04e2b3df in dictkeys_decref Objects/dictobject.c:446
#4 0x59ec04e2b3df in dict_dealloc Objects/dictobject.c:3354
#5 0x59ec04e2b3df in dict_dealloc Objects/dictobject.c:3328
#6 0x59ec04e7b1d8 in _Py_Dealloc Objects/object.c:3200
#7 0x59ec04dcc7a4 in Py_DECREF Include/refcount.h:418
#8 0x59ec04dcc7a4 in frame_tp_clear Objects/frameobject.c:1985
#9 0x59ec04dcc8aa in frame_clear_impl Objects/frameobject.c:2028
#10 0x59ec04dcc8aa in frame_clear Objects/clinic/frameobject.c.h:407
#11 0x59ec04d5e3e7 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169
#12 0x59ec04d5e3e7 in PyObject_Vectorcall Objects/call.c:327
#13 0x59ec04c125a2 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620
#14 0x59ec050dd2a5 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121
#15 0x59ec050dd2a5 in _PyEval_Vector Python/ceval.c:2001
#16 0x59ec04f105e2 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169
#17 0x59ec04f105e2 in vectorcall_unbound Objects/typeobject.c:3033
#18 0x59ec04f105e2 in maybe_call_special_one_arg Objects/typeobject.c:3175
#19 0x59ec04f105e2 in _PyObject_MaybeCallSpecialOneArg Objects/typeobject.c:3190
#20 0x59ec04f105e2 in slot_tp_richcompare Objects/typeobject.c:10729
#21 0x59ec04e822af in do_richcompare Objects/object.c:1059
#22 0x59ec04e822af in PyObject_RichCompare Objects/object.c:1108
#23 0x59ec04e822af in PyObject_RichCompareBool Objects/object.c:1130
#24 0x59ec04e2e373 in compare_generic Objects/dictobject.c:1110
#25 0x59ec04e2e373 in do_lookup Objects/dictobject.c:1010
#26 0x59ec04e2e373 in dictkeys_generic_lookup Objects/dictobject.c:1129
#27 0x59ec04e2e373 in _Py_dict_lookup Objects/dictobject.c:1295
#28 0x59ec04e3865e in _PyDict_GetItemRef_KnownHash Objects/dictobject.c:2421
#29 0x59ec04e3865e in PyDict_GetItemRef Objects/dictobject.c:2456
#30 0x59ec04dd2260 in framelocalsproxy_getitem Objects/frameobject.c:206
#31 0x59ec04d0eeba in PyObject_GetItem Objects/abstract.c:163
#32 0x59ec04d0eeba in PyMapping_GetOptionalItem Objects/abstract.c:215
#33 0x59ec050db89b in _PyEval_LoadName Python/ceval.c:3536
#34 0x59ec04c04c5e in _PyEval_EvalFrameDefault Python/generated_cases.c.h:9348
#35 0x59ec050dcad6 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121
#36 0x59ec050dcad6 in _PyEval_Vector Python/ceval.c:2001
#37 0x59ec050dcad6 in PyEval_EvalCode Python/ceval.c:884
#38 0x59ec0522216e in run_eval_code_obj Python/pythonrun.c:1365
#39 0x59ec0522216e in run_mod Python/pythonrun.c:1459
#40 0x59ec05228670 in _PyRun_StringFlagsWithName Python/pythonrun.c:1259
#41 0x59ec05228670 in PyRun_StringFlags Python/pythonrun.c:1271
#42 0x59ec050c6b09 in builtin_exec_impl Python/bltinmodule.c:1209
#43 0x59ec050c6b09 in builtin_exec Python/clinic/bltinmodule.c.h:571
#44 0x59ec04d5e3e7 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169
#45 0x59ec04d5e3e7 in PyObject_Vectorcall Objects/call.c:327
#46 0x59ec04c125a2 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620
#47 0x59ec050dcad6 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121
#48 0x59ec050dcad6 in _PyEval_Vector Python/ceval.c:2001
#49 0x59ec050dcad6 in PyEval_EvalCode Python/ceval.c:884
#50 0x59ec0522216e in run_eval_code_obj Python/pythonrun.c:1365
#51 0x59ec0522216e in run_mod Python/pythonrun.c:1459
#52 0x59ec05226e17 in pyrun_file Python/pythonrun.c:1293
#53 0x59ec05226e17 in _PyRun_SimpleFileObject Python/pythonrun.c:521
#54 0x59ec0522793c in _PyRun_AnyFileObject Python/pythonrun.c:81
#55 0x59ec0529ae3c in pymain_run_file_obj Modules/main.c:410
#56 0x59ec0529ae3c in pymain_run_file Modules/main.c:429
#57 0x59ec0529ae3c in pymain_run_python Modules/main.c:691
#58 0x59ec0529c71e in Py_RunMain Modules/main.c:772
#59 0x59ec0529c71e in pymain_main Modules/main.c:802
#60 0x59ec0529c71e in Py_BytesMain Modules/main.c:826
#61 0x7d3ef602a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#62 0x7d3ef602a28a in __libc_start_main_impl ../csu/libc-start.c:360
previously allocated by thread T0 here:
#0 0x7d3ef64fd9c7 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
#1 0x59ec04e27f14 in new_keys_object Objects/dictobject.c:784
#2 0x59ec04e27f14 in insert_to_emptydict Objects/dictobject.c:1948
#3 0x59ec04c01cbc in _PyEval_EvalFrameDefault Python/generated_cases.c.h:11245
#4 0x59ec050dcad6 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121
#5 0x59ec050dcad6 in _PyEval_Vector Python/ceval.c:2001
#6 0x59ec050dcad6 in PyEval_EvalCode Python/ceval.c:884
#7 0x59ec0522216e in run_eval_code_obj Python/pythonrun.c:1365
#8 0x59ec0522216e in run_mod Python/pythonrun.c:1459
#9 0x59ec05226e17 in pyrun_file Python/pythonrun.c:1293
#10 0x59ec05226e17 in _PyRun_SimpleFileObject Python/pythonrun.c:521
#11 0x59ec0522793c in _PyRun_AnyFileObject Python/pythonrun.c:81
#12 0x59ec0529ae3c in pymain_run_file_obj Modules/main.c:410
#13 0x59ec0529ae3c in pymain_run_file Modules/main.c:429
#14 0x59ec0529ae3c in pymain_run_python Modules/main.c:691
#15 0x59ec0529c71e in Py_RunMain Modules/main.c:772
#16 0x59ec0529c71e in pymain_main Modules/main.c:802
#17 0x59ec0529c71e in Py_BytesMain Modules/main.c:826
#18 0x7d3ef602a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#19 0x7d3ef602a28a in __libc_start_main_impl ../csu/libc-start.c:360
#20 0x59ec04c36634 in _start (/home/jackfromeast/Desktop/entropy/targets/grammar-afl++-latest/targets/cpython/python+0x206634) (BuildId: 4d105290d0ad566a4d6f4f7b2f05fbc9e317b533)
SUMMARY: AddressSanitizer: heap-use-after-free Objects/dictobject.c:1115 in compare_generic
Shadow bytes around the buggy address:
0x50e00000dc00: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x50e00000dc80: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
0x50e00000dd00: fd fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa
0x50e00000dd80: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 00
0x50e00000de00: 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa
=>0x50e00000de80: fd fd fd fd fd fd[fd]fd fd fd fd fd fd fd fd fd
0x50e00000df00: fd fd fd fd fa fa fa fa fa fa fa fa fd fd fd fd
0x50e00000df80: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x50e00000e000: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x50e00000e080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x50e00000e100: 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
==2195217==ABORTING
Metadata
Metadata
Assignees
Labels
No labels