-
-
Notifications
You must be signed in to change notification settings - Fork 33.8k
Closed as duplicate of#143200
Closed as duplicate of#143200
Copy link
Description
What happened?
A crafted iterable for root[:] = Evil() clears the element during PySequence_Fast, so element_ass_subscr frees self->extra and then immediately iterates that null child table in the recycle loop, dereferencing NULL while populating PyList_SET_ITEM.
Proof of Concept:
import xml.etree.ElementTree as ET
root = ET.Element('root')
root.extend([ET.Element('c0'), ET.Element('c1')])
class Evil:
def __iter__(self):
yield from self._gen()
def _gen(self):
root.clear()
yield ET.Element('new')
root[:] = Evil()Affected Versions
| Python Version | Status | Exit Code |
|---|---|---|
Python 3.9.24+ (heads/3.9:111bbc15b26, Oct 27 2025, 21:34:13) |
OK | 0 |
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
static int
element_ass_subscr(PyObject *op, PyObject *item, PyObject *value)
{
/* ... */
/* A new slice is actually being assigned */
// Bug: Invoke the __iter__ methods which clear the element tree
seq = PySequence_Fast(value, "assignment expects an iterable");
if (!seq) {
return -1;
}
newlen = PySequence_Fast_GET_SIZE(seq);
if (step != 1 && newlen != slicelen)
{
Py_DECREF(seq);
PyErr_Format(PyExc_ValueError,
"attempt to assign sequence of size %zd "
"to extended slice of size %zd",
newlen, slicelen
);
return -1;
}
/* Resize before creating the recycle bin, to prevent refleaks. */
if (newlen > slicelen) {
if (element_resize(self, newlen - slicelen) < 0) {
Py_DECREF(seq);
return -1;
}
}
PyTypeObject *tp = Py_TYPE(self);
elementtreestate *st = get_elementtree_state_by_type(tp);
for (i = 0; i < newlen; i++) {
PyObject *element = PySequence_Fast_GET_ITEM(seq, i);
if (!Element_Check(st, element)) {
raise_type_error(element);
Py_DECREF(seq);
return -1;
}
}
if (slicelen > 0) {
/* to avoid recursive calls to this method (via decref), move
old items to the recycle bin here, and get rid of them when
we're done modifying the element */
recycle = PyList_New(slicelen);
if (!recycle) {
Py_DECREF(seq);
return -1;
}
for (cur = start, i = 0; i < slicelen;
cur += step, i++)
// Crash: self->extra is null ptr right now
PyList_SET_ITEM(recycle, i, self->extra->children[cur]);
}
/* ... */Sanitizer Output
=================================================================
==1358729==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000018 (pc 0x7ec7aa3f4a34 bp 0x7ffc814b7630 sp 0x7ffc814b7540 T0)
==1358729==The signal is caused by a READ memory access.
==1358729==Hint: address points to the zero page.
#0 0x7ec7aa3f4a34 in element_ass_subscr /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/./Modules/_elementtree.c:1992:17
#1 0x5eb4609c0d68 in _PyEval_EvalFrameDefault /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/generated_cases.c.h:11245:27
#2 0x5eb4609b23bb in _PyEval_EvalFrame /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/./Include/internal/pycore_ceval.h:121:16
#3 0x5eb4609b23bb in _PyEval_Vector /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/ceval.c:2005:12
#4 0x5eb4609b23bb in PyEval_EvalCode /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/ceval.c:888:21
#5 0x5eb460b09370 in run_eval_code_obj /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/pythonrun.c:1365:12
#6 0x5eb460b09370 in run_mod /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/pythonrun.c:1459:19
#7 0x5eb460b0343c in pyrun_file /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/pythonrun.c:1293:15
#8 0x5eb460b0343c in _PyRun_SimpleFileObject /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/pythonrun.c:521:13
#9 0x5eb460b02b05 in _PyRun_AnyFileObject /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/pythonrun.c:81:15
#10 0x5eb460b6afe5 in pymain_run_file_obj /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Modules/main.c:410:15
#11 0x5eb460b6afe5 in pymain_run_file /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Modules/main.c:429:15
#12 0x5eb460b6999d in pymain_run_python /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Modules/main.c:691:21
#13 0x5eb460b6999d in Py_RunMain /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Modules/main.c:772:5
#14 0x5eb460b6a451 in pymain_main /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Modules/main.c:802:12
#15 0x5eb460b6a5c3 in Py_BytesMain /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Modules/main.c:826:12
#16 0x7ec7ac62a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#17 0x7ec7ac62a28a in __libc_start_main csu/../csu/libc-start.c:360:3
#18 0x5eb46051a104 in _start (/home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/python+0x1c7104) (BuildId: 5de9d2fcbcd44bfc1b0fe256566d49ad35ca1d56)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/./Modules/_elementtree.c:1992:17 in element_ass_subscr
==1358729==ABORTING
Metadata
Metadata
Assignees
Labels
No labels