https://github.com/python/cpython/commit/42762bb0989bddca75f0a98ff674ecbaf66d1b2a
commit: 42762bb0989bddca75f0a98ff674ecbaf66d1b2a
branch: 3.9
author: Miss Islington (bot) <[email protected]>
committer: ambv <[email protected]>
date: 2025-10-31T15:44:41+01:00
summary:

[3.9] gh-120384: gh-120298: Fix array-out-of-bounds & use after free `list` 
(GH-121345) (GH-140834)

(cherry picked from commit 8334a1b55c93068f5d243852029baa83377ff6c9)
(cherry picked from commit 0cd888b8d3a47428097571dddf5a0b5de37084e0)

Co-authored-by: Gregory P. Smith <[email protected]>
Co-authored-by: Nikita Sobolev <[email protected]>
Co-authored-by: Ɓukasz Langa <[email protected]>

files:
A Misc/NEWS.d/next/Core and 
Builtins/2024-06-10-10-42-48.gh-issue-120298.napREA.rst
A Misc/NEWS.d/next/Core and 
Builtins/2024-06-13-12-17-52.gh-issue-120384.w1UBGl.rst
M Lib/test/list_tests.py
M Lib/test/test_list.py
M Objects/listobject.c

diff --git a/Lib/test/list_tests.py b/Lib/test/list_tests.py
index 44bc2ae6573c1a..e5aab7b542155f 100644
--- a/Lib/test/list_tests.py
+++ b/Lib/test/list_tests.py
@@ -206,6 +206,14 @@ def test_setslice(self):
 
         self.assertRaises(TypeError, a.__setitem__)
 
+    def test_slice_assign_iterator(self):
+        x = self.type2test(range(5))
+        x[0:3] = reversed(range(3))
+        self.assertEqual(x, self.type2test([2, 1, 0, 3, 4]))
+
+        x[:] = reversed(range(3))
+        self.assertEqual(x, self.type2test([2, 1, 0]))
+
     def test_delslice(self):
         a = self.type2test([0, 1])
         del a[1:2]
diff --git a/Lib/test/test_list.py b/Lib/test/test_list.py
index 85bbf51e3f9977..d18387908bc675 100644
--- a/Lib/test/test_list.py
+++ b/Lib/test/test_list.py
@@ -201,6 +201,31 @@ def __eq__(self, other):
         list4 = [1]
         self.assertFalse(list3 == list4)
 
+    def test_lt_operator_modifying_operand(self):
+        # See gh-120298
+        class evil:
+            def __lt__(self, other):
+                other.clear()
+                return NotImplemented
+
+        a = [[evil()]]
+        with self.assertRaises(TypeError):
+            a[0] < a
+
+    def test_list_index_modifing_operand(self):
+        # See gh-120384
+        class evil:
+            def __init__(self, lst):
+                self.lst = lst
+            def __iter__(self):
+                yield from self.lst
+                self.lst.clear()
+
+        lst = list(range(5))
+        operand = evil(lst)
+        with self.assertRaises(ValueError):
+            lst[::-1] = operand
+
     @cpython_only
     def test_preallocation(self):
         iterable = [0] * 10
diff --git a/Misc/NEWS.d/next/Core and 
Builtins/2024-06-10-10-42-48.gh-issue-120298.napREA.rst b/Misc/NEWS.d/next/Core 
and Builtins/2024-06-10-10-42-48.gh-issue-120298.napREA.rst
new file mode 100644
index 00000000000000..531d39517ac423
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and 
Builtins/2024-06-10-10-42-48.gh-issue-120298.napREA.rst 
@@ -0,0 +1,2 @@
+Fix use-after free in ``list_richcompare_impl`` which can be invoked via
+some specificly tailored evil input.
diff --git a/Misc/NEWS.d/next/Core and 
Builtins/2024-06-13-12-17-52.gh-issue-120384.w1UBGl.rst b/Misc/NEWS.d/next/Core 
and Builtins/2024-06-13-12-17-52.gh-issue-120384.w1UBGl.rst
new file mode 100644
index 00000000000000..4a4db821ce29b8
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and 
Builtins/2024-06-13-12-17-52.gh-issue-120384.w1UBGl.rst 
@@ -0,0 +1,3 @@
+Fix an array out of bounds crash in ``list_ass_subscript``, which could be
+invoked via some specificly tailored input: including concurrent modification
+of a list object, where one thread assigns a slice and another clears it.
diff --git a/Objects/listobject.c b/Objects/listobject.c
index c12c02cbbf6b32..e4adf18ce30f9f 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -2679,7 +2679,14 @@ list_richcompare(PyObject *v, PyObject *w, int op)
     }
 
     /* Compare the final item again using the proper operator */
-    return PyObject_RichCompare(vl->ob_item[i], wl->ob_item[i], op);
+    PyObject *vitem = vl->ob_item[i];
+    PyObject *witem = wl->ob_item[i];
+    Py_INCREF(vitem);
+    Py_INCREF(witem);
+    PyObject *result = PyObject_RichCompare(vl->ob_item[i], wl->ob_item[i], 
op);
+    Py_DECREF(vitem);
+    Py_DECREF(witem);
+    return result;
 }
 
 /*[clinic input]
@@ -2863,6 +2870,23 @@ list_subscript(PyListObject* self, PyObject* item)
     }
 }
 
+static Py_ssize_t
+adjust_slice_indexes(PyListObject *lst,
+                     Py_ssize_t *start, Py_ssize_t *stop,
+                     Py_ssize_t step)
+{
+    Py_ssize_t slicelength = PySlice_AdjustIndices(Py_SIZE(lst), start, stop,
+                                                   step);
+
+    /* Make sure s[5:2] = [..] inserts at the right place:
+        before 5, not before 2. */
+    if ((step < 0 && *start < *stop) ||
+        (step > 0 && *start > *stop))
+        *stop = *start;
+
+    return slicelength;
+}
+
 static int
 list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value)
 {
@@ -2875,22 +2899,11 @@ list_ass_subscript(PyListObject* self, PyObject* item, 
PyObject* value)
         return list_ass_item(self, i, value);
     }
     else if (PySlice_Check(item)) {
-        Py_ssize_t start, stop, step, slicelength;
+        Py_ssize_t start, stop, step;
 
         if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
             return -1;
         }
-        slicelength = PySlice_AdjustIndices(Py_SIZE(self), &start, &stop,
-                                            step);
-
-        if (step == 1)
-            return list_ass_slice(self, start, stop, value);
-
-        /* Make sure s[5:2] = [..] inserts at the right place:
-           before 5, not before 2. */
-        if ((step < 0 && start < stop) ||
-            (step > 0 && start > stop))
-            stop = start;
 
         if (value == NULL) {
             /* delete slice */
@@ -2899,6 +2912,12 @@ list_ass_subscript(PyListObject* self, PyObject* item, 
PyObject* value)
             Py_ssize_t i;
             int res;
 
+            Py_ssize_t slicelength = adjust_slice_indexes(self, &start, &stop,
+                                                          step);
+
+            if (step == 1)
+                return list_ass_slice(self, start, stop, value);
+
             if (slicelength <= 0)
                 return 0;
 
@@ -2974,6 +2993,15 @@ list_ass_subscript(PyListObject* self, PyObject* item, 
PyObject* value)
             if (!seq)
                 return -1;
 
+            Py_ssize_t slicelength = adjust_slice_indexes(self, &start, &stop,
+                                                          step);
+
+            if (step == 1) {
+                int res = list_ass_slice(self, start, stop, seq);
+                Py_DECREF(seq);
+                return res;
+            }
+
             if (PySequence_Fast_GET_SIZE(seq) != slicelength) {
                 PyErr_Format(PyExc_ValueError,
                     "attempt to assign sequence of "

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to