Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions Lib/test/test_xml_etree_c.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,32 @@ def __hash__(self):
r = e.get(X())
self.assertIsNone(r)

def test_use_after_free_crash_with_evil_element(self):
# test fix for reported used-after-free issue gh-126033
class EvilElement(cET.Element):
def __eq__(self, other):
base.clear() # this frees base->extra
return False

base = cET.Element('a')
base.append(EvilElement('a'))
base.append(EvilElement('a'))

with self.assertRaisesRegex(ReferenceError, r'base has been cleared during'):
base.remove(cET.Element('b'))

def test_use_after_free_crash_with_evil_tag(self):
# test fix for reported used-after-free issue gh-126037
class EvilTag(str):
def __eq__(self, other):
base.clear() # this frees base->extra
return False
base = cET.Element('a')
base.append(cET.Element(EvilTag('x')))

with self.assertRaisesRegex(ReferenceError, r'base has been cleared during'):
base.find('a')

@support.cpython_only
def test_immutable_types(self):
root = cET.fromstring('<a></a>')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed use-after-crash crashes on :class:`xml.etree.ElementTree` which underlying :meth:`~object.__eq__` function implements clearing its base. Reported by picnixz. Patch by Xingru Li.
13 changes: 13 additions & 0 deletions Modules/_elementtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -1267,6 +1267,13 @@ _elementtree_Element_find_impl(ElementObject *self, PyTypeObject *cls,
assert(Element_Check(st, item));
Py_INCREF(item);
rc = PyObject_RichCompareBool(((ElementObject*)item)->tag, path, Py_EQ);
if (!self->extra) {
PyErr_SetString(
PyExc_ReferenceError,
"list.find(x): list's base has been cleared during finding");
Py_DECREF(item);
return NULL;
}
if (rc > 0)
return item;
Py_DECREF(item);
Expand Down Expand Up @@ -1649,6 +1656,12 @@ _elementtree_Element_remove_impl(ElementObject *self, PyObject *subelement)
if (self->extra->children[i] == subelement)
break;
rc = PyObject_RichCompareBool(self->extra->children[i], subelement, Py_EQ);
if (!self->extra) {
PyErr_SetString(
PyExc_ReferenceError,
"list.remove(x): list's base has been cleared during removing");
return NULL;
}
if (rc > 0)
break;
if (rc < 0)
Expand Down
Loading