Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
fix: bytearray: prevent UAF in search-like methods by exporting self …
…buffer
  • Loading branch information
fatelei committed Dec 11, 2025
commit 887afac6011c066d83a804bf639b445637a6cc98
18 changes: 18 additions & 0 deletions Lib/test/test_bytes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2060,6 +2060,24 @@ def __index__(self):
self.assertEqual(instance.ba[0], ord("?"), "Assigned bytearray not altered")
self.assertEqual(instance.new_ba, bytearray(0x180), "Wrong object altered")

def test_search_methods_reentrancy_raises_buffererror(self):
ba = bytearray(b"A")
class Evil:
def __index__(self):
ba.clear()
return 65 # ord('A')
with self.assertRaises(BufferError):
ba.find(Evil())
with self.assertRaises(BufferError):
ba.count(Evil())
with self.assertRaises(BufferError):
ba.index(Evil())
with self.assertRaises(BufferError):
ba.rindex(Evil())
with self.assertRaises(BufferError):
ba.rfind(Evil())



class AssortedBytesTest(unittest.TestCase):
#
Expand Down
131 changes: 96 additions & 35 deletions Objects/bytearrayobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1233,8 +1233,14 @@ bytearray_find_impl(PyByteArrayObject *self, PyObject *sub, Py_ssize_t start,
Py_ssize_t end)
/*[clinic end generated code: output=413e1cab2ae87da0 input=df3aa94840d893a7]*/
{
return _Py_bytes_find(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
sub, start, end);
Py_buffer selfbuf;
PyObject *res;
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
return NULL;
}
res = _Py_bytes_find((const char *)selfbuf.buf, selfbuf.len, sub, start, end);
PyBuffer_Release(&selfbuf);
return res;
}

/*[clinic input]
Expand All @@ -1250,8 +1256,14 @@ bytearray_count_impl(PyByteArrayObject *self, PyObject *sub,
Py_ssize_t start, Py_ssize_t end)
/*[clinic end generated code: output=a21ee2692e4f1233 input=e8fcdca8272857e0]*/
{
return _Py_bytes_count(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
sub, start, end);
Py_buffer selfbuf;
PyObject *res;
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
return NULL;
}
res = _Py_bytes_count((const char *)selfbuf.buf, selfbuf.len, sub, start, end);
PyBuffer_Release(&selfbuf);
return res;
}

/*[clinic input]
Expand Down Expand Up @@ -1299,8 +1311,14 @@ bytearray_index_impl(PyByteArrayObject *self, PyObject *sub,
Py_ssize_t start, Py_ssize_t end)
/*[clinic end generated code: output=067a1e78efc672a7 input=c37f177cfee19fe4]*/
{
return _Py_bytes_index(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
sub, start, end);
Py_buffer selfbuf;
PyObject *res;
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
return NULL;
}
res = _Py_bytes_index((const char *)selfbuf.buf, selfbuf.len, sub, start, end);
PyBuffer_Release(&selfbuf);
return res;
}

/*[clinic input]
Expand All @@ -1318,8 +1336,14 @@ bytearray_rfind_impl(PyByteArrayObject *self, PyObject *sub,
Py_ssize_t start, Py_ssize_t end)
/*[clinic end generated code: output=51bf886f932b283c input=1265b11c437d2750]*/
{
return _Py_bytes_rfind(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
sub, start, end);
Py_buffer selfbuf;
PyObject *res;
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
return NULL;
}
res = _Py_bytes_rfind((const char *)selfbuf.buf, selfbuf.len, sub, start, end);
PyBuffer_Release(&selfbuf);
return res;
}

/*[clinic input]
Expand All @@ -1337,19 +1361,26 @@ bytearray_rindex_impl(PyByteArrayObject *self, PyObject *sub,
Py_ssize_t start, Py_ssize_t end)
/*[clinic end generated code: output=38e1cf66bafb08b9 input=7d198b3d6b0a62ce]*/
{
return _Py_bytes_rindex(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
sub, start, end);
Py_buffer selfbuf;
PyObject *res;
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
return NULL;
}
res = _Py_bytes_rindex((const char *)selfbuf.buf, selfbuf.len, sub, start, end);
PyBuffer_Release(&selfbuf);
return res;
}

