Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit220f0b1

Browse files
authored
gh-142560: prevent use-after-free in search-like methods by exporting buffer in bytearray (#142938)
1 parent1391ee6 commit220f0b1

File tree

3 files changed

+103
-42
lines changed

3 files changed

+103
-42
lines changed

‎Lib/test/test_bytes.py‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2060,6 +2060,37 @@ 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+
deftest_search_methods_reentrancy_raises_buffererror(self):
2064+
# gh-142560: Raise BufferError if buffer mutates during search arg conversion.
2065+
classEvil:
2066+
def__init__(self,ba):
2067+
self.ba=ba
2068+
def__buffer__(self,flags):
2069+
self.ba.clear()
2070+
returnmemoryview(self.ba)
2071+
def__release_buffer__(self,view:memoryview)->None:
2072+
view.release()
2073+
def__index__(self):
2074+
self.ba.clear()
2075+
returnord("A")
2076+
2077+
defmake_case():
2078+
ba=bytearray(b"A")
2079+
returnba,Evil(ba)
2080+
2081+
fornamein ("find","count","index","rindex","rfind"):
2082+
ba,evil=make_case()
2083+
withself.subTest(name):
2084+
withself.assertRaises(BufferError):
2085+
getattr(ba,name)(evil)
2086+
2087+
ba,evil=make_case()
2088+
withself.assertRaises(BufferError):
2089+
evilinba
2090+
withself.assertRaises(BufferError):
2091+
ba.split(evil)
2092+
withself.assertRaises(BufferError):
2093+
ba.rsplit(evil)
20632094

20642095
classAssortedBytesTest(unittest.TestCase):
20652096
#
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix use-after-free in:class:`bytearray` search-like methods (:meth:`~bytearray.find`,:meth:`~bytearray.count`,:meth:`~bytearray.index`,:meth:`~bytearray.rindex`, and:meth:`~bytearray.rfind`) by marking the storage as exported which causes reallocation attempts to raise:exc:`BufferError`. For:func:`~operator.contains`,:meth:`~bytearray.split`, and:meth:`~bytearray.rsplit` the:ref:`buffer protocol<bufferobjects>` is used for this.

‎Objects/bytearrayobject.c‎

Lines changed: 71 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,25 @@ bytearray_releasebuffer(PyObject *self, Py_buffer *view)
9090
Py_END_CRITICAL_SECTION();
9191
}
9292

93+
typedefPyObject* (*_ba_bytes_op)(constchar*buf,Py_ssize_tlen,
94+
PyObject*sub,Py_ssize_tstart,
95+
Py_ssize_tend);
96+
97+
staticPyObject*
98+
_bytearray_with_buffer(PyByteArrayObject*self,_ba_bytes_opop,PyObject*sub,
99+
Py_ssize_tstart,Py_ssize_tend)
100+
{
101+
PyObject*res;
102+
103+
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
104+
105+
/* Increase exports to prevent bytearray storage from changing during op. */
106+
self->ob_exports++;
107+
res=op(PyByteArray_AS_STRING(self),Py_SIZE(self),sub,start,end);
108+
self->ob_exports--;
109+
returnres;
110+
}
111+
93112
staticint
94113
_canresize(PyByteArrayObject*self)
95114
{
@@ -1248,8 +1267,7 @@ bytearray_find_impl(PyByteArrayObject *self, PyObject *sub, Py_ssize_t start,
12481267
Py_ssize_tend)
12491268
/*[clinic end generated code: output=413e1cab2ae87da0 input=df3aa94840d893a7]*/
12501269
{
1251-
return_Py_bytes_find(PyByteArray_AS_STRING(self),PyByteArray_GET_SIZE(self),
1252-
sub,start,end);
1270+
return_bytearray_with_buffer(self,_Py_bytes_find,sub,start,end);
12531271
}
12541272

12551273
/*[clinic input]
@@ -1265,8 +1283,7 @@ bytearray_count_impl(PyByteArrayObject *self, PyObject *sub,
12651283
Py_ssize_tstart,Py_ssize_tend)
12661284
/*[clinic end generated code: output=a21ee2692e4f1233 input=e8fcdca8272857e0]*/
12671285
{
1268-
return_Py_bytes_count(PyByteArray_AS_STRING(self),PyByteArray_GET_SIZE(self),
1269-
sub,start,end);
1286+
return_bytearray_with_buffer(self,_Py_bytes_count,sub,start,end);
12701287
}
12711288

12721289
/*[clinic input]
@@ -1314,8 +1331,7 @@ bytearray_index_impl(PyByteArrayObject *self, PyObject *sub,
13141331
Py_ssize_tstart,Py_ssize_tend)
13151332
/*[clinic end generated code: output=067a1e78efc672a7 input=c37f177cfee19fe4]*/
13161333
{
1317-
return_Py_bytes_index(PyByteArray_AS_STRING(self),PyByteArray_GET_SIZE(self),
1318-
sub,start,end);
1334+
return_bytearray_with_buffer(self,_Py_bytes_index,sub,start,end);
13191335
}
13201336

13211337
/*[clinic input]
@@ -1333,8 +1349,7 @@ bytearray_rfind_impl(PyByteArrayObject *self, PyObject *sub,
13331349
Py_ssize_tstart,Py_ssize_tend)
13341350
/*[clinic end generated code: output=51bf886f932b283c input=1265b11c437d2750]*/
13351351
{
1336-
return_Py_bytes_rfind(PyByteArray_AS_STRING(self),PyByteArray_GET_SIZE(self),
1337-
sub,start,end);
1352+
return_bytearray_with_buffer(self,_Py_bytes_rfind,sub,start,end);
13381353
}
13391354

13401355
/*[clinic input]
@@ -1352,18 +1367,22 @@ bytearray_rindex_impl(PyByteArrayObject *self, PyObject *sub,
13521367
Py_ssize_tstart,Py_ssize_tend)
13531368
/*[clinic end generated code: output=38e1cf66bafb08b9 input=7d198b3d6b0a62ce]*/
13541369
{
1355-
return_Py_bytes_rindex(PyByteArray_AS_STRING(self),PyByteArray_GET_SIZE(self),
1356-
sub,start,end);
1370+
return_bytearray_with_buffer(self,_Py_bytes_rindex,sub,start,end);
13571371
}
13581372

13591373
staticint
13601374
bytearray_contains(PyObject*self,PyObject*arg)
13611375
{
1362-
intret;
1376+
intret=-1;
13631377
Py_BEGIN_CRITICAL_SECTION(self);
1364-
ret=_Py_bytes_contains(PyByteArray_AS_STRING(self),
1378+
PyByteArrayObject*ba=_PyByteArray_CAST(self);
1379+
1380+
/* Increase exports to prevent bytearray storage from changing during _Py_bytes_contains(). */
1381+
ba->ob_exports++;
1382+
ret=_Py_bytes_contains(PyByteArray_AS_STRING(ba),
13651383
PyByteArray_GET_SIZE(self),
13661384
arg);
1385+
ba->ob_exports--;
13671386
Py_END_CRITICAL_SECTION();
13681387
returnret;
13691388
}
@@ -1390,8 +1409,7 @@ bytearray_startswith_impl(PyByteArrayObject *self, PyObject *subobj,
13901409
Py_ssize_tstart,Py_ssize_tend)
13911410
/*[clinic end generated code: output=a3d9b6d44d3662a6 input=93f9ffee684f109a]*/
13921411
{
1393-
return_Py_bytes_startswith(PyByteArray_AS_STRING(self),PyByteArray_GET_SIZE(self),
1394-
subobj,start,end);
1412+
return_bytearray_with_buffer(self,_Py_bytes_startswith,subobj,start,end);
13951413
}
13961414

13971415
/*[clinic input]
@@ -1416,8 +1434,7 @@ bytearray_endswith_impl(PyByteArrayObject *self, PyObject *subobj,
14161434
Py_ssize_tstart,Py_ssize_tend)
14171435
/*[clinic end generated code: output=e75ea8c227954caa input=d158b030a11d0b06]*/
14181436
{
1419-
return_Py_bytes_endswith(PyByteArray_AS_STRING(self),PyByteArray_GET_SIZE(self),
1420-
subobj,start,end);
1437+
return_bytearray_with_buffer(self,_Py_bytes_endswith,subobj,start,end);
14211438
}
14221439

14231440
/*[clinic input]
@@ -1782,26 +1799,32 @@ bytearray_split_impl(PyByteArrayObject *self, PyObject *sep,
17821799
Py_ssize_tmaxsplit)
17831800
/*[clinic end generated code: output=833e2cf385d9a04d input=dd9f6e2910cc3a34]*/
17841801
{
1785-
Py_ssize_tlen=PyByteArray_GET_SIZE(self),n;
1786-
constchar*s=PyByteArray_AS_STRING(self),*sub;
1787-
PyObject*list;
1788-
Py_buffervsub;
1802+
PyObject*list=NULL;
1803+
1804+
/* Increase exports to prevent bytearray storage from changing during _Py_bytes_contains(). */
1805+
self->ob_exports++;
1806+
constchar*sbuf=PyByteArray_AS_STRING(self);
1807+
Py_ssize_tslen=PyByteArray_GET_SIZE((PyObject*)self);
17891808

17901809
if (maxsplit<0)
17911810
maxsplit=PY_SSIZE_T_MAX;
17921811

1793-
if (sep==Py_None)
1794-
returnstringlib_split_whitespace((PyObject*)self,s,len,maxsplit);
1812+
if (sep==Py_None) {
1813+
list=stringlib_split_whitespace((PyObject*)self,sbuf,slen,maxsplit);
1814+
gotodone;
1815+
}
17951816

1796-
if (PyObject_GetBuffer(sep,&vsub,PyBUF_SIMPLE)!=0)
1797-
returnNULL;
1798-
sub=vsub.buf;
1799-
n=vsub.len;
1817+
Py_buffervsub;
1818+
if (PyObject_GetBuffer(sep,&vsub,PyBUF_SIMPLE)!=0) {
1819+
gotodone;
1820+
}
18001821

1801-
list=stringlib_split(
1802-
(PyObject*)self,s,len,sub,n,maxsplit
1803-
);
1822+
list=stringlib_split((PyObject*)self,sbuf,slen,
1823+
(constchar*)vsub.buf,vsub.len,maxsplit);
18041824
PyBuffer_Release(&vsub);
1825+
1826+
done:
1827+
self->ob_exports--;
18051828
returnlist;
18061829
}
18071830

@@ -1900,26 +1923,32 @@ bytearray_rsplit_impl(PyByteArrayObject *self, PyObject *sep,
19001923
Py_ssize_tmaxsplit)
19011924
/*[clinic end generated code: output=a55e0b5a03cb6190 input=60e9abf305128ff4]*/
19021925
{
1903-
Py_ssize_tlen=PyByteArray_GET_SIZE(self),n;
1904-
constchar*s=PyByteArray_AS_STRING(self),*sub;
1905-
PyObject*list;
1906-
Py_buffervsub;
1926+
PyObject*list=NULL;
1927+
1928+
/* Increase exports to prevent bytearray storage from changing during _Py_bytes_contains(). */
1929+
self->ob_exports++;
1930+
constchar*sbuf=PyByteArray_AS_STRING(self);
1931+
Py_ssize_tslen=PyByteArray_GET_SIZE((PyObject*)self);
19071932

19081933
if (maxsplit<0)
19091934
maxsplit=PY_SSIZE_T_MAX;
19101935

1911-
if (sep==Py_None)
1912-
returnstringlib_rsplit_whitespace((PyObject*)self,s,len,maxsplit);
1936+
if (sep==Py_None) {
1937+
list=stringlib_rsplit_whitespace((PyObject*)self,sbuf,slen,maxsplit);
1938+
gotodone;
1939+
}
19131940

1914-
if (PyObject_GetBuffer(sep,&vsub,PyBUF_SIMPLE)!=0)
1915-
returnNULL;
1916-
sub=vsub.buf;
1917-
n=vsub.len;
1941+
Py_buffervsub;
1942+
if (PyObject_GetBuffer(sep,&vsub,PyBUF_SIMPLE)!=0) {
1943+
gotodone;
1944+
}
19181945

1919-
list=stringlib_rsplit(
1920-
(PyObject*)self,s,len,sub,n,maxsplit
1921-
);
1946+
list=stringlib_rsplit((PyObject*)self,sbuf,slen,
1947+
(constchar*)vsub.buf,vsub.len,maxsplit);
19221948
PyBuffer_Release(&vsub);
1949+
1950+
done:
1951+
self->ob_exports--;
19231952
returnlist;
19241953
}
19251954

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp