From 4dd8a152168c067d9013809b0927e2750fcf7362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Richart?= Date: Mon, 31 Jul 2023 17:23:23 +0200 Subject: [PATCH 1/3] py: Prevent overflowing size_t before callin mp_seq_multiply. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The inputs [0]*2**30 or "blue"*2**30 could create a situation where size_t was overflowed and malloc was called with a corrupted value that would then lead to a bad access in memory. Signed-off-by: Félix Richart --- py/objlist.c | 3 +++ py/objstr.c | 3 +++ py/objtuple.c | 3 +++ 3 files changed, 9 insertions(+) diff --git a/py/objlist.c b/py/objlist.c index 1423cb1dee..c3f96ad6aa 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -132,6 +132,9 @@ STATIC mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { if (n < 0) { n = 0; } + if (o->len != 0 && (size_t)n > UINT_MAX / o->len) { + m_malloc_fail(UINT_MAX); + } mp_obj_list_t *s = list_new(o->len * n); mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items); return MP_OBJ_FROM_PTR(s); diff --git a/py/objstr.c b/py/objstr.c index b966a70169..d9d72f4e47 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -366,6 +366,9 @@ mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i return mp_const_empty_bytes; } } + if (lhs_len != 0 && (size_t)n > UINT_MAX / lhs_len) { + m_malloc_fail(UINT_MAX); + } vstr_t vstr; vstr_init_len(&vstr, lhs_len * n); mp_seq_multiply(lhs_data, sizeof(*lhs_data), lhs_len, n, vstr.buf); diff --git a/py/objtuple.c b/py/objtuple.c index 0318a35db6..42f366a8b8 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -165,6 +165,9 @@ mp_obj_t mp_obj_tuple_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { if (n <= 0) { return mp_const_empty_tuple; } + if (o->len != 0 && (size_t)n > UINT_MAX / o->len) { + m_malloc_fail(UINT_MAX); + } mp_obj_tuple_t *s = MP_OBJ_TO_PTR(mp_obj_new_tuple(o->len * n, NULL)); mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items); return MP_OBJ_FROM_PTR(s); From df421e0125eefecb6c1e15946332657631fc34de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Richart?= Date: Tue, 1 Aug 2023 09:13:57 +0200 Subject: [PATCH 2/3] py/sequence.c: Factorize check for int overflow. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Félix Richart --- py/objlist.c | 3 --- py/objstr.c | 3 --- py/objtuple.c | 3 --- py/sequence.c | 5 +++++ 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/py/objlist.c b/py/objlist.c index c3f96ad6aa..1423cb1dee 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -132,9 +132,6 @@ STATIC mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { if (n < 0) { n = 0; } - if (o->len != 0 && (size_t)n > UINT_MAX / o->len) { - m_malloc_fail(UINT_MAX); - } mp_obj_list_t *s = list_new(o->len * n); mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items); return MP_OBJ_FROM_PTR(s); diff --git a/py/objstr.c b/py/objstr.c index d9d72f4e47..b966a70169 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -366,9 +366,6 @@ mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i return mp_const_empty_bytes; } } - if (lhs_len != 0 && (size_t)n > UINT_MAX / lhs_len) { - m_malloc_fail(UINT_MAX); - } vstr_t vstr; vstr_init_len(&vstr, lhs_len * n); mp_seq_multiply(lhs_data, sizeof(*lhs_data), lhs_len, n, vstr.buf); diff --git a/py/objtuple.c b/py/objtuple.c index 42f366a8b8..0318a35db6 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -165,9 +165,6 @@ mp_obj_t mp_obj_tuple_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { if (n <= 0) { return mp_const_empty_tuple; } - if (o->len != 0 && (size_t)n > UINT_MAX / o->len) { - m_malloc_fail(UINT_MAX); - } mp_obj_tuple_t *s = MP_OBJ_TO_PTR(mp_obj_new_tuple(o->len * n, NULL)); mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items); return MP_OBJ_FROM_PTR(s); diff --git a/py/sequence.c b/py/sequence.c index 5838607431..be5d77e072 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -36,6 +36,11 @@ // Implements backend of sequence * integer operation. Assumes elements are // memory-adjacent in sequence. void mp_seq_multiply(const void *items, size_t item_sz, size_t len, size_t times, void *dest) { + if (item_sz != 0 && len != 0 && times != 0 && (len > SIZE_MAX / item_sz || times > SIZE_MAX / (item_sz * len))) { + // dest couldn't be correctly allocated in memory because + // item_sz * len * times overflows SIZE_MAX. + m_malloc_fail(SIZE_MAX); + } for (size_t i = 0; i < times; i++) { size_t copy_sz = item_sz * len; memcpy(dest, items, copy_sz); From e0a66965720614972304e48ec9139cd1b9f17cf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Richart?= Date: Tue, 1 Aug 2023 09:25:26 +0200 Subject: [PATCH 3/3] py/sequence.c: Add an early return. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Félix Richart --- py/sequence.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/py/sequence.c b/py/sequence.c index be5d77e072..505bd1d005 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -36,7 +36,10 @@ // Implements backend of sequence * integer operation. Assumes elements are // memory-adjacent in sequence. void mp_seq_multiply(const void *items, size_t item_sz, size_t len, size_t times, void *dest) { - if (item_sz != 0 && len != 0 && times != 0 && (len > SIZE_MAX / item_sz || times > SIZE_MAX / (item_sz * len))) { + if (len == 0 || times == 0 || item_sz == 0) { + return; + } + if (len > SIZE_MAX / item_sz || times > SIZE_MAX / (item_sz * len)) { // dest couldn't be correctly allocated in memory because // item_sz * len * times overflows SIZE_MAX. m_malloc_fail(SIZE_MAX);