Matej Cepl
30e970e5f7
use-after-free in Python via heappushpop in heapq (bsc#1214675, CVE-2022-48560). - switch from %patchN style to the %patch -P N one. OBS-URL: https://build.opensuse.org/package/show/devel:languages:python:Factory/python?expand=0&rev=391
133 lines
4.5 KiB
Diff
133 lines
4.5 KiB
Diff
From 5179d30710e6185dc7e6a6098ab23fe068b0d85b Mon Sep 17 00:00:00 2001
|
|
From: Lumir Balhar <lbalhar@redhat.com>
|
|
Date: Thu, 23 Nov 2023 13:25:44 +0100
|
|
Subject: [PATCH] 00408-cve-2022-48560.patch
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Security fix for CVE-2022-48560: python3: use after free in heappushpop()
|
|
of heapq module
|
|
Resolved upstream: https://github.com/python/cpython/issues/83602
|
|
|
|
Backported from Python 3.6.11.
|
|
|
|
Co-authored-by: Pablo Galindo <Pablogsal@gmail.com>
|
|
Co-authored-by: Lumír Balhar <lbalhar@redhat.com>
|
|
---
|
|
Lib/test/test_heapq.py | 32 ++++++++++++++++++++++++++++++++
|
|
Modules/_heapqmodule.c | 31 ++++++++++++++++++++++++-------
|
|
2 files changed, 56 insertions(+), 7 deletions(-)
|
|
|
|
--- a/Lib/test/test_heapq.py
|
|
+++ b/Lib/test/test_heapq.py
|
|
@@ -396,6 +396,38 @@ class TestErrorHandling(TestCase):
|
|
with self.assertRaises((IndexError, RuntimeError)):
|
|
self.module.heappop(heap)
|
|
|
|
+ def test_comparison_operator_modifiying_heap(self):
|
|
+ # See bpo-39421: Strong references need to be taken
|
|
+ # when comparing objects as they can alter the heap
|
|
+ class EvilClass(int):
|
|
+ def __lt__(self, o):
|
|
+ heap[:] = []
|
|
+ return NotImplemented
|
|
+
|
|
+ heap = []
|
|
+ self.module.heappush(heap, EvilClass(0))
|
|
+ self.assertRaises(IndexError, self.module.heappushpop, heap, 1)
|
|
+
|
|
+ def test_comparison_operator_modifiying_heap_two_heaps(self):
|
|
+
|
|
+ class h(int):
|
|
+ def __lt__(self, o):
|
|
+ list2[:] = []
|
|
+ return NotImplemented
|
|
+
|
|
+ class g(int):
|
|
+ def __lt__(self, o):
|
|
+ list1[:] = []
|
|
+ return NotImplemented
|
|
+
|
|
+ list1, list2 = [], []
|
|
+
|
|
+ self.module.heappush(list1, h(0))
|
|
+ self.module.heappush(list2, g(0))
|
|
+
|
|
+ self.assertRaises((IndexError, RuntimeError), self.module.heappush, list1, g(1))
|
|
+ self.assertRaises((IndexError, RuntimeError), self.module.heappush, list2, h(1))
|
|
+
|
|
|
|
class TestErrorHandlingPython(TestErrorHandling):
|
|
module = py_heapq
|
|
--- a/Modules/_heapqmodule.c
|
|
+++ b/Modules/_heapqmodule.c
|
|
@@ -52,7 +52,11 @@ _siftdown(PyListObject *heap, Py_ssize_t
|
|
while (pos > startpos) {
|
|
parentpos = (pos - 1) >> 1;
|
|
parent = PyList_GET_ITEM(heap, parentpos);
|
|
+ Py_INCREF(newitem);
|
|
+ Py_INCREF(parent);
|
|
cmp = cmp_lt(newitem, parent);
|
|
+ Py_DECREF(parent);
|
|
+ Py_DECREF(newitem);
|
|
if (cmp == -1)
|
|
return -1;
|
|
if (size != PyList_GET_SIZE(heap)) {
|
|
@@ -93,9 +97,13 @@ _siftup(PyListObject *heap, Py_ssize_t p
|
|
childpos = 2*pos + 1; /* leftmost child position */
|
|
rightpos = childpos + 1;
|
|
if (rightpos < endpos) {
|
|
- cmp = cmp_lt(
|
|
- PyList_GET_ITEM(heap, childpos),
|
|
- PyList_GET_ITEM(heap, rightpos));
|
|
+ PyObject* a = PyList_GET_ITEM(heap, childpos);
|
|
+ PyObject* b = PyList_GET_ITEM(heap, rightpos);
|
|
+ Py_INCREF(a);
|
|
+ Py_INCREF(b);
|
|
+ cmp = cmp_lt(a, b);
|
|
+ Py_DECREF(a);
|
|
+ Py_DECREF(b);
|
|
if (cmp == -1)
|
|
return -1;
|
|
if (cmp == 0)
|
|
@@ -236,7 +244,10 @@ heappushpop(PyObject *self, PyObject *ar
|
|
return item;
|
|
}
|
|
|
|
- cmp = cmp_lt(PyList_GET_ITEM(heap, 0), item);
|
|
+ PyObject* top = PyList_GET_ITEM(heap, 0);
|
|
+ Py_INCREF(top);
|
|
+ cmp = cmp_lt(top, item);
|
|
+ Py_DECREF(top);
|
|
if (cmp == -1)
|
|
return NULL;
|
|
if (cmp == 0) {
|
|
@@ -395,7 +406,9 @@ _siftdownmax(PyListObject *heap, Py_ssiz
|
|
while (pos > startpos){
|
|
parentpos = (pos - 1) >> 1;
|
|
parent = PyList_GET_ITEM(heap, parentpos);
|
|
+ Py_INCREF(parent);
|
|
cmp = cmp_lt(parent, newitem);
|
|
+ Py_DECREF(parent);
|
|
if (cmp == -1) {
|
|
Py_DECREF(newitem);
|
|
return -1;
|
|
@@ -436,9 +449,13 @@ _siftupmax(PyListObject *heap, Py_ssize_
|
|
childpos = 2*pos + 1; /* leftmost child position */
|
|
rightpos = childpos + 1;
|
|
if (rightpos < endpos) {
|
|
- cmp = cmp_lt(
|
|
- PyList_GET_ITEM(heap, rightpos),
|
|
- PyList_GET_ITEM(heap, childpos));
|
|
+ PyObject* a = PyList_GET_ITEM(heap, rightpos);
|
|
+ PyObject* b = PyList_GET_ITEM(heap, childpos);
|
|
+ Py_INCREF(a);
|
|
+ Py_INCREF(b);
|
|
+ cmp = cmp_lt(a, b);
|
|
+ Py_DECREF(a);
|
|
+ Py_DECREF(b);
|
|
if (cmp == -1) {
|
|
Py_DECREF(newitem);
|
|
return -1;
|