diff options
author | Claudio Imbrenda <imbrenda@linux.ibm.com> | 2020-06-22 18:21:37 +0200 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2020-06-22 13:48:04 -0400 |
commit | cde8415e148df178726a2d6913f4299dcaa65f11 (patch) | |
tree | 5a93a6795c6b3fd28367b9a64a51947673824314 | |
parent | 6ea7326a9de006edca66e342959b78c1fb4b776f (diff) | |
download | kvm-unit-tests-cde8415e148df178726a2d6913f4299dcaa65f11.tar.gz |
lib/alloc.c: add overflow check for calloc
Add an overflow check for calloc to prevent potential multiplication overflow.
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-Id: <20200622162141.279716-5-imbrenda@linux.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | lib/alloc.c | 36 |
1 files changed, 35 insertions, 1 deletions
diff --git a/lib/alloc.c b/lib/alloc.c index ed8f5f9..f4aa87a 100644 --- a/lib/alloc.c +++ b/lib/alloc.c @@ -6,9 +6,43 @@ void *malloc(size_t size) return memalign(sizeof(long), size); } +static bool mult_overflow(size_t a, size_t b) +{ +#if BITS_PER_LONG == 32 + /* 32 bit system, easy case: just use u64 */ + return (u64)a * (u64)b >= (1ULL << 32); +#else +#ifdef __SIZEOF_INT128__ + /* if __int128 is available use it (like the u64 case above) */ + unsigned __int128 res = a; + res *= b; + res >>= 64; + return res != 0; +#else + u64 tmp; + + if ((a >> 32) && (b >> 32)) + return true; + if (!(a >> 32) && !(b >> 32)) + return false; + tmp = (u32)a; + tmp *= (u32)b; + tmp >>= 32; + if (a < b) + tmp += a * (b >> 32); + else + tmp += b * (a >> 32); + return tmp >> 32; +#endif /* __SIZEOF_INT128__ */ +#endif /* BITS_PER_LONG == 32 */ +} + void *calloc(size_t nmemb, size_t size) { - void *ptr = malloc(nmemb * size); + void *ptr; + + assert(!mult_overflow(nmemb, size)); + ptr = malloc(nmemb * size); if (ptr) memset(ptr, 0, nmemb * size); return ptr; |