Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork34k
Closed
Description
What happened?
types.GenericAlias.__repr__ walks its type arguments by borrowed pointers. A crafted argument object implements__getattr__ to clear the shared list when_Py_typing_type_repr probes__origin__/__args__, dropping the last reference to the same object mid-repr. The second attribute probe then dereferences the freed object insidePyObject_HasAttrWithError, producing a heap use-after-free duringrepr().
Proof of Concept:
importtypesclassZap:__slots__= ("container",)def__init__(self,container):self.container=containerdef__getattr__(self,name):ifname=="__origin__":self.container.clear()returnNoneifname=="__args__":return ()raiseAttributeErrorparams= []params.append(Zap(params))alias=types.GenericAlias(list, (params,))repr(alias)
Vulnerable Code Snippet:
Click to expand
/* Buggy Re-entrant Path */staticintga_repr_items_list(PyUnicodeWriter*writer,PyObject*p){Py_ssize_tlen=PyList_GET_SIZE(p); ...PyObject*item=PyList_GET_ITEM(p,i);/* crashing pointer derived */if (_Py_typing_type_repr(writer,item)<0) {return-1; }}int_Py_typing_type_repr(PyUnicodeWriter*writer,PyObject*p){ ...if ((rc=PyObject_HasAttrWithError(p,&_Py_ID(__origin__)))>0&&/* Reentrant call site */ (rc=PyObject_HasAttrWithError(p,&_Py_ID(__args__)))>0) {/* user __getattr__ can clear the list and free 'p' */ gotouse_repr; } ...}intPyObject_GetOptionalAttr(PyObject*v,PyObject*name,PyObject**result){PyTypeObject*tp=Py_TYPE(v);/* Crash site */ ...}/* Clobbering Path */staticvoidlist_clear_impl(PyListObject*a,boolis_resize){PyObject**items=a->ob_item;/* ... */Py_ssize_ti=Py_SIZE(a);Py_SET_SIZE(a,0);FT_ATOMIC_STORE_PTR_RELEASE(a->ob_item,NULL);a->allocated=0;while (--i >=0) {Py_XDECREF(items[i]);/* state mutate site */ }free_list_items(items,use_qsbr);}
Sanitizer Output:
Click to expand
===================================================================440644==ERROR: AddressSanitizer: heap-use-after-free on address 0x504000054aa8 at pc 0x58f73fa51496 bp 0x7fff368835e0 sp 0x7fff368835d0READ of size 8 at 0x504000054aa8 thread T0 #0 0x58f73fa51495 in _Py_TYPE Include/object.h:277 #1 0x58f73fa51495 in PyObject_GetOptionalAttr Objects/object.c:1337 #2 0x58f73fa51495 in PyObject_HasAttrWithError Objects/object.c:1431 #3 0x58f73fb1d83e in _Py_typing_type_repr Objects/typevarobject.c:280 #4 0x58f73f97890b in ga_repr_items_list Objects/genericaliasobject.c:72 #5 0x58f73f97890b in ga_repr Objects/genericaliasobject.c:118 #6 0x58f73fa4d04e in PyObject_Repr Objects/object.c:779 #7 0x58f73f92f3e7 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169 #8 0x58f73f92f3e7 in PyObject_Vectorcall Objects/call.c:327 #9 0x58f73f7e35a2 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620 #10 0x58f73fcadad6 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121 #11 0x58f73fcadad6 in _PyEval_Vector Python/ceval.c:2001 #12 0x58f73fcadad6 in PyEval_EvalCode Python/ceval.c:884 #13 0x58f73fdf316e in run_eval_code_obj Python/pythonrun.c:1365 #14 0x58f73fdf316e in run_mod Python/pythonrun.c:1459 #15 0x58f73fdf7e17 in pyrun_file Python/pythonrun.c:1293 #16 0x58f73fdf7e17 in _PyRun_SimpleFileObject Python/pythonrun.c:521 #17 0x58f73fdf893c in _PyRun_AnyFileObject Python/pythonrun.c:81 #18 0x58f73fe6be3c in pymain_run_file_obj Modules/main.c:410 #19 0x58f73fe6be3c in pymain_run_file Modules/main.c:429 #20 0x58f73fe6be3c in pymain_run_python Modules/main.c:691 #21 0x58f73fe6d71e in Py_RunMain Modules/main.c:772 #22 0x58f73fe6d71e in pymain_main Modules/main.c:802 #23 0x58f73fe6d71e in Py_BytesMain Modules/main.c:826 #24 0x7adc66e2a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 #25 0x7adc66e2a28a in __libc_start_main_impl ../csu/libc-start.c:360 #26 0x58f73f807634 in _start (/home/jackfromeast/Desktop/entropy/targets/grammar-afl++-latest/targets/cpython/python+0x206634) (BuildId: 4d105290d0ad566a4d6f4f7b2f05fbc9e317b533)0x504000054aa8 is located 24 bytes inside of 40-byte region [0x504000054a90,0x504000054ab8)freed by thread T0 here: #0 0x7adc672fc4d8 in free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:52 #1 0x58f73fac08f3 in subtype_dealloc Objects/typeobject.c:2852 #2 0x58f73fa4c1d8 in _Py_Dealloc Objects/object.c:3200 #3 0x58f73fd37a49 in Py_DECREF_MORTAL Include/internal/pycore_object.h:482 #4 0x58f73fd37a49 in PyStackRef_XCLOSE Include/internal/pycore_stackref.h:736 #5 0x58f73fd37a49 in _PyFrame_ClearLocals Python/frame.c:101 #6 0x58f73fd37a49 in _PyFrame_ClearExceptCode Python/frame.c:126 #7 0x58f73fca3052 in clear_thread_frame Python/ceval.c:1826 #8 0x58f73fca3052 in _PyEval_FrameClearAndPop Python/ceval.c:1850 #9 0x58f73f7e7f4c in _PyEval_EvalFrameDefault Python/generated_cases.c.h:10403 #10 0x58f73fcae2a5 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121 #11 0x58f73fcae2a5 in _PyEval_Vector Python/ceval.c:2001 #12 0x58f73f92f3e7 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169 #13 0x58f73f92f3e7 in PyObject_Vectorcall Objects/call.c:327 #14 0x58f73faef275 in call_attribute Objects/typeobject.c:10627 #15 0x58f73faef275 in call_attribute Objects/typeobject.c:10621 #16 0x58f73faef275 in _Py_slot_tp_getattr_hook Objects/typeobject.c:10688 #17 0x58f73fa51218 in PyObject_GetOptionalAttr Objects/object.c:1377 #18 0x58f73fa51218 in PyObject_HasAttrWithError Objects/object.c:1431 #19 0x58f73fb1d6f6 in _Py_typing_type_repr Objects/typevarobject.c:279 #20 0x58f73f97890b in ga_repr_items_list Objects/genericaliasobject.c:72 #21 0x58f73f97890b in ga_repr Objects/genericaliasobject.c:118 #22 0x58f73fa4d04e in PyObject_Repr Objects/object.c:779 #23 0x58f73f92f3e7 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169 #24 0x58f73f92f3e7 in PyObject_Vectorcall Objects/call.c:327 #25 0x58f73f7e35a2 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620 #26 0x58f73fcadad6 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121 #27 0x58f73fcadad6 in _PyEval_Vector Python/ceval.c:2001 #28 0x58f73fcadad6 in PyEval_EvalCode Python/ceval.c:884 #29 0x58f73fdf316e in run_eval_code_obj Python/pythonrun.c:1365 #30 0x58f73fdf316e in run_mod Python/pythonrun.c:1459 #31 0x58f73fdf7e17 in pyrun_file Python/pythonrun.c:1293 #32 0x58f73fdf7e17 in _PyRun_SimpleFileObject Python/pythonrun.c:521 #33 0x58f73fdf893c in _PyRun_AnyFileObject Python/pythonrun.c:81 #34 0x58f73fe6be3c in pymain_run_file_obj Modules/main.c:410 #35 0x58f73fe6be3c in pymain_run_file Modules/main.c:429 #36 0x58f73fe6be3c in pymain_run_python Modules/main.c:691 #37 0x58f73fe6d71e in Py_RunMain Modules/main.c:772 #38 0x58f73fe6d71e in pymain_main Modules/main.c:802 #39 0x58f73fe6d71e in Py_BytesMain Modules/main.c:826 #40 0x7adc66e2a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 #41 0x7adc66e2a28a in __libc_start_main_impl ../csu/libc-start.c:360 #42 0x58f73f807634 in _start (/home/jackfromeast/Desktop/entropy/targets/grammar-afl++-latest/targets/cpython/python+0x206634) (BuildId: 4d105290d0ad566a4d6f4f7b2f05fbc9e317b533)previously allocated by thread T0 here: #0 0x7adc672fd9c7 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69 #1 0x58f73fad488e in _PyObject_MallocWithType Include/internal/pycore_object_alloc.h:46 #2 0x58f73fad488e in _PyType_AllocNoTrack Objects/typeobject.c:2504 #3 0x58f73fad4af4 in PyType_GenericAlloc Objects/typeobject.c:2535 #4 0x58f73facc118 in type_call Objects/typeobject.c:2448 #5 0x58f73f92d9cd in _PyObject_MakeTpCall Objects/call.c:242 #6 0x58f73f7e35a2 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620 #7 0x58f73fcadad6 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121 #8 0x58f73fcadad6 in _PyEval_Vector Python/ceval.c:2001 #9 0x58f73fcadad6 in PyEval_EvalCode Python/ceval.c:884 #10 0x58f73fdf316e in run_eval_code_obj Python/pythonrun.c:1365 #11 0x58f73fdf316e in run_mod Python/pythonrun.c:1459 #12 0x58f73fdf7e17 in pyrun_file Python/pythonrun.c:1293 #13 0x58f73fdf7e17 in _PyRun_SimpleFileObject Python/pythonrun.c:521 #14 0x58f73fdf893c in _PyRun_AnyFileObject Python/pythonrun.c:81 #15 0x58f73fe6be3c in pymain_run_file_obj Modules/main.c:410 #16 0x58f73fe6be3c in pymain_run_file Modules/main.c:429 #17 0x58f73fe6be3c in pymain_run_python Modules/main.c:691 #18 0x58f73fe6d71e in Py_RunMain Modules/main.c:772 #19 0x58f73fe6d71e in pymain_main Modules/main.c:802 #20 0x58f73fe6d71e in Py_BytesMain Modules/main.c:826 #21 0x7adc66e2a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 #22 0x7adc66e2a28a in __libc_start_main_impl ../csu/libc-start.c:360 #23 0x58f73f807634 in _start (/home/jackfromeast/Desktop/entropy/targets/grammar-afl++-latest/targets/cpython/python+0x206634) (BuildId: 4d105290d0ad566a4d6f4f7b2f05fbc9e317b533)SUMMARY: AddressSanitizer: heap-use-after-free Include/object.h:277 in _Py_TYPEShadow bytes around the buggy address: 0x504000054800: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fd 0x504000054880: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fd 0x504000054900: fa fa 00 00 00 00 00 05 fa fa fd fd fd fd fd fa 0x504000054980: fa fa 00 00 00 00 00 05 fa fa fd fd fd fd fd fa 0x504000054a00: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fa=>0x504000054a80: fa fa fd fd fd[fd]fd fa fa fa fd fd fd fd fd fd 0x504000054b00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x504000054b80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x504000054c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x504000054c80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x504000054d00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa faShadow 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==440644==ABORTINGCPython versions tested on:
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)] | 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 |
Operating systems tested on:
Linux
Output from running 'python -VV' on the command line:
Python 3.15.0a1+ (heads/main:f5394c257ce, Oct 28 2025, 19:29:54) [GCC 13.3.0]