-
-
Notifications
You must be signed in to change notification settings - Fork 34.2k
Closed
Labels
3.13bugs and security fixesbugs and security fixes3.14bugs and security fixesbugs and security fixes3.15new features, bugs and security fixesnew features, bugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or errortype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
Description
What happened?
A custom __length_hint__ can report zero to bytearray_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 like float(bytearray()) read past the buffer.
Proof of Concept:
class Evil:
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):
return self
def __next__(self):
if self.data:
return self.data.pop(0)
raise StopIteration
def __length_hint__(self):
return 0
victim = bytearray()
victim.extend(Evil())
float(bytearray())Affected Versions:
Details
| 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:
Details
static PyObject *
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);
return NULL;
}
// Bug: Since buf_size is 0, the shared _PyByteArray_empty_string is returned
bytearray_obj = PyByteArray_FromStringAndSize(NULL, buf_size);
if (bytearray_obj == NULL) {
Py_DECREF(it);
return NULL;
}
// Now, buf points to _PyByteArray_empty_string
buf = 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);
return NULL;
}
// Write to the _PyByteArray_empty_string!
buf[len++] = value;
Py_DECREF(item);
/* ... */
}Sanitizer Output:
Details
=================================================================
==1342965==ERROR: AddressSanitizer: global-buffer-overflow on address 0x584de306fc81 at pc 0x584de1b121da bp 0x7ffcf155a660 sp 0x7ffcf1559e28
READ 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 8
0x584de306fc81 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 1
SUMMARY: AddressSanitizer: global-buffer-overflow (/home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/python+0x1e21d9) (BuildId: 5de9d2fcbcd44bfc1b0fe256566d49ad35ca1d56) in strchr
Shadow 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 00
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
==1342965==ABORTING
Linked PRs
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
3.13bugs and security fixesbugs and security fixes3.14bugs and security fixesbugs and security fixes3.15new features, bugs and security fixesnew features, bugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or errortype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump