n and rr are sized with a floor division by 32 (num_bits >> 5), but
br_i32_decode() and the zero-init loop before br_i32_reduce() need
ceil(bits/32) words plus a header word. Whenever the stripped modulus
byte length isn't a multiple of 4, br_i32_decode() writes one word
past the end of n; whenever it's odd, the zero-init loop writes one
zero word past the end of rr. The modulus length is fully
attacker-controlled via the DER public key's ASN.1 INTEGER length, so
both overflows are reachable with a crafted key.

Switch both allocations to ceiling division so they always hold the
full word count each site writes. rrtmp is already exactly sized and
is left unchanged.

Fixes: 49d0ea3746ca ("lib: rsa: fix allocated size for rr and rrtmp in 
rsa_gen_key_prop()")
Signed-off-by: Prasad Kummari <[email protected]>
---
UT:
Tested on sandbox without fix:

=> ut lib lib_rsa_keyprop_oob
Test: lib_rsa_keyprop_oob: rsa.c
rsa_gen_key_prop: n_sz=257 leading_zeros=0 stripped_bytes=257
num_bits=2056
rsa_gen_key_prop: n_words=65 rr_words=129 rrtmp_words=130
n=000000001a0a5ae0 rr=000000001a0a5bf0 rrtmp=000000001a0a7010 (UNFIXED
sizing)
rsa_gen_key_prop: br_i32_decode(n) done, n[0] (bit_length)=2056
n0inv_input n[1]=0x968b6a4d
rsa_gen_key_prop: rlen=4112 rr zero-init loop wrote indices 1..129
rsa_gen_key_prop: br_i32_reduce(rr) done, rr[0] (bit_length)=2056
Tests run: 1, 0 ms, average: 0 ms, failures: 0

Tested on sandbox with fix:

=> ut lib lib_rsa_keyprop_oob
Test: lib_rsa_keyprop_oob: rsa.c
rsa_gen_key_prop: n_sz=257 leading_zeros=0 stripped_bytes=257
num_bits=2056
rsa_gen_key_prop: n_words=66 rr_words=130 rrtmp_words=130
n=000000001a0a5ae0 rr=000000001a0a5bf0 rrtmp=000000001a0a7010
rsa_gen_key_prop: br_i32_decode(n) done, n[0] (bit_length)=2056
n0inv_input n[1]=0x968b6a4d
rsa_gen_key_prop: rlen=4112 rr zero-init loop wrote indices 1..129
rsa_gen_key_prop: br_i32_reduce(rr) done, rr[0] (bit_length)=2056
Tests run: 1, 1 ms, average: 1 ms, failures: 0

Tested on versal2 without fix:

versal2> ut lib lib_rsa_keyprop_oob
Test: lib_rsa_keyprop_oob: rsa.c
rsa_gen_key_prop: n_sz=257 leading_zeros=0 stripped_bytes=257
num_bits=2056
rsa_gen_key_prop: n_words=65 rr_words=129 rrtmp_words=130
n=000000007bf027a0 rr=000000007bf028b0 rrtmp=000000007bf02ac0 (UNFIXED
sizing)
rsa_gen_key_prop: br_i32_decode(n) done, n[0] (bit_length)=2056
n0inv_input n[1]=0x968b6a4d
rsa_gen_key_prop: rlen=4112 rr zero-init loop wrote indices 1..129
rsa_gen_key_prop: br_i32_reduce(rr) done, rr[0] (bit_length)=2056
Tests run: 1, 39 ms, average: 39 ms, failures: 0

Tested on vek385 with fix:

versal2> ut lib lib_rsa_keyprop_oob
Test: lib_rsa_keyprop_oob: rsa.c
rsa_gen_key_prop: n_sz=257 leading_zeros=0 stripped_bytes=257
num_bits=2056
rsa_gen_key_prop: n_words=66 rr_words=130 rrtmp_words=130
n=000000007bf027a0 rr=000000007bf028b0 rrtmp=000000007bf02ac0
rsa_gen_key_prop: br_i32_decode(n) done, n[0] (bit_length)=2056
n0inv_input n[1]=0x968b6a4d
rsa_gen_key_prop: rlen=4112 rr zero-init loop wrote indices 1..129
rsa_gen_key_prop: br_i32_reduce(rr) done, rr[0] (bit_length)=2056
Tests run: 1, 38 ms, average: 38 ms, failures: 0

 lib/rsa/rsa-keyprop.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/rsa/rsa-keyprop.c b/lib/rsa/rsa-keyprop.c
index 80d0594a430..9b5aa1114e3 100644
--- a/lib/rsa/rsa-keyprop.c
+++ b/lib/rsa/rsa-keyprop.c
@@ -677,8 +677,8 @@ int rsa_gen_key_prop(const void *key, uint32_t keylen, 
struct key_prop **prop)
        }
        memcpy((void *)(*prop)->modulus, &rsa_key.n[i], rsa_key.n_sz - i);
 
-       n = calloc(sizeof(uint32_t), 1 + ((*prop)->num_bits >> 5));
-       rr = calloc(sizeof(uint32_t), 1 + (((*prop)->num_bits * 2) >> 5));
+       n = calloc(sizeof(uint32_t), 1 + (((*prop)->num_bits + 31) >> 5));
+       rr = calloc(sizeof(uint32_t), 1 + ((((*prop)->num_bits * 2) + 31) >> 
5));
        rrtmp = calloc(sizeof(uint32_t), 2 + (((*prop)->num_bits * 2) >> 5));
        if (!n || !rr || !rrtmp) {
                ret = -ENOMEM;
-- 
2.43.0

Reply via email to