aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClaudio Imbrenda <imbrenda@linux.ibm.com>2020-06-22 18:21:37 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2020-06-22 13:48:04 -0400
commitcde8415e148df178726a2d6913f4299dcaa65f11 (patch)
tree5a93a6795c6b3fd28367b9a64a51947673824314
parent6ea7326a9de006edca66e342959b78c1fb4b776f (diff)
downloadkvm-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.c36
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;