Skip to content

Null pointer dereference in element_ass_subscr via re-entrant calls #143200

@jackfromeast

Description

@jackfromeast

What happened?

A crafted __index__ invoked by root[bad_index:] clears the element so element_ass_subscr frees self->extra, but the slice handling continues and calls PySlice_AdjustIndices on the dangling child store, dereferencing NULL and crashing the interpreter.

Proof of Concept:

import xml.etree.ElementTree as ET

root = ET.Element("root")
root.extend([ET.Element("c0"), ET.Element("c1")])

class Evil:
    def __index__(self):
        # Re-entrant mutation: clear() frees the internal child storage
        global root
        root.clear()
        return 0

bad_index = Evil()
root[bad_index:]
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)
{
    ElementObject *self = _Element_CAST(op);

    if (PyIndex_Check(item)) {
        /* ... */
    }
    else if (PySlice_Check(item)) {
        Py_ssize_t start, stop, step, slicelen, newlen, i;
        size_t cur;

        PyObject* recycle = NULL;
        PyObject* seq;

        if (!self->extra) {
            if (create_extra(self, NULL) < 0)
                return -1;
        }

        // Bug: Trigger _PyEval_SliceIndex() on start, stop and step which calls __index__
        if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
            return -1;
        }

        // Crash: self->extra is a null pointer now
        slicelen = PySlice_AdjustIndices(self->extra->length, &start, &stop,
                                         step);
        /* ... */
Sanitizer Output
=================================================================
==1355724==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000008 (pc 0x7395f056c3c9 bp 0x7ffe1a3bd730 sp 0x7ffe1a3bd640 T0)
==1355724==The signal is caused by a READ memory access.
==1355724==Hint: address points to the zero page.
    #0 0x7395f056c3c9 in element_ass_subscr /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/./Modules/_elementtree.c:1875:55
    #1 0x62fba8d2b38b in _PyEval_EvalFrameDefault /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/generated_cases.c.h:5281:23
    #2 0x62fba8d1a3bb in _PyEval_EvalFrame /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/./Include/internal/pycore_ceval.h:121:16
    #3 0x62fba8d1a3bb in _PyEval_Vector /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/ceval.c:2005:12
    #4 0x62fba8d1a3bb in PyEval_EvalCode /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/ceval.c:888:21
    #5 0x62fba8e71370 in run_eval_code_obj /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/pythonrun.c:1365:12
    #6 0x62fba8e71370 in run_mod /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/pythonrun.c:1459:19
    #7 0x62fba8e6b43c in pyrun_file /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/pythonrun.c:1293:15
    #8 0x62fba8e6b43c in _PyRun_SimpleFileObject /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/pythonrun.c:521:13
    #9 0x62fba8e6ab05 in _PyRun_AnyFileObject /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Python/pythonrun.c:81:15
    #10 0x62fba8ed2fe5 in pymain_run_file_obj /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Modules/main.c:410:15
    #11 0x62fba8ed2fe5 in pymain_run_file /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Modules/main.c:429:15
    #12 0x62fba8ed199d in pymain_run_python /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Modules/main.c:691:21
    #13 0x62fba8ed199d in Py_RunMain /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Modules/main.c:772:5
    #14 0x62fba8ed2451 in pymain_main /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Modules/main.c:802:12
    #15 0x62fba8ed25c3 in Py_BytesMain /home/jackfromeast/Desktop/entropy/tasks/reproducexx/targets/cpython-main/Modules/main.c:826:12
    #16 0x7395f282a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #17 0x7395f282a28a in __libc_start_main csu/../csu/libc-start.c:360:3
    #18 0x62fba8882104 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:1875:55 in element_ass_subscr
==1355724==ABORTING

Metadata

Metadata

Assignees

Labels

extension-modulesC modules in the Modules dirtopic-XMLtype-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