Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Use-after-free inbuiltin_delattr_impl andbuiltin_setattr_impl via re-entrant__hash__ #142731

Open
Labels
interpreter-core(Objects, Python, Grammar, and Parser dirs)type-crashA hard crash of the interpreter, possibly with a core dump
@jackfromeast

Description

@jackfromeast

What happened?

delattr(obj, name) andsetattr(obj, name) ends up inPyObject_SetAttr(..., value=NULL), which calls the generic setter that deletes fromobj.__dict__ via_PyDict_SetItem_LockHeld(value=NULL). Ifname is astr subclass with a re-entrant__hash__, hashingname runs user code that swaps out and frees the old__dict__. The deletion then continues using the stale dict pointer in_PyDict_DelItem_KnownHash_LockHeld, leading to a heap-use-after-free.

Proof of Concept:

PoC

classEvil(str):def__hash__(self):old=target.__dict__target.__dict__= {}delolddicts= []foriinrange(100):dicts.append({f"key{i}":f"value{i}"})return0classVictim:passtarget=Victim()delattr(target,Evil("marker"))
importgcclassEvil(str):def__hash__(self):old=target.__dict__target.__dict__= {}deloldgc.collect()return0classVictim:passtarget=Victim()setattr(target,Evil("marker"))

Related Code Snippet

Details
int_PyDict_SetItem_LockHeld(PyDictObject*dict,PyObject*name,PyObject*value){if (value==NULL) {// Bug: Trigger the override __hash__ method that free the dictPy_hash_thash=_PyObject_HashFast(name);if (hash==-1) {dict_unhashable_type(name);return-1;        }// Access the freed dict buffer.return_PyDict_DelItem_KnownHash_LockHeld((PyObject*)dict,name,hash);    }else {returnsetitem_lock_held(dict,name,value);    }}int_PyDict_DelItem_KnownHash_LockHeld(PyObject*op,PyObject*key,Py_hash_thash){Py_ssize_tix;PyDictObject*mp;PyObject*old_value;if (!PyDict_Check(op)) {PyErr_BadInternalCall();return-1;    }ASSERT_DICT_LOCKED(op);assert(key);assert(hash!=-1);mp= (PyDictObject*)op;// Leak the op/mp->me_key pointer backix=_Py_dict_lookup(mp,key,hash,&old_value);if (ix==DKIX_ERROR)return-1;if (ix==DKIX_EMPTY||old_value==NULL) {_PyErr_SetKeyError(key);return-1;    }PyInterpreterState*interp=_PyInterpreterState_GET();_PyDict_NotifyEvent(interp,PyDict_EVENT_DELETED,mp,key,NULL);delitem_common(mp,hash,ix,old_value);return0;}

Affected Versions:

Details
Python VersionStatusExit Code
Python 3.9.24+ (heads/3.9:9c4638d, Oct 17 2025, 11:19:30)ASAN1
Python 3.10.19+ (heads/3.10:0142619, Oct 17 2025, 11:20:05) [GCC 13.3.0]ASAN1
Python 3.11.14+ (heads/3.11:88f3f5b, Oct 17 2025, 11:20:44) [GCC 13.3.0]ASAN1
Python 3.12.12+ (heads/3.12:8cb2092, Oct 17 2025, 11:21:35) [GCC 13.3.0]ASAN1
Python 3.13.9+ (heads/3.13:0760a57, Oct 17 2025, 11:22:25) [GCC 13.3.0]ASAN1
Python 3.14.0+ (heads/3.14:889e918, Oct 17 2025, 11:23:02) [GCC 13.3.0]ASAN1
Python 3.15.0a1+ (heads/main:fbf0843, Oct 17 2025, 11:23:37) [GCC 13.3.0]ASAN1

Sanitizer Output:

Details
===================================================================1553427==ERROR: AddressSanitizer: heap-use-after-free on address 0x5080000a5748 at pc 0x63af6ffd3df9 bp 0x7fff69a92e30 sp 0x7fff69a92e20READ of size 8 at 0x5080000a5748 thread T0    #0 0x63af6ffd3df8 in _Py_TYPE Include/object.h:277    #1 0x63af6ffd3df8 in _PyDict_DelItem_KnownHash_LockHeld Objects/dictobject.c:2829    #2 0x63af6ffd4001 in _PyDict_SetItem_LockHeld Objects/dictobject.c:6914    #3 0x63af6ffd7cc4 in store_instance_attr_dict Objects/dictobject.c:7032    #4 0x63af6ffd7d56 in _PyObject_StoreInstanceAttribute Objects/dictobject.c:7053    #5 0x63af6fffe5e7 in _PyObject_GenericSetAttrWithDict Objects/object.c:1969    #6 0x63af6fffe85e in PyObject_GenericSetAttr Objects/object.c:2031    #7 0x63af6fffac11 in PyObject_SetAttr Objects/object.c:1476    #8 0x63af6fffb35a in PyObject_DelAttr Objects/object.c:1512    #9 0x63af7019c7c6 in builtin_delattr_impl Python/bltinmodule.c:1747    #10 0x63af7019c841 in builtin_delattr Python/clinic/bltinmodule.c.h:716    #11 0x63af6ffed364 in cfunction_vectorcall_FASTCALL Objects/methodobject.c:449    #12 0x63af6ff3ae7f in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169    #13 0x63af6ff3af72 in PyObject_Vectorcall Objects/call.c:327    #14 0x63af701b9056 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620    #15 0x63af701fce54 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121    #16 0x63af701fd148 in _PyEval_Vector Python/ceval.c:2001    #17 0x63af701fd3f8 in PyEval_EvalCode Python/ceval.c:884    #18 0x63af702f4507 in run_eval_code_obj Python/pythonrun.c:1365    #19 0x63af702f4723 in run_mod Python/pythonrun.c:1459    #20 0x63af702f557a in pyrun_file Python/pythonrun.c:1293    #21 0x63af702f8220 in _PyRun_SimpleFileObject Python/pythonrun.c:521    #22 0x63af702f84f6 in _PyRun_AnyFileObject Python/pythonrun.c:81    #23 0x63af7034974d in pymain_run_file_obj Modules/main.c:410    #24 0x63af703499b4 in pymain_run_file Modules/main.c:429    #25 0x63af7034b1b2 in pymain_run_python Modules/main.c:691    #26 0x63af7034b842 in Py_RunMain Modules/main.c:772    #27 0x63af7034ba2e in pymain_main Modules/main.c:802    #28 0x63af7034bdb3 in Py_BytesMain Modules/main.c:826    #29 0x63af6fdcf645 in main Programs/python.c:15    #30 0x73d687c2a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58    #31 0x73d687c2a28a in __libc_start_main_impl ../csu/libc-start.c:360    #32 0x63af6fdcf574 in _start (/home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-latest/targets/cpython/python+0x2dd574) (BuildId: ff3dc40ea460bd4beb2c3a72283cca525b319bf0)0x5080000a5748 is located 40 bytes inside of 88-byte region [0x5080000a5720,0x5080000a5778)freed by thread T0 here:    #0 0x73d6880fc4d8 in free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:52    #1 0x63af7000196d in _PyMem_RawFree Objects/obmalloc.c:91    #2 0x63af70003cd9 in _PyMem_DebugRawFree Objects/obmalloc.c:2955    #3 0x63af70003d1a in _PyMem_DebugFree Objects/obmalloc.c:3100    #4 0x63af7002c06c in PyObject_Free Objects/obmalloc.c:1522    #5 0x63af7026acf7 in PyObject_GC_Del Python/gc.c:2435    #6 0x63af6fffa4cc in free_object Objects/object.c:916    #7 0x63af6fff5e1e in clear_freelist Objects/object.c:902    #8 0x63af6fff71ba in _PyObject_ClearFreeLists Objects/object.c:933    #9 0x63af7026af8d in _PyGC_ClearAllFreeLists Python/gc_gil.c:14    #10 0x63af70268da2 in gc_collect_full Python/gc.c:1735    #11 0x63af7026a045 in _PyGC_Collect Python/gc.c:2096    #12 0x63af7034d0f0 in gc_collect_impl Modules/gcmodule.c:93    #13 0x63af7034d268 in gc_collect Modules/clinic/gcmodule.c.h:143    #14 0x63af701bda49 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:2361    #15 0x63af701fce54 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121    #16 0x63af701fd148 in _PyEval_Vector Python/ceval.c:2001    #17 0x63af6ff3a9b8 in _PyFunction_Vectorcall Objects/call.c:413    #18 0x63af6ff3ae7f in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169    #19 0x63af6ff3b03f in PyObject_CallOneArg Objects/call.c:395    #20 0x63af7004d648 in call_unbound_noarg Objects/typeobject.c:3040    #21 0x63af70068fa0 in maybe_call_special_no_args Objects/typeobject.c:3153    #22 0x63af700695e4 in slot_tp_hash Objects/typeobject.c:10564    #23 0x63af6fff73d6 in PyObject_Hash Objects/object.c:1157    #24 0x63af6ffc4dda in _PyObject_HashFast Include/internal/pycore_object.h:872    #25 0x63af6ffd3fed in _PyDict_SetItem_LockHeld Objects/dictobject.c:6909    #26 0x63af6ffd7cc4 in store_instance_attr_dict Objects/dictobject.c:7032    #27 0x63af6ffd7d56 in _PyObject_StoreInstanceAttribute Objects/dictobject.c:7053    #28 0x63af6fffe5e7 in _PyObject_GenericSetAttrWithDict Objects/object.c:1969    #29 0x63af6fffe85e in PyObject_GenericSetAttr Objects/object.c:2031previously allocated by thread T0 here:    #0 0x73d6880fd9c7 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69    #1 0x63af70002284 in _PyMem_RawMalloc Objects/obmalloc.c:63    #2 0x63af70001655 in _PyMem_DebugRawAlloc Objects/obmalloc.c:2887    #3 0x63af700016bd in _PyMem_DebugRawMalloc Objects/obmalloc.c:2920    #4 0x63af70002f3b in _PyMem_DebugMalloc Objects/obmalloc.c:3085    #5 0x63af7002bf28 in PyObject_Malloc Objects/obmalloc.c:1493    #6 0x63af7026a734 in _PyObject_MallocWithType Include/internal/pycore_object_alloc.h:46    #7 0x63af7026a734 in gc_alloc Python/gc.c:2327    #8 0x63af7026a88a in _PyObject_GC_New Python/gc.c:2347    #9 0x63af6ffc8cad in new_dict Objects/dictobject.c:875    #10 0x63af6ffca396 in PyDict_New Objects/dictobject.c:973    #11 0x63af6ffca3e5 in dict_new_presized Objects/dictobject.c:2203    #12 0x63af6ffd2877 in _PyDict_FromItems Objects/dictobject.c:2244    #13 0x63af701b6e63 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1272    #14 0x63af701fce54 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121    #15 0x63af701fd148 in _PyEval_Vector Python/ceval.c:2001    #16 0x63af6ff3a9b8 in _PyFunction_Vectorcall Objects/call.c:413    #17 0x63af6ff3ae7f in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169    #18 0x63af6ff3cbc0 in object_vacall Objects/call.c:819    #19 0x63af6ff3ce3e in PyObject_CallMethodObjArgs Objects/call.c:886    #20 0x63af70289cc9 in import_find_and_load Python/import.c:3701    #21 0x63af70290c01 in PyImport_ImportModuleLevelObject Python/import.c:3783    #22 0x63af701ac4a3 in _PyEval_ImportName Python/ceval.c:3017    #23 0x63af701d51b0 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:6219    #24 0x63af701fce54 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121    #25 0x63af701fd148 in _PyEval_Vector Python/ceval.c:2001    #26 0x63af701fd3f8 in PyEval_EvalCode Python/ceval.c:884    #27 0x63af7019b94a in builtin_exec_impl Python/bltinmodule.c:1180    #28 0x63af7019bc4c in builtin_exec Python/clinic/bltinmodule.c.h:571    #29 0x63af6ffed123 in cfunction_vectorcall_FASTCALL_KEYWORDS Objects/methodobject.c:465    #30 0x63af6ff3e1d2 in _PyVectorcall_Call Objects/call.c:273SUMMARY: AddressSanitizer: heap-use-after-free Include/object.h:277 in _Py_TYPEShadow bytes around the buggy address:  0x5080000a5480: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 fa  0x5080000a5500: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 fa  0x5080000a5580: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 fa  0x5080000a5600: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 00  0x5080000a5680: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fa=>0x5080000a5700: fa fa fa fa fd fd fd fd fd[fd]fd fd fd fd fd fa  0x5080000a5780: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fa  0x5080000a5800: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fa  0x5080000a5880: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fa  0x5080000a5900: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fa  0x5080000a5980: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 02 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==1553427==ABORTING

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)type-crashA hard crash of the interpreter, possibly with a core dump

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions


      [8]ページ先頭

      ©2009-2026 Movatter.jp