gh-148735: Fix a UAF in Element.findtext() (#148738)

This commit is contained in:
Stan Ulbrych 2026-04-23 15:48:00 +01:00 committed by GitHub
parent 158dbbb97f
commit 0469e6d38d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 22 additions and 13 deletions

View file

@ -3271,6 +3271,16 @@ def test_findtext_with_mutating(self):
e.extend([ET.Element('bar')])
e.findtext(cls(e, 'x'))
def test_findtext_with_mutating_non_none_text(self):
for cls in [MutationDeleteElementPath, MutationClearElementPath]:
with self.subTest(cls):
e = ET.Element('foo')
child = ET.Element('bar')
child.text = str(object())
e.append(child)
del child
repr(e.findtext(cls(e, 'x')))
def test_findtext_with_error(self):
e = ET.Element('foo')
e.extend([ET.Element('bar')])

View file

@ -0,0 +1,3 @@
:mod:`xml.etree.ElementTree`: Fix a use-after-free in
:meth:`Element.findtext <xml.etree.ElementTree.Element.findtext>` when the
element tree is mutated concurrently during the search.

View file

@ -573,7 +573,7 @@ element_get_attrib(ElementObject* self)
LOCAL(PyObject*)
element_get_text(ElementObject* self)
{
/* return borrowed reference to text attribute */
/* return new reference to text attribute */
PyObject *res = self->text;
@ -588,13 +588,13 @@ element_get_text(ElementObject* self)
}
}
return res;
return Py_NewRef(res);
}
LOCAL(PyObject*)
element_get_tail(ElementObject* self)
{
/* return borrowed reference to text attribute */
/* return new reference to tail attribute */
PyObject *res = self->tail;
@ -609,7 +609,7 @@ element_get_tail(ElementObject* self)
}
}
return res;
return Py_NewRef(res);
}
static PyObject*
@ -1359,9 +1359,9 @@ _elementtree_Element_findtext_impl(ElementObject *self, PyTypeObject *cls,
PyObject *text = element_get_text((ElementObject *)item);
Py_DECREF(item);
if (text == Py_None) {
Py_DECREF(text);
return Py_GetConstant(Py_CONSTANT_EMPTY_STR);
}
Py_XINCREF(text);
return text;
}
Py_DECREF(item);
@ -2064,16 +2064,14 @@ static PyObject*
element_text_getter(PyObject *op, void *closure)
{
ElementObject *self = _Element_CAST(op);
PyObject *res = element_get_text(self);
return Py_XNewRef(res);
return element_get_text(self);
}
static PyObject*
element_tail_getter(PyObject *op, void *closure)
{
ElementObject *self = _Element_CAST(op);
PyObject *res = element_get_tail(self);
return Py_XNewRef(res);
return element_get_tail(self);
}
static PyObject*
@ -2316,16 +2314,14 @@ elementiter_next(PyObject *op)
continue;
gettext:
Py_DECREF(elem);
if (!text) {
Py_DECREF(elem);
return NULL;
}
if (text == Py_None) {
Py_DECREF(elem);
Py_DECREF(text);
}
else {
Py_INCREF(text);
Py_DECREF(elem);
rc = PyObject_IsTrue(text);
if (rc > 0)
return text;