Skip to content

Commit 887afac

Browse files
committed
fix: bytearray: prevent UAF in search-like methods by exporting self buffer
1 parent da8199f commit 887afac

File tree

2 files changed

+114
-35
lines changed

2 files changed

+114
-35
lines changed

Lib/test/test_bytes.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2060,6 +2060,24 @@ def __index__(self):
20602060
self.assertEqual(instance.ba[0], ord("?"), "Assigned bytearray not altered")
20612061
self.assertEqual(instance.new_ba, bytearray(0x180), "Wrong object altered")
20622062

2063+
def test_search_methods_reentrancy_raises_buffererror(self):
2064+
ba = bytearray(b"A")
2065+
class Evil:
2066+
def __index__(self):
2067+
ba.clear()
2068+
return 65 # ord('A')
2069+
with self.assertRaises(BufferError):
2070+
ba.find(Evil())
2071+
with self.assertRaises(BufferError):
2072+
ba.count(Evil())
2073+
with self.assertRaises(BufferError):
2074+
ba.index(Evil())
2075+
with self.assertRaises(BufferError):
2076+
ba.rindex(Evil())
2077+
with self.assertRaises(BufferError):
2078+
ba.rfind(Evil())
2079+
2080+
20632081

20642082
class AssortedBytesTest(unittest.TestCase):
20652083
#

Objects/bytearrayobject.c

Lines changed: 96 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,8 +1233,14 @@ bytearray_find_impl(PyByteArrayObject *self, PyObject *sub, Py_ssize_t start,
12331233
Py_ssize_t end)
12341234
/*[clinic end generated code: output=413e1cab2ae87da0 input=df3aa94840d893a7]*/
12351235
{
1236-
return _Py_bytes_find(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1237-
sub, start, end);
1236+
Py_buffer selfbuf;
1237+
PyObject *res;
1238+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1239+
return NULL;
1240+
}
1241+
res = _Py_bytes_find((const char *)selfbuf.buf, selfbuf.len, sub, start, end);
1242+
PyBuffer_Release(&selfbuf);
1243+
return res;
12381244
}
12391245

12401246
/*[clinic input]
@@ -1250,8 +1256,14 @@ bytearray_count_impl(PyByteArrayObject *self, PyObject *sub,
12501256
Py_ssize_t start, Py_ssize_t end)
12511257
/*[clinic end generated code: output=a21ee2692e4f1233 input=e8fcdca8272857e0]*/
12521258
{
1253-
return _Py_bytes_count(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1254-
sub, start, end);
1259+
Py_buffer selfbuf;
1260+
PyObject *res;
1261+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1262+
return NULL;
1263+
}
1264+
res = _Py_bytes_count((const char *)selfbuf.buf, selfbuf.len, sub, start, end);
1265+
PyBuffer_Release(&selfbuf);
1266+
return res;
12551267
}
12561268

12571269
/*[clinic input]
@@ -1299,8 +1311,14 @@ bytearray_index_impl(PyByteArrayObject *self, PyObject *sub,
12991311
Py_ssize_t start, Py_ssize_t end)
13001312
/*[clinic end generated code: output=067a1e78efc672a7 input=c37f177cfee19fe4]*/
13011313
{
1302-
return _Py_bytes_index(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1303-
sub, start, end);
1314+
Py_buffer selfbuf;
1315+
PyObject *res;
1316+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1317+
return NULL;
1318+
}
1319+
res = _Py_bytes_index((const char *)selfbuf.buf, selfbuf.len, sub, start, end);
1320+
PyBuffer_Release(&selfbuf);
1321+
return res;
13041322
}
13051323

13061324
/*[clinic input]
@@ -1318,8 +1336,14 @@ bytearray_rfind_impl(PyByteArrayObject *self, PyObject *sub,
13181336
Py_ssize_t start, Py_ssize_t end)
13191337
/*[clinic end generated code: output=51bf886f932b283c input=1265b11c437d2750]*/
13201338
{
1321-
return _Py_bytes_rfind(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1322-
sub, start, end);
1339+
Py_buffer selfbuf;
1340+
PyObject *res;
1341+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1342+
return NULL;
1343+
}
1344+
res = _Py_bytes_rfind((const char *)selfbuf.buf, selfbuf.len, sub, start, end);
1345+
PyBuffer_Release(&selfbuf);
1346+
return res;
13231347
}
13241348

13251349
/*[clinic input]
@@ -1337,19 +1361,26 @@ bytearray_rindex_impl(PyByteArrayObject *self, PyObject *sub,
13371361
Py_ssize_t start, Py_ssize_t end)
13381362
/*[clinic end generated code: output=38e1cf66bafb08b9 input=7d198b3d6b0a62ce]*/
13391363
{
1340-
return _Py_bytes_rindex(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1341-
sub, start, end);
1364+
Py_buffer selfbuf;
1365+
PyObject *res;
1366+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1367+
return NULL;
1368+
}
1369+
res = _Py_bytes_rindex((const char *)selfbuf.buf, selfbuf.len, sub, start, end);
1370+
PyBuffer_Release(&selfbuf);
1371+
return res;
13421372
}
13431373

13441374
static int
13451375
bytearray_contains(PyObject *self, PyObject *arg)
13461376
{
13471377
int ret;
1348-
Py_BEGIN_CRITICAL_SECTION(self);
1349-
ret = _Py_bytes_contains(PyByteArray_AS_STRING(self),
1350-
PyByteArray_GET_SIZE(self),
1351-
arg);
1352-
Py_END_CRITICAL_SECTION();
1378+
Py_buffer selfbuf;
1379+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1380+
return -1;
1381+
}
1382+
ret = _Py_bytes_contains((const char *)selfbuf.buf, selfbuf.len, arg);
1383+
PyBuffer_Release(&selfbuf);
13531384
return ret;
13541385
}
13551386

@@ -1375,8 +1406,15 @@ bytearray_startswith_impl(PyByteArrayObject *self, PyObject *subobj,
13751406
Py_ssize_t start, Py_ssize_t end)
13761407
/*[clinic end generated code: output=a3d9b6d44d3662a6 input=93f9ffee684f109a]*/
13771408
{
1378-
return _Py_bytes_startswith(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1409+
Py_buffer selfbuf;
1410+
PyObject *res;
1411+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1412+
return NULL;
1413+
}
1414+
res = _Py_bytes_startswith((const char *)selfbuf.buf, selfbuf.len,
13791415
subobj, start, end);
1416+
PyBuffer_Release(&selfbuf);
1417+
return res;
13801418
}
13811419

13821420
/*[clinic input]
@@ -1401,8 +1439,15 @@ bytearray_endswith_impl(PyByteArrayObject *self, PyObject *subobj,
14011439
Py_ssize_t start, Py_ssize_t end)
14021440
/*[clinic end generated code: output=e75ea8c227954caa input=d158b030a11d0b06]*/
14031441
{
1404-
return _Py_bytes_endswith(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1442+
Py_buffer selfbuf;
1443+
PyObject *res;
1444+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1445+
return NULL;
1446+
}
1447+
res = _Py_bytes_endswith((const char *)selfbuf.buf, selfbuf.len,
14051448
subobj, start, end);
1449+
PyBuffer_Release(&selfbuf);
1450+
return res;
14061451
}
14071452

14081453
/*[clinic input]
@@ -1767,26 +1812,34 @@ bytearray_split_impl(PyByteArrayObject *self, PyObject *sep,
17671812
Py_ssize_t maxsplit)
17681813
/*[clinic end generated code: output=833e2cf385d9a04d input=dd9f6e2910cc3a34]*/
17691814
{
1770-
Py_ssize_t len = PyByteArray_GET_SIZE(self), n;
1771-
const char *s = PyByteArray_AS_STRING(self), *sub;
17721815
PyObject *list;
1773-
Py_buffer vsub;
1816+
Py_buffer selfbuf, vsub;
1817+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1818+
return NULL;
1819+
}
17741820

17751821
if (maxsplit < 0)
17761822
maxsplit = PY_SSIZE_T_MAX;
17771823

1778-
if (sep == Py_None)
1779-
return stringlib_split_whitespace((PyObject*) self, s, len, maxsplit);
1824+
if (sep == Py_None) {
1825+
list = stringlib_split_whitespace((PyObject*) self,
1826+
(const char *)selfbuf.buf, selfbuf.len,
1827+
maxsplit);
1828+
PyBuffer_Release(&selfbuf);
1829+
return list;
1830+
}
17801831

1781-
if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0)
1832+
if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0) {
1833+
PyBuffer_Release(&selfbuf);
17821834
return NULL;
1783-
sub = vsub.buf;
1784-
n = vsub.len;
1835+
}
17851836

17861837
list = stringlib_split(
1787-
(PyObject*) self, s, len, sub, n, maxsplit
1838+
(PyObject*) self, (const char *)selfbuf.buf, selfbuf.len,
1839+
(const char *)vsub.buf, vsub.len, maxsplit
17881840
);
17891841
PyBuffer_Release(&vsub);
1842+
PyBuffer_Release(&selfbuf);
17901843
return list;
17911844
}
17921845

@@ -1885,26 +1938,34 @@ bytearray_rsplit_impl(PyByteArrayObject *self, PyObject *sep,
18851938
Py_ssize_t maxsplit)
18861939
/*[clinic end generated code: output=a55e0b5a03cb6190 input=60e9abf305128ff4]*/
18871940
{
1888-
Py_ssize_t len = PyByteArray_GET_SIZE(self), n;
1889-
const char *s = PyByteArray_AS_STRING(self), *sub;
18901941
PyObject *list;
1891-
Py_buffer vsub;
1942+
Py_buffer selfbuf, vsub;
1943+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1944+
return NULL;
1945+
}
18921946

18931947
if (maxsplit < 0)
18941948
maxsplit = PY_SSIZE_T_MAX;
18951949

1896-
if (sep == Py_None)
1897-
return stringlib_rsplit_whitespace((PyObject*) self, s, len, maxsplit);
1950+
if (sep == Py_None) {
1951+
list = stringlib_rsplit_whitespace((PyObject*) self,
1952+
(const char *)selfbuf.buf, selfbuf.len,
1953+
maxsplit);
1954+
PyBuffer_Release(&selfbuf);
1955+
return list;
1956+
}
18981957

1899-
if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0)
1958+
if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0) {
1959+
PyBuffer_Release(&selfbuf);
19001960
return NULL;
1901-
sub = vsub.buf;
1902-
n = vsub.len;
1961+
}
19031962

19041963
list = stringlib_rsplit(
1905-
(PyObject*) self, s, len, sub, n, maxsplit
1964+
(PyObject*) self, (const char *)selfbuf.buf, selfbuf.len,
1965+
(const char *)vsub.buf, vsub.len, maxsplit
19061966
);
19071967
PyBuffer_Release(&vsub);
1968+
PyBuffer_Release(&selfbuf);
19081969
return list;
19091970
}
19101971

0 commit comments

Comments
 (0)