SDL: cpuinfo: Check for overflow in SIMD allocation

From 2a7948016a637136b5cb2d2d00494db653a8261f Mon Sep 17 00:00:00 2001
From: Simon McVittie <[EMAIL REDACTED]>
Date: Mon, 9 May 2022 14:58:51 +0100
Subject: [PATCH] cpuinfo: Check for overflow in SIMD allocation

If the size to be allocated is very large and untrusted, then adding
the padding etc. might be enough to cause unsigned overflow, after
which a very small amount of memory will be allocated.

Signed-off-by: Simon McVittie <smcv@collabora.com>
---
 src/cpuinfo/SDL_cpuinfo.c | 22 ++++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/src/cpuinfo/SDL_cpuinfo.c b/src/cpuinfo/SDL_cpuinfo.c
index 53b6366d041..cc383ad28ec 100644
--- a/src/cpuinfo/SDL_cpuinfo.c
+++ b/src/cpuinfo/SDL_cpuinfo.c
@@ -1059,9 +1059,17 @@ SDL_SIMDAlloc(const size_t len)
 {
     const size_t alignment = SDL_SIMDGetAlignment();
     const size_t padding = (alignment - (len % alignment)) % alignment;
-    const size_t padded = len + padding;
     Uint8 *retval = NULL;
-    Uint8 *ptr = (Uint8 *) SDL_malloc(padded + alignment + sizeof (void *));
+    Uint8 *ptr;
+    size_t to_allocate;
+
+    /* alignment + padding + sizeof (void *) is bounded (a few hundred
+     * bytes max), so no need to check for overflow within that argument */
+    if (SDL_size_add_overflow(len, alignment + padding + sizeof (void *), &to_allocate)) {
+        return NULL;
+    }
+
+    ptr = (Uint8 *) SDL_malloc(to_allocate);
     if (ptr) {
         /* store the actual allocated pointer right before our aligned pointer. */
         retval = ptr + sizeof (void *);
@@ -1076,11 +1084,17 @@ SDL_SIMDRealloc(void *mem, const size_t len)
 {
     const size_t alignment = SDL_SIMDGetAlignment();
     const size_t padding = (alignment - (len % alignment)) % alignment;
-    const size_t padded = len + padding;
     Uint8 *retval = (Uint8*) mem;
     void *oldmem = mem;
     size_t memdiff = 0, ptrdiff;
     Uint8 *ptr;
+    size_t to_allocate;
+
+    /* alignment + padding + sizeof (void *) is bounded (a few hundred
+     * bytes max), so no need to check for overflow within that argument */
+    if (SDL_size_add_overflow(len, alignment + padding + sizeof (void *), &to_allocate)) {
+        return NULL;
+    }
 
     if (mem) {
         void **realptr = (void **) mem;
@@ -1091,7 +1105,7 @@ SDL_SIMDRealloc(void *mem, const size_t len)
         memdiff = ((size_t) oldmem) - ((size_t) mem);
     }
 
-    ptr = (Uint8 *) SDL_realloc(mem, padded + alignment + sizeof (void *));
+    ptr = (Uint8 *) SDL_realloc(mem, to_allocate);
 
     if (ptr == NULL) {
         return NULL; /* Out of memory, bail! */