Skip to content

Commit 0488d21

Browse files
committed
gh-143195: fix UAF in {bytearray,memoryview}.hex(sep) via re-entrant sep.__len__
1 parent 57d5699 commit 0488d21

File tree

4 files changed

+40
-1
lines changed

4 files changed

+40
-1
lines changed

Lib/test/test_bytes.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2092,6 +2092,19 @@ def make_case():
20922092
with self.assertRaises(BufferError):
20932093
ba.rsplit(evil)
20942094

2095+
def test_hex_use_after_free(self):
2096+
# Prevent UAF in bytearray.hex(sep) with re-entrant sep.__len__.
2097+
# Regression test for https://github.com/python/cpython/issues/143195.
2098+
ba = bytearray(b'\xAA')
2099+
2100+
class S(bytes):
2101+
def __len__(self):
2102+
ba.clear()
2103+
return 1
2104+
2105+
self.assertRaises(BufferError, ba.hex, S(b':'))
2106+
2107+
20952108
class AssortedBytesTest(unittest.TestCase):
20962109
#
20972110
# Test various combinations of bytes and bytearray

Lib/test/test_memoryview.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
are in test_buffer.
55
"""
66

7+
import contextlib
78
import unittest
89
import test.support
910
import sys
@@ -442,6 +443,22 @@ def test_issue22668(self):
442443
self.assertEqual(c.format, "H")
443444
self.assertEqual(d.format, "H")
444445

446+
def test_hex_use_after_free(self):
447+
# Prevent UAF in memoryview.hex(sep) with re-entrant sep.__len__.
448+
# Regression test for https://github.com/python/cpython/issues/143195.
449+
ba = bytearray(b'A' * 1024)
450+
mv = memoryview(ba)
451+
452+
class S(bytes):
453+
def __len__(self):
454+
mv.release()
455+
ba.clear()
456+
return 1
457+
458+
# The following should not crash but it may not necessarily raise.
459+
with contextlib.suppress(BufferError):
460+
mv.hex(S(b':'))
461+
445462

446463
# Variations on source objects for the buffer: bytes-like objects, then arrays
447464
# with itemsize > 1.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix use-after-free crashes in :meth:`bytearray.hex` and :meth:`memoryview.hex`
2+
when the separator's :meth:`~object.__len__` mutates the original object.
3+
Patch by Bénédikt Tran.

Objects/bytearrayobject.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2664,7 +2664,13 @@ bytearray_hex_impl(PyByteArrayObject *self, PyObject *sep, int bytes_per_sep)
26642664
{
26652665
char* argbuf = PyByteArray_AS_STRING(self);
26662666
Py_ssize_t arglen = PyByteArray_GET_SIZE(self);
2667-
return _Py_strhex_with_sep(argbuf, arglen, sep, bytes_per_sep);
2667+
// Prevent 'self' from being freed if computing len(sep) mutates 'self'
2668+
// in _Py_strhex_with_sep().
2669+
// See: https://github.com/python/cpython/issues/143195.
2670+
self->ob_exports++;
2671+
PyObject *res = _Py_strhex_with_sep(argbuf, arglen, sep, bytes_per_sep);
2672+
self->ob_exports--;
2673+
return res;
26682674
}
26692675

26702676
static PyObject *

0 commit comments

Comments
 (0)