Skip to content

Commit 5225635

Browse files
gh-143003: Fix possible shared buffer overflow in bytearray.extend() (GH-143086)
When __length_hint__() returns 0 for non-empty iterator, the data can be written past the shared 0-terminated buffer, corrupting it.
1 parent 23abbf1 commit 5225635

File tree

3 files changed

+21
-2
lines changed

3 files changed

+21
-2
lines changed

Lib/test/test_bytes.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2104,6 +2104,23 @@ def make_case():
21042104
with self.assertRaises(BufferError):
21052105
ba.rsplit(evil)
21062106

2107+
def test_extend_empty_buffer_overflow(self):
2108+
# gh-143003
2109+
class EvilIter:
2110+
def __iter__(self):
2111+
return self
2112+
def __next__(self):
2113+
return next(source)
2114+
def __length_hint__(self):
2115+
return 0
2116+
2117+
# Use ASCII digits so float() takes the fast path that expects a NUL terminator.
2118+
source = iter(b'42')
2119+
ba = bytearray()
2120+
ba.extend(EvilIter())
2121+
2122+
self.assertRaises(ValueError, float, bytearray())
2123+
21072124
def test_hex_use_after_free(self):
21082125
# Prevent UAF in bytearray.hex(sep) with re-entrant sep.__len__.
21092126
# Regression test for https://github.com/python/cpython/issues/143195.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix an overflow of the shared empty buffer in :meth:`bytearray.extend` when
2+
``__length_hint__()`` returns 0 for non-empty iterator.

Objects/bytearrayobject.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2223,7 +2223,6 @@ bytearray_extend_impl(PyByteArrayObject *self, PyObject *iterable_of_ints)
22232223
Py_DECREF(bytearray_obj);
22242224
return NULL;
22252225
}
2226-
buf[len++] = value;
22272226
Py_DECREF(item);
22282227

22292228
if (len >= buf_size) {
@@ -2233,7 +2232,7 @@ bytearray_extend_impl(PyByteArrayObject *self, PyObject *iterable_of_ints)
22332232
Py_DECREF(bytearray_obj);
22342233
return PyErr_NoMemory();
22352234
}
2236-
addition = len >> 1;
2235+
addition = len ? len >> 1 : 1;
22372236
if (addition > PyByteArray_SIZE_MAX - len)
22382237
buf_size = PyByteArray_SIZE_MAX;
22392238
else
@@ -2247,6 +2246,7 @@ bytearray_extend_impl(PyByteArrayObject *self, PyObject *iterable_of_ints)
22472246
have invalidated it. */
22482247
buf = PyByteArray_AS_STRING(bytearray_obj);
22492248
}
2249+
buf[len++] = value;
22502250
}
22512251
Py_DECREF(it);
22522252

0 commit comments

Comments
 (0)