From 54fbf6c3eccd90eb18e8172c15819c85bddd0391 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 30 Dec 2025 14:46:26 +0900 Subject: [PATCH] bigint.c: fix buffer overflow in mpz_div_2exp with large shift When right-shifting by more bits than the number contains, the loop condition `i < x->sz - digs` would underflow (since size_t is unsigned), causing out-of-bounds memory access. Fixed by checking if digs >= x->sz upfront and returning zero in that case, since shifting right by more bits than the number has always yields zero. Discovered via ClusterFuzz with input "7<<78<<-772". Co-authored-by: Claude --- mrbgems/mruby-bigint/core/bigint.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-bigint/core/bigint.c b/mrbgems/mruby-bigint/core/bigint.c index c96f551f4..e5f912ffa 100644 --- a/mrbgems/mruby-bigint/core/bigint.c +++ b/mrbgems/mruby-bigint/core/bigint.c @@ -2099,12 +2099,18 @@ mpz_div_2exp(mpz_ctx_t *ctx, mpz_t *z, mpz_t *x, mrb_int e) else { size_t digs = e / DIG_SIZE; size_t bs = e % DIG_SIZE; - mpz_t y; - size_t new_size = (digs >= x->sz) ? 1 : x->sz - digs; + /* If shifting by more limbs than we have, result is zero */ + if (digs >= x->sz) { + zero(z); + return; + } + + mpz_t y; + size_t new_size = x->sz - digs; mpz_init_temp(ctx, &y, new_size); mpz_realloc(ctx, &y, new_size); - for (size_t i = 0; i < x->sz - digs; i++) + for (size_t i = 0; i < new_size; i++) y.p[i] = x->p[i + digs]; if (bs) { mpz_init_heap(ctx, z, new_size);