static int
bytearray_contains(PyObject *self, PyObject *arg)
{
int ret;
Py_BEGIN_CRITICAL_SECTION(self);
ret = _Py_bytes_contains(PyByteArray_AS_STRING(self),
PyByteArray_GET_SIZE(self),
arg);
Py_END_CRITICAL_SECTION();
Py_buffer selfbuf;
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
return -1;
}
ret = _Py_bytes_contains((const char *)selfbuf.buf, selfbuf.len, arg);
PyBuffer_Release(&selfbuf);
return ret;
}

Expand All @@ -1375,8 +1406,15 @@ bytearray_startswith_impl(PyByteArrayObject *self, PyObject *subobj,
Py_ssize_t start, Py_ssize_t end)
/*[clinic end generated code: output=a3d9b6d44d3662a6 input=93f9ffee684f109a]*/
{
return _Py_bytes_startswith(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
Py_buffer selfbuf;
PyObject *res;
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
return NULL;
}
res = _Py_bytes_startswith((const char *)selfbuf.buf, selfbuf.len,
subobj, start, end);
PyBuffer_Release(&selfbuf);
return res;
}

/*[clinic input]
Expand All @@ -1401,8 +1439,15 @@ bytearray_endswith_impl(PyByteArrayObject *self, PyObject *subobj,
Py_ssize_t start, Py_ssize_t end)
/*[clinic end generated code: output=e75ea8c227954caa input=d158b030a11d0b06]*/
{
return _Py_bytes_endswith(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
Py_buffer selfbuf;
PyObject *res;
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
return NULL;
}
res = _Py_bytes_endswith((const char *)selfbuf.buf, selfbuf.len,
subobj, start, end);
PyBuffer_Release(&selfbuf);
return res;
}

/*[clinic input]
Expand Down Expand Up @@ -1767,26 +1812,34 @@ bytearray_split_impl(PyByteArrayObject *self, PyObject *sep,
Py_ssize_t maxsplit)
/*[clinic end generated code: output=833e2cf385d9a04d input=dd9f6e2910cc3a34]*/
{
Py_ssize_t len = PyByteArray_GET_SIZE(self), n;
const char *s = PyByteArray_AS_STRING(self), *sub;
PyObject *list;
Py_buffer vsub;
Py_buffer selfbuf, vsub;
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
return NULL;
}

if (maxsplit < 0)
maxsplit = PY_SSIZE_T_MAX;

if (sep == Py_None)
return stringlib_split_whitespace((PyObject*) self, s, len, maxsplit);
if (sep == Py_None) {
list = stringlib_split_whitespace((PyObject*) self,
(const char *)selfbuf.buf, selfbuf.len,
maxsplit);
PyBuffer_Release(&selfbuf);
return list;
}

if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0)
if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0) {
PyBuffer_Release(&selfbuf);
return NULL;
sub = vsub.buf;
n = vsub.len;
}

list = stringlib_split(
(PyObject*) self, s, len, sub, n, maxsplit
(PyObject*) self, (const char *)selfbuf.buf, selfbuf.len,
(const char *)vsub.buf, vsub.len, maxsplit
);
PyBuffer_Release(&vsub);
PyBuffer_Release(&selfbuf);
return list;
}

Expand Down Expand Up @@ -1885,26 +1938,34 @@ bytearray_rsplit_impl(PyByteArrayObject *self, PyObject *sep,
Py_ssize_t maxsplit)
/*[clinic end generated code: output=a55e0b5a03cb6190 input=60e9abf305128ff4]*/
{
Py_ssize_t len = PyByteArray_GET_SIZE(self), n;
const char *s = PyByteArray_AS_STRING(self), *sub;
PyObject *list;
Py_buffer vsub;
Py_buffer selfbuf, vsub;
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
return NULL;
}

if (maxsplit < 0)
maxsplit = PY_SSIZE_T_MAX;

if (sep == Py_None)
return stringlib_rsplit_whitespace((PyObject*) self, s, len, maxsplit);
if (sep == Py_None) {
list = stringlib_rsplit_whitespace((PyObject*) self,
(const char *)selfbuf.buf, selfbuf.len,
maxsplit);
PyBuffer_Release(&selfbuf);
return list;
}

if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0)
if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0) {
PyBuffer_Release(&selfbuf);
return NULL;
sub = vsub.buf;
n = vsub.len;
}

list = stringlib_rsplit(
(PyObject*) self, s, len, sub, n, maxsplit
(PyObject*) self, (const char *)selfbuf.buf, selfbuf.len,
(const char *)vsub.buf, vsub.len, maxsplit
);
PyBuffer_Release(&vsub);
PyBuffer_Release(&selfbuf);
return list;
}

Expand Down
Loading