Skip to content

Commit fb25b7d

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

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
@@ -1248,8 +1248,14 @@ bytearray_find_impl(PyByteArrayObject *self, PyObject *sub, Py_ssize_t start,
12481248
Py_ssize_t end)
12491249
/*[clinic end generated code: output=413e1cab2ae87da0 input=df3aa94840d893a7]*/
12501250
{
1251-
return _Py_bytes_find(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1252-
sub, start, end);
1251+
Py_buffer selfbuf;
1252+
PyObject *res;
1253+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1254+
return NULL;
1255+
}
1256+
res = _Py_bytes_find((const char *)selfbuf.buf, selfbuf.len, sub, start, end);
1257+
PyBuffer_Release(&selfbuf);
1258+
return res;
12531259
}
12541260

12551261
/*[clinic input]
@@ -1265,8 +1271,14 @@ bytearray_count_impl(PyByteArrayObject *self, PyObject *sub,
12651271
Py_ssize_t start, Py_ssize_t end)
12661272
/*[clinic end generated code: output=a21ee2692e4f1233 input=e8fcdca8272857e0]*/
12671273
{
1268-
return _Py_bytes_count(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1269-
sub, start, end);
1274+
Py_buffer selfbuf;
1275+
PyObject *res;
1276+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1277+
return NULL;
1278+
}
1279+
res = _Py_bytes_count((const char *)selfbuf.buf, selfbuf.len, sub, start, end);
1280+
PyBuffer_Release(&selfbuf);
1281+
return res;
12701282
}
12711283

12721284
/*[clinic input]
@@ -1314,8 +1326,14 @@ bytearray_index_impl(PyByteArrayObject *self, PyObject *sub,
13141326
Py_ssize_t start, Py_ssize_t end)
13151327
/*[clinic end generated code: output=067a1e78efc672a7 input=c37f177cfee19fe4]*/
13161328
{
1317-
return _Py_bytes_index(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1318-
sub, start, end);
1329+
Py_buffer selfbuf;
1330+
PyObject *res;
1331+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1332+
return NULL;
1333+
}
1334+
res = _Py_bytes_index((const char *)selfbuf.buf, selfbuf.len, sub, start, end);
1335+
PyBuffer_Release(&selfbuf);
1336+
return res;
13191337
}
13201338

13211339
/*[clinic input]
@@ -1333,8 +1351,14 @@ bytearray_rfind_impl(PyByteArrayObject *self, PyObject *sub,
13331351
Py_ssize_t start, Py_ssize_t end)
13341352
/*[clinic end generated code: output=51bf886f932b283c input=1265b11c437d2750]*/
13351353
{
1336-
return _Py_bytes_rfind(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1337-
sub, start, end);
1354+
Py_buffer selfbuf;
1355+
PyObject *res;
1356+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1357+
return NULL;
1358+
}
1359+
res = _Py_bytes_rfind((const char *)selfbuf.buf, selfbuf.len, sub, start, end);
1360+
PyBuffer_Release(&selfbuf);
1361+
return res;
13381362
}
13391363

13401364
/*[clinic input]
@@ -1352,19 +1376,26 @@ bytearray_rindex_impl(PyByteArrayObject *self, PyObject *sub,
13521376
Py_ssize_t start, Py_ssize_t end)
13531377
/*[clinic end generated code: output=38e1cf66bafb08b9 input=7d198b3d6b0a62ce]*/
13541378
{
1355-
return _Py_bytes_rindex(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1356-
sub, start, end);
1379+
Py_buffer selfbuf;
1380+
PyObject *res;
1381+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1382+
return NULL;
1383+
}
1384+
res = _Py_bytes_rindex((const char *)selfbuf.buf, selfbuf.len, sub, start, end);
1385+
PyBuffer_Release(&selfbuf);
1386+
return res;
13571387
}
13581388

13591389
static int
13601390
bytearray_contains(PyObject *self, PyObject *arg)
13611391
{
13621392
int ret;
1363-
Py_BEGIN_CRITICAL_SECTION(self);
1364-
ret = _Py_bytes_contains(PyByteArray_AS_STRING(self),
1365-
PyByteArray_GET_SIZE(self),
1366-
arg);
1367-
Py_END_CRITICAL_SECTION();
1393+
Py_buffer selfbuf;
1394+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1395+
return -1;
1396+
}
1397+
ret = _Py_bytes_contains((const char *)selfbuf.buf, selfbuf.len, arg);
1398+
PyBuffer_Release(&selfbuf);
13681399
return ret;
13691400
}
13701401

@@ -1390,8 +1421,15 @@ bytearray_startswith_impl(PyByteArrayObject *self, PyObject *subobj,
13901421
Py_ssize_t start, Py_ssize_t end)
13911422
/*[clinic end generated code: output=a3d9b6d44d3662a6 input=93f9ffee684f109a]*/
13921423
{
1393-
return _Py_bytes_startswith(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1424+
Py_buffer selfbuf;
1425+
PyObject *res;
1426+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1427+
return NULL;
1428+
}
1429+
res = _Py_bytes_startswith((const char *)selfbuf.buf, selfbuf.len,
13941430
subobj, start, end);
1431+
PyBuffer_Release(&selfbuf);
1432+
return res;
13951433
}
13961434

13971435
/*[clinic input]
@@ -1416,8 +1454,15 @@ bytearray_endswith_impl(PyByteArrayObject *self, PyObject *subobj,
14161454
Py_ssize_t start, Py_ssize_t end)
14171455
/*[clinic end generated code: output=e75ea8c227954caa input=d158b030a11d0b06]*/
14181456
{
1419-
return _Py_bytes_endswith(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1457+
Py_buffer selfbuf;
1458+
PyObject *res;
1459+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1460+
return NULL;
1461+
}
1462+
res = _Py_bytes_endswith((const char *)selfbuf.buf, selfbuf.len,
14201463
subobj, start, end);
1464+
PyBuffer_Release(&selfbuf);
1465+
return res;
14211466
}
14221467

14231468
/*[clinic input]
@@ -1782,26 +1827,34 @@ bytearray_split_impl(PyByteArrayObject *self, PyObject *sep,
17821827
Py_ssize_t maxsplit)
17831828
/*[clinic end generated code: output=833e2cf385d9a04d input=dd9f6e2910cc3a34]*/
17841829
{
1785-
Py_ssize_t len = PyByteArray_GET_SIZE(self), n;
1786-
const char *s = PyByteArray_AS_STRING(self), *sub;
17871830
PyObject *list;
1788-
Py_buffer vsub;
1831+
Py_buffer selfbuf, vsub;
1832+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1833+
return NULL;
1834+
}
17891835

17901836
if (maxsplit < 0)
17911837
maxsplit = PY_SSIZE_T_MAX;
17921838

1793-
if (sep == Py_None)
1794-
return stringlib_split_whitespace((PyObject*) self, s, len, maxsplit);
1839+
if (sep == Py_None) {
1840+
list = stringlib_split_whitespace((PyObject*) self,
1841+
(const char *)selfbuf.buf, selfbuf.len,
1842+
maxsplit);
1843+
PyBuffer_Release(&selfbuf);
1844+
return list;
1845+
}
17951846

1796-
if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0)
1847+
if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0) {
1848+
PyBuffer_Release(&selfbuf);
17971849
return NULL;
1798-
sub = vsub.buf;
1799-
n = vsub.len;
1850+
}
18001851

18011852
list = stringlib_split(
1802-
(PyObject*) self, s, len, sub, n, maxsplit
1853+
(PyObject*) self, (const char *)selfbuf.buf, selfbuf.len,
1854+
(const char *)vsub.buf, vsub.len, maxsplit
18031855
);
18041856
PyBuffer_Release(&vsub);
1857+
PyBuffer_Release(&selfbuf);
18051858
return list;
18061859
}
18071860

@@ -1900,26 +1953,34 @@ bytearray_rsplit_impl(PyByteArrayObject *self, PyObject *sep,
19001953
Py_ssize_t maxsplit)
19011954
/*[clinic end generated code: output=a55e0b5a03cb6190 input=60e9abf305128ff4]*/
19021955
{
1903-
Py_ssize_t len = PyByteArray_GET_SIZE(self), n;
1904-
const char *s = PyByteArray_AS_STRING(self), *sub;
19051956
PyObject *list;
1906-
Py_buffer vsub;
1957+
Py_buffer selfbuf, vsub;
1958+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1959+
return NULL;
1960+
}
19071961

19081962
if (maxsplit < 0)
19091963
maxsplit = PY_SSIZE_T_MAX;
19101964

1911-
if (sep == Py_None)
1912-
return stringlib_rsplit_whitespace((PyObject*) self, s, len, maxsplit);
1965+
if (sep == Py_None) {
1966+
list = stringlib_rsplit_whitespace((PyObject*) self,
1967+
(const char *)selfbuf.buf, selfbuf.len,
1968+
maxsplit);
1969+
PyBuffer_Release(&selfbuf);
1970+
return list;
1971+
}
19131972

1914-
if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0)
1973+
if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0) {
1974+
PyBuffer_Release(&selfbuf);
19151975
return NULL;
1916-
sub = vsub.buf;
1917-
n = vsub.len;
1976+
}
19181977

19191978
list = stringlib_rsplit(
1920-
(PyObject*) self, s, len, sub, n, maxsplit
1979+
(PyObject*) self, (const char *)selfbuf.buf, selfbuf.len,
1980+
(const char *)vsub.buf, vsub.len, maxsplit
19211981
);
19221982
PyBuffer_Release(&vsub);
1983+
PyBuffer_Release(&selfbuf);
19231984
return list;
19241985
}
19251986

0 commit comments

Comments
 (0)