Skip to content

Commit 8ad1901

Browse files
committed
fix: bytearray: prevent UAF in search-like methods by exporting self buffer
1 parent 5a31024 commit 8ad1901

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
@@ -1951,6 +1951,24 @@ def __index__(self):
19511951
self.assertEqual(instance.ba[0], ord("?"), "Assigned bytearray not altered")
19521952
self.assertEqual(instance.new_ba, bytearray(0x180), "Wrong object altered")
19531953

1954+
def test_search_methods_reentrancy_raises_buffererror(self):
1955+
ba = bytearray(b"A")
1956+
class Evil:
1957+
def __index__(self):
1958+
ba.clear()
1959+
return 65 # ord('A')
1960+
with self.assertRaises(BufferError):
1961+
ba.find(Evil())
1962+
with self.assertRaises(BufferError):
1963+
ba.count(Evil())
1964+
with self.assertRaises(BufferError):
1965+
ba.index(Evil())
1966+
with self.assertRaises(BufferError):
1967+
ba.rindex(Evil())
1968+
with self.assertRaises(BufferError):
1969+
ba.rfind(Evil())
1970+
1971+
19541972

19551973
class AssortedBytesTest(unittest.TestCase):
19561974
#

Objects/bytearrayobject.c

Lines changed: 96 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,8 +1226,14 @@ bytearray_find_impl(PyByteArrayObject *self, PyObject *sub, Py_ssize_t start,
12261226
Py_ssize_t end)
12271227
/*[clinic end generated code: output=413e1cab2ae87da0 input=df3aa94840d893a7]*/
12281228
{
1229-
return _Py_bytes_find(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1230-
sub, start, end);
1229+
Py_buffer selfbuf;
1230+
PyObject *res;
1231+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1232+
return NULL;
1233+
}
1234+
res = _Py_bytes_find((const char *)selfbuf.buf, selfbuf.len, sub, start, end);
1235+
PyBuffer_Release(&selfbuf);
1236+
return res;
12311237
}
12321238

12331239
/*[clinic input]
@@ -1243,8 +1249,14 @@ bytearray_count_impl(PyByteArrayObject *self, PyObject *sub,
12431249
Py_ssize_t start, Py_ssize_t end)
12441250
/*[clinic end generated code: output=a21ee2692e4f1233 input=e8fcdca8272857e0]*/
12451251
{
1246-
return _Py_bytes_count(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1247-
sub, start, end);
1252+
Py_buffer selfbuf;
1253+
PyObject *res;
1254+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1255+
return NULL;
1256+
}
1257+
res = _Py_bytes_count((const char *)selfbuf.buf, selfbuf.len, sub, start, end);
1258+
PyBuffer_Release(&selfbuf);
1259+
return res;
12481260
}
12491261

12501262
/*[clinic input]
@@ -1292,8 +1304,14 @@ bytearray_index_impl(PyByteArrayObject *self, PyObject *sub,
12921304
Py_ssize_t start, Py_ssize_t end)
12931305
/*[clinic end generated code: output=067a1e78efc672a7 input=c37f177cfee19fe4]*/
12941306
{
1295-
return _Py_bytes_index(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1296-
sub, start, end);
1307+
Py_buffer selfbuf;
1308+
PyObject *res;
1309+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1310+
return NULL;
1311+
}
1312+
res = _Py_bytes_index((const char *)selfbuf.buf, selfbuf.len, sub, start, end);
1313+
PyBuffer_Release(&selfbuf);
1314+
return res;
12971315
}
12981316

12991317
/*[clinic input]
@@ -1311,8 +1329,14 @@ bytearray_rfind_impl(PyByteArrayObject *self, PyObject *sub,
13111329
Py_ssize_t start, Py_ssize_t end)
13121330
/*[clinic end generated code: output=51bf886f932b283c input=1265b11c437d2750]*/
13131331
{
1314-
return _Py_bytes_rfind(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1315-
sub, start, end);
1332+
Py_buffer selfbuf;
1333+
PyObject *res;
1334+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1335+
return NULL;
1336+
}
1337+
res = _Py_bytes_rfind((const char *)selfbuf.buf, selfbuf.len, sub, start, end);
1338+
PyBuffer_Release(&selfbuf);
1339+
return res;
13161340
}
13171341

13181342
/*[clinic input]
@@ -1330,19 +1354,26 @@ bytearray_rindex_impl(PyByteArrayObject *self, PyObject *sub,
13301354
Py_ssize_t start, Py_ssize_t end)
13311355
/*[clinic end generated code: output=38e1cf66bafb08b9 input=7d198b3d6b0a62ce]*/
13321356
{
1333-
return _Py_bytes_rindex(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1334-
sub, start, end);
1357+
Py_buffer selfbuf;
1358+
PyObject *res;
1359+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1360+
return NULL;
1361+
}
1362+
res = _Py_bytes_rindex((const char *)selfbuf.buf, selfbuf.len, sub, start, end);
1363+
PyBuffer_Release(&selfbuf);
1364+
return res;
13351365
}
13361366

13371367
static int
13381368
bytearray_contains(PyObject *self, PyObject *arg)
13391369
{
13401370
int ret;
1341-
Py_BEGIN_CRITICAL_SECTION(self);
1342-
ret = _Py_bytes_contains(PyByteArray_AS_STRING(self),
1343-
PyByteArray_GET_SIZE(self),
1344-
arg);
1345-
Py_END_CRITICAL_SECTION();
1371+
Py_buffer selfbuf;
1372+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1373+
return -1;
1374+
}
1375+
ret = _Py_bytes_contains((const char *)selfbuf.buf, selfbuf.len, arg);
1376+
PyBuffer_Release(&selfbuf);
13461377
return ret;
13471378
}
13481379

@@ -1368,8 +1399,15 @@ bytearray_startswith_impl(PyByteArrayObject *self, PyObject *subobj,
13681399
Py_ssize_t start, Py_ssize_t end)
13691400
/*[clinic end generated code: output=a3d9b6d44d3662a6 input=93f9ffee684f109a]*/
13701401
{
1371-
return _Py_bytes_startswith(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1402+
Py_buffer selfbuf;
1403+
PyObject *res;
1404+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1405+
return NULL;
1406+
}
1407+
res = _Py_bytes_startswith((const char *)selfbuf.buf, selfbuf.len,
13721408
subobj, start, end);
1409+
PyBuffer_Release(&selfbuf);
1410+
return res;
13731411
}
13741412

13751413
/*[clinic input]
@@ -1394,8 +1432,15 @@ bytearray_endswith_impl(PyByteArrayObject *self, PyObject *subobj,
13941432
Py_ssize_t start, Py_ssize_t end)
13951433
/*[clinic end generated code: output=e75ea8c227954caa input=d158b030a11d0b06]*/
13961434
{
1397-
return _Py_bytes_endswith(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self),
1435+
Py_buffer selfbuf;
1436+
PyObject *res;
1437+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1438+
return NULL;
1439+
}
1440+
res = _Py_bytes_endswith((const char *)selfbuf.buf, selfbuf.len,
13981441
subobj, start, end);
1442+
PyBuffer_Release(&selfbuf);
1443+
return res;
13991444
}
14001445

14011446
/*[clinic input]
@@ -1672,26 +1717,34 @@ bytearray_split_impl(PyByteArrayObject *self, PyObject *sep,
16721717
Py_ssize_t maxsplit)
16731718
/*[clinic end generated code: output=833e2cf385d9a04d input=dd9f6e2910cc3a34]*/
16741719
{
1675-
Py_ssize_t len = PyByteArray_GET_SIZE(self), n;
1676-
const char *s = PyByteArray_AS_STRING(self), *sub;
16771720
PyObject *list;
1678-
Py_buffer vsub;
1721+
Py_buffer selfbuf, vsub;
1722+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1723+
return NULL;
1724+
}
16791725

16801726
if (maxsplit < 0)
16811727
maxsplit = PY_SSIZE_T_MAX;
16821728

1683-
if (sep == Py_None)
1684-
return stringlib_split_whitespace((PyObject*) self, s, len, maxsplit);
1729+
if (sep == Py_None) {
1730+
list = stringlib_split_whitespace((PyObject*) self,
1731+
(const char *)selfbuf.buf, selfbuf.len,
1732+
maxsplit);
1733+
PyBuffer_Release(&selfbuf);
1734+
return list;
1735+
}
16851736

1686-
if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0)
1737+
if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0) {
1738+
PyBuffer_Release(&selfbuf);
16871739
return NULL;
1688-
sub = vsub.buf;
1689-
n = vsub.len;
1740+
}
16901741

16911742
list = stringlib_split(
1692-
(PyObject*) self, s, len, sub, n, maxsplit
1743+
(PyObject*) self, (const char *)selfbuf.buf, selfbuf.len,
1744+
(const char *)vsub.buf, vsub.len, maxsplit
16931745
);
16941746
PyBuffer_Release(&vsub);
1747+
PyBuffer_Release(&selfbuf);
16951748
return list;
16961749
}
16971750

@@ -1790,26 +1843,34 @@ bytearray_rsplit_impl(PyByteArrayObject *self, PyObject *sep,
17901843
Py_ssize_t maxsplit)
17911844
/*[clinic end generated code: output=a55e0b5a03cb6190 input=60e9abf305128ff4]*/
17921845
{
1793-
Py_ssize_t len = PyByteArray_GET_SIZE(self), n;
1794-
const char *s = PyByteArray_AS_STRING(self), *sub;
17951846
PyObject *list;
1796-
Py_buffer vsub;
1847+
Py_buffer selfbuf, vsub;
1848+
if (PyObject_GetBuffer((PyObject *)self, &selfbuf, PyBUF_SIMPLE) != 0) {
1849+
return NULL;
1850+
}
17971851

17981852
if (maxsplit < 0)
17991853
maxsplit = PY_SSIZE_T_MAX;
18001854

1801-
if (sep == Py_None)
1802-
return stringlib_rsplit_whitespace((PyObject*) self, s, len, maxsplit);
1855+
if (sep == Py_None) {
1856+
list = stringlib_rsplit_whitespace((PyObject*) self,
1857+
(const char *)selfbuf.buf, selfbuf.len,
1858+
maxsplit);
1859+
PyBuffer_Release(&selfbuf);
1860+
return list;
1861+
}
18031862

1804-
if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0)
1863+
if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0) {
1864+
PyBuffer_Release(&selfbuf);
18051865
return NULL;
1806-
sub = vsub.buf;
1807-
n = vsub.len;
1866+
}
18081867

18091868
list = stringlib_rsplit(
1810-
(PyObject*) self, s, len, sub, n, maxsplit
1869+
(PyObject*) self, (const char *)selfbuf.buf, selfbuf.len,
1870+
(const char *)vsub.buf, vsub.len, maxsplit
18111871
);
18121872
PyBuffer_Release(&vsub);
1873+
PyBuffer_Release(&selfbuf);
18131874
return list;
18141875
}
18151876

0 commit comments

Comments
 (0)