bigint.c: fix buffer overflow in uadd with mismatched operand sizes

fix out-of-bounds read when adding bigints of different sizes. the
unrolled loop accessed both operands up to the size of x without
checking if y had enough limbs. when y->sz < x->sz, this caused reads
beyond y's allocation. now use min(x->sz, y->sz) for the overlap
region and handle remaining limbs from the larger operand separately.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-11-19 08:54:30 +09:00
parent 2993302b8a
commit 3f2611ebcd
+11 -3
View File
@@ -354,10 +354,11 @@ uadd(mpz_t *z, mpz_t *x, mpz_t *y)
/* Core multi-limb addition with carry propagation */
mp_dbl_limb c = 0;
size_t i;
size_t min_sz = (x->sz < y->sz) ? x->sz : y->sz;
/* Add overlapping limbs from both operands */
/* 4x unrolled loop for better performance */
for (i = 0; i + 4 <= x->sz; i += 4) {
for (i = 0; i + 4 <= min_sz; i += 4) {
c += (mp_dbl_limb)y->p[i] + (mp_dbl_limb)x->p[i];
z->p[i] = LOW(c);
c >>= DIG_SIZE;
@@ -375,13 +376,20 @@ uadd(mpz_t *z, mpz_t *x, mpz_t *y)
c >>= DIG_SIZE;
}
/* Handle remaining elements */
for (; i < x->sz; i++) {
/* Handle remaining elements in overlap */
for (; i < min_sz; i++) {
c += (mp_dbl_limb)y->p[i] + (mp_dbl_limb)x->p[i];
z->p[i] = LOW(c);
c >>= DIG_SIZE;
}
/* Add remaining limbs from x if it's larger */
for (; i < x->sz; i++) {
c += x->p[i];
z->p[i] = LOW(c);
c >>= DIG_SIZE;
}
/* Add remaining limbs from larger operand */
/* 4x unrolled loop for better performance */
for (; i + 4 <= y->sz; i += 4) {