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?
Insave_picklebuffer a userbuffer_callback returns an object whose__bool__ releases thePickleBuffer, freeing the bytearray while the function still holdsview->buf. The pickler then proceeds into_save_bytearray_data, which copies from the stale pointer and triggers a use-after-free.
Proof of Concept:
importioimportpicklebase=bytearray(b'A'*0x1000)pb=pickle.PickleBuffer(base)classEvil:def__bool__(self):globalbasepb.release()base=NonereturnTruedefcallback(pb):returnEvil()pickle.dumps(pb,protocol=5,buffer_callback=callback)
Affected Versions
Details
| Python Version | Status | Exit Code |
|---|---|---|
Python 3.9.24+ (heads/3.9:111bbc15b26, Oct 28 2025, 16:51:20) | ASAN | 1 |
Python 3.10.19+ (heads/3.10:014261980b1, Oct 28 2025, 16:52:08) [Clang 18.1.3 (1ubuntu1)] | ASAN | 1 |
Python 3.11.14+ (heads/3.11:88f3f5b5f11, Oct 28 2025, 16:53:08) [Clang 18.1.3 (1ubuntu1)] | ASAN | 1 |
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
Details
/* Buggy Re-entrant Path */staticPyObject*_pickle_Pickler_dump_impl(PicklerObject*self,PyTypeObject*cls,PyObject*obj){PickleState*st=_Pickle_GetStateByClass(cls);/* ... */if (dump(st,self,obj)<0)returnNULL;/* ... */Py_RETURN_NONE;}staticintsave_picklebuffer(PickleState*st,PicklerObject*self,PyObject*obj){/* ... *//* crashing pointer derived: view->buf */intin_band=1;if (self->buffer_callback!=NULL) {PyObject*ret=PyObject_CallOneArg(self->buffer_callback,obj);/* Reentrant call site */if (ret==NULL) {return-1; }in_band=PyObject_IsTrue(ret);/* Reentrant call site */Py_DECREF(ret);if (in_band==-1) {return-1; } }if (in_band) {/* Write data in-band */if (view->readonly) {return_save_bytes_data(st,self,obj, (constchar*)view->buf,view->len); }else {return_save_bytearray_data(st,self,obj, (constchar*)view->buf,view->len); } }/* ... */}/* Crash site */staticPy_ssize_t_Pickler_Write(PicklerObject*self,constchar*s,Py_ssize_tdata_len){/* ... */memcpy(buffer+self->output_len,s,data_len);/* Crash site *//* ... */returndata_len;}/* Clobbering Path */intPyPickleBuffer_Release(PyObject*obj){PyPickleBufferObject*self= (PyPickleBufferObject*)obj;/* ... */PyBuffer_Release(&self->view);/* state mutate site */return0;}
Sanitizer Output
Details
===================================================================1950369==ERROR: AddressSanitizer: heap-use-after-free on address 0x52100002d110 at pc 0x79df96afb42e bp 0x7ffdcd025960 sp 0x7ffdcd025108READ of size 4096 at 0x52100002d110 thread T0 #0 0x79df96afb42d in memcpy ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc:115 #1 0x79df95b52985 in memcpy /usr/include/x86_64-linux-gnu/bits/string_fortified.h:29 #2 0x79df95b52985 in _Pickler_Write Modules/_pickle.c:1088 #3 0x79df95b54997 in _Pickler_write_bytes Modules/_pickle.c:2381 #4 0x79df95b555db in _save_bytearray_data Modules/_pickle.c:2505 #5 0x79df95b55a30 in save_picklebuffer Modules/_pickle.c:2590 #6 0x79df95b56209 in save Modules/_pickle.c:4435 #7 0x79df95b5d92e in dump Modules/_pickle.c:4611 #8 0x79df95b5dc65 in _pickle_Pickler_dump_impl Modules/_pickle.c:4685 #9 0x79df95b5de40 in _pickle_Pickler_dump Modules/clinic/_pickle.c.h:73 #10 0x58d50b4990b6 in cfunction_vectorcall_FASTCALL_KEYWORDS_METHOD Objects/methodobject.c:481 #11 0x58d50b3e6e7f in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169 #12 0x58d50b3e6f72 in PyObject_Vectorcall Objects/call.c:327 #13 0x58d50b665056 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620 #14 0x58d50b6a8e54 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121 #15 0x58d50b6a9148 in _PyEval_Vector Python/ceval.c:2001 #16 0x58d50b6a93f8 in PyEval_EvalCode Python/ceval.c:884 #17 0x58d50b7a0507 in run_eval_code_obj Python/pythonrun.c:1365 #18 0x58d50b7a0723 in run_mod Python/pythonrun.c:1459 #19 0x58d50b7a157a in pyrun_file Python/pythonrun.c:1293 #20 0x58d50b7a4220 in _PyRun_SimpleFileObject Python/pythonrun.c:521 #21 0x58d50b7a44f6 in _PyRun_AnyFileObject Python/pythonrun.c:81 #22 0x58d50b7f574d in pymain_run_file_obj Modules/main.c:410 #23 0x58d50b7f59b4 in pymain_run_file Modules/main.c:429 #24 0x58d50b7f71b2 in pymain_run_python Modules/main.c:691 #25 0x58d50b7f7842 in Py_RunMain Modules/main.c:772 #26 0x58d50b7f7a2e in pymain_main Modules/main.c:802 #27 0x58d50b7f7db3 in Py_BytesMain Modules/main.c:826 #28 0x58d50b27b645 in main Programs/python.c:15 #29 0x79df9662a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 #30 0x79df9662a28a in __libc_start_main_impl ../csu/libc-start.c:360 #31 0x58d50b27b574 in _start (/home/jackfromeast/Desktop/entropy/targets/grammar-afl++-latest/targets/cpython/python+0x2dd574) (BuildId: 202d5dbb945f6d5f5a66ad50e2688d56affd6ecb)0x52100002d110 is located 16 bytes inside of 4121-byte region [0x52100002d100,0x52100002e119)freed by thread T0 here: #0 0x79df96afc4d8 in free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:52 #1 0x58d50b4ad96d in _PyMem_RawFree Objects/obmalloc.c:91 #2 0x58d50b4afcd9 in _PyMem_DebugRawFree Objects/obmalloc.c:2955 #3 0x58d50b4afd1a in _PyMem_DebugFree Objects/obmalloc.c:3100 #4 0x58d50b4d7348 in PyMem_Free Objects/obmalloc.c:1070 #5 0x58d50b3c4eef in bytearray_dealloc Objects/bytearrayobject.c:1173 #6 0x58d50b4a4481 in _Py_Dealloc Objects/object.c:3200 #7 0x58d50b46f874 in Py_DECREF Include/refcount.h:401 #8 0x58d50b46f893 in Py_XDECREF Include/refcount.h:511 #9 0x58d50b47e2ff in insertdict Objects/dictobject.c:1927 #10 0x58d50b47e67e in setitem_take2_lock_held Objects/dictobject.c:2675 #11 0x58d50b47ee45 in _PyDict_SetItem_Take2 Objects/dictobject.c:2683 #12 0x58d50b47eec1 in PyDict_SetItem Objects/dictobject.c:2703 #13 0x58d50b6a1446 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:11090 #14 0x58d50b6a8e54 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121 #15 0x58d50b6a9148 in _PyEval_Vector Python/ceval.c:2001 #16 0x58d50b3e69b8 in _PyFunction_Vectorcall Objects/call.c:413 #17 0x58d50b3e6e7f in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169 #18 0x58d50b3e703f in PyObject_CallOneArg Objects/call.c:395 #19 0x58d50b4f9648 in call_unbound_noarg Objects/typeobject.c:3040 #20 0x58d50b514fa0 in maybe_call_special_no_args Objects/typeobject.c:3153 #21 0x58d50b5152c2 in slot_nb_bool Objects/typeobject.c:10464 #22 0x58d50b4a35b0 in PyObject_IsTrue Objects/object.c:2060 #23 0x79df95b55846 in save_picklebuffer Modules/_pickle.c:2577 #24 0x79df95b56209 in save Modules/_pickle.c:4435 #25 0x79df95b5d92e in dump Modules/_pickle.c:4611 #26 0x79df95b5dc65 in _pickle_Pickler_dump_impl Modules/_pickle.c:4685 #27 0x79df95b5de40 in _pickle_Pickler_dump Modules/clinic/_pickle.c.h:73 #28 0x58d50b4990b6 in cfunction_vectorcall_FASTCALL_KEYWORDS_METHOD Objects/methodobject.c:481 #29 0x58d50b3e6e7f in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169previously allocated by thread T0 here: #0 0x79df96afd9c7 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69 #1 0x58d50b4ae284 in _PyMem_RawMalloc Objects/obmalloc.c:63 #2 0x58d50b4ad655 in _PyMem_DebugRawAlloc Objects/obmalloc.c:2887 #3 0x58d50b4b064f in _PyMem_DebugRawRealloc Objects/obmalloc.c:2963 #4 0x58d50b4b0823 in _PyMem_DebugRealloc Objects/obmalloc.c:3108 #5 0x58d50b4d72e7 in PyMem_Realloc Objects/obmalloc.c:1063 #6 0x58d50b3bfc04 in bytearray_resize_lock_held Objects/bytearrayobject.c:258 #7 0x58d50b3cd24c in PyByteArray_Resize Objects/bytearrayobject.c:278 #8 0x58d50b3cd850 in bytearray___init___impl Objects/bytearrayobject.c:978 #9 0x58d50b3ce2c9 in bytearray___init__ Objects/clinic/bytearrayobject.c.h:102 #10 0x58d50b50d3c0 in type_call Objects/typeobject.c:2460 #11 0x58d50b3e6c71 in _PyObject_MakeTpCall Objects/call.c:242 #12 0x58d50b3e6f19 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:167 #13 0x58d50b3e6f72 in PyObject_Vectorcall Objects/call.c:327 #14 0x58d50b665056 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620 #15 0x58d50b6a8e54 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121 #16 0x58d50b6a9148 in _PyEval_Vector Python/ceval.c:2001 #17 0x58d50b6a93f8 in PyEval_EvalCode Python/ceval.c:884 #18 0x58d50b7a0507 in run_eval_code_obj Python/pythonrun.c:1365 #19 0x58d50b7a0723 in run_mod Python/pythonrun.c:1459 #20 0x58d50b7a157a in pyrun_file Python/pythonrun.c:1293 #21 0x58d50b7a4220 in _PyRun_SimpleFileObject Python/pythonrun.c:521 #22 0x58d50b7a44f6 in _PyRun_AnyFileObject Python/pythonrun.c:81 #23 0x58d50b7f574d in pymain_run_file_obj Modules/main.c:410 #24 0x58d50b7f59b4 in pymain_run_file Modules/main.c:429 #25 0x58d50b7f71b2 in pymain_run_python Modules/main.c:691 #26 0x58d50b7f7842 in Py_RunMain Modules/main.c:772 #27 0x58d50b7f7a2e in pymain_main Modules/main.c:802 #28 0x58d50b7f7db3 in Py_BytesMain Modules/main.c:826 #29 0x58d50b27b645 in main Programs/python.c:15SUMMARY: AddressSanitizer: heap-use-after-free ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc:115 in memcpyShadow bytes around the buggy address: 0x52100002ce80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x52100002cf00: 00 00 00 00 00 fa fa fa fa fa fa fa fa fa fa fa 0x52100002cf80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x52100002d000: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x52100002d080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa=>0x52100002d100: fd fd[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd 0x52100002d180: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x52100002d200: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x52100002d280: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x52100002d300: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x52100002d380: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fdShadow 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==1950369==ABORTINGLinked PRs
Metadata
Metadata
Assignees
Labels
Projects
Status
Done