From 0615d13963ba33650a5b2070368584c7aec9c9dd Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 6 Aug 2025 10:15:57 -0500 Subject: [PATCH] py/objringio: Detect incorrect constructor calls. ringbuffer.size must be at least 2, and is a 16-bit quantity. This fixes several cases including the one the fuzzer discovered, which would lead to a fatal signal when accessing the object. Fixes issue #17847. Signed-off-by: Jeff Epler --- py/objringio.c | 19 ++++++++----------- tests/micropython/ringio.py | 18 ++++++++++++++++++ tests/micropython/ringio.py.exp | 3 +++ tests/micropython/ringio_big.py | 29 +++++++++++++++++++++++++++++ tests/micropython/ringio_big.py.exp | 2 ++ 5 files changed, 60 insertions(+), 11 deletions(-) create mode 100644 tests/micropython/ringio_big.py create mode 100644 tests/micropython/ringio_big.py.exp diff --git a/py/objringio.c b/py/objringio.c index ba1ec25307..0025b26be3 100644 --- a/py/objringio.c +++ b/py/objringio.c @@ -39,22 +39,19 @@ typedef struct _micropython_ringio_obj_t { static mp_obj_t micropython_ringio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 1, 1, false); - mp_int_t buff_size = -1; mp_buffer_info_t bufinfo = {NULL, 0, 0}; if (!mp_get_buffer(args[0], &bufinfo, MP_BUFFER_RW)) { - buff_size = mp_obj_get_int(args[0]); + bufinfo.len = mp_obj_get_int(args[0]) + 1; + bufinfo.buf = m_new(uint8_t, bufinfo.len); + } + if (bufinfo.len < 2 || bufinfo.len > UINT16_MAX) { + mp_raise_ValueError(NULL); } micropython_ringio_obj_t *self = mp_obj_malloc(micropython_ringio_obj_t, type); - if (bufinfo.buf != NULL) { - // buffer passed in, use it directly for ringbuffer. - self->ringbuffer.buf = bufinfo.buf; - self->ringbuffer.size = bufinfo.len; - self->ringbuffer.iget = self->ringbuffer.iput = 0; - } else { - // Allocate new buffer, add one extra to buff_size as ringbuf consumes one byte for tracking. - ringbuf_alloc(&(self->ringbuffer), buff_size + 1); - } + self->ringbuffer.buf = bufinfo.buf; + self->ringbuffer.size = bufinfo.len; + self->ringbuffer.iget = self->ringbuffer.iput = 0; return MP_OBJ_FROM_PTR(self); } diff --git a/tests/micropython/ringio.py b/tests/micropython/ringio.py index a0102ef63d..4109288798 100644 --- a/tests/micropython/ringio.py +++ b/tests/micropython/ringio.py @@ -46,3 +46,21 @@ try: micropython.RingIO(None) except TypeError as ex: print(type(ex)) + +try: + # Buffer may not be empty + micropython.RingIO(bytearray(0)) +except ValueError as ex: + print(type(ex)) + +try: + # Buffer may not be too small + micropython.RingIO(bytearray(1)) +except ValueError as ex: + print(type(ex)) + +try: + # Size may not be too small + micropython.RingIO(0) +except ValueError as ex: + print(type(ex)) diff --git a/tests/micropython/ringio.py.exp b/tests/micropython/ringio.py.exp index 65bae06472..c391529a41 100644 --- a/tests/micropython/ringio.py.exp +++ b/tests/micropython/ringio.py.exp @@ -14,3 +14,6 @@ b'\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01' 0 b'\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01' + + + diff --git a/tests/micropython/ringio_big.py b/tests/micropython/ringio_big.py new file mode 100644 index 0000000000..d55c4c00b7 --- /dev/null +++ b/tests/micropython/ringio_big.py @@ -0,0 +1,29 @@ +# Check that micropython.RingIO works correctly. + +import micropython + +try: + micropython.RingIO +except AttributeError: + print("SKIP") + raise SystemExit + +try: + # The maximum possible size + micropython.RingIO(bytearray(65535)) + micropython.RingIO(65534) + + try: + # Buffer may not be too big + micropython.RingIO(bytearray(65536)) + except ValueError as ex: + print(type(ex)) + + try: + # Size may not be too big + micropython.RingIO(65535) + except ValueError as ex: + print(type(ex)) +except MemoryError: + print("SKIP") + raise SystemExit diff --git a/tests/micropython/ringio_big.py.exp b/tests/micropython/ringio_big.py.exp new file mode 100644 index 0000000000..72af34b383 --- /dev/null +++ b/tests/micropython/ringio_big.py.exp @@ -0,0 +1,2 @@ + +