SDL: video: Detect and reject nonsense SDL_surface dimensions

From 535fdc3adcdc08a193ab0d45540014fd536cf251 Mon Sep 17 00:00:00 2001
From: Simon McVittie <[EMAIL REDACTED]>
Date: Tue, 10 May 2022 10:34:41 +0100
Subject: [PATCH] video: Detect and reject nonsense SDL_surface dimensions

Signed-off-by: Simon McVittie <smcv@collabora.com>
---
 src/video/SDL_surface.c | 70 ++++++++++++++++++++++++++++++++++++-----
 1 file changed, 63 insertions(+), 7 deletions(-)

diff --git a/src/video/SDL_surface.c b/src/video/SDL_surface.c
index cc2085689ec..b2b52370073 100644
--- a/src/video/SDL_surface.c
+++ b/src/video/SDL_surface.c
@@ -42,7 +42,7 @@ SDL_COMPILE_TIME_ASSERT(can_indicate_overflow, SDL_SIZE_MAX > SDL_MAX_SINT32);
  * Return SDL_SIZE_MAX on overflow.
  */
 static size_t
-SDL_CalculatePitch(Uint32 format, size_t width)
+SDL_CalculatePitch(Uint32 format, size_t width, SDL_bool minimal)
 {
     size_t pitch;
 
@@ -59,11 +59,13 @@ SDL_CalculatePitch(Uint32 format, size_t width)
         }
         pitch /= 8;
     }
-    /* 4-byte aligning for speed */
-    if (SDL_size_add_overflow(pitch, 3, &pitch)) {
-        return SDL_SIZE_MAX;
+    if (!minimal) {
+        /* 4-byte aligning for speed */
+        if (SDL_size_add_overflow(pitch, 3, &pitch)) {
+            return SDL_SIZE_MAX;
+        }
+        pitch &= ~3;
     }
-    pitch &= ~3;
     return pitch;
 }
 
@@ -81,7 +83,17 @@ SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int width, int height, int depth,
     /* The flags are no longer used, make the compiler happy */
     (void)flags;
 
-    pitch = SDL_CalculatePitch(format, width);
+    if (width < 0) {
+        SDL_InvalidParamError("width");
+        return NULL;
+    }
+
+    if (height < 0) {
+        SDL_InvalidParamError("height");
+        return NULL;
+    }
+
+    pitch = SDL_CalculatePitch(format, width, SDL_FALSE);
     if (pitch > SDL_MAX_SINT32) {
         /* Overflow... */
         SDL_OutOfMemory();
@@ -194,8 +206,34 @@ SDL_CreateRGBSurfaceFrom(void *pixels,
                          Uint32 Amask)
 {
     SDL_Surface *surface;
+    Uint32 format;
+    size_t minimalPitch;
 
-    surface = SDL_CreateRGBSurface(0, 0, 0, depth, Rmask, Gmask, Bmask, Amask);
+    if (width < 0) {
+        SDL_InvalidParamError("width");
+        return NULL;
+    }
+
+    if (height < 0) {
+        SDL_InvalidParamError("height");
+        return NULL;
+    }
+
+    format = SDL_MasksToPixelFormatEnum(depth, Rmask, Gmask, Bmask, Amask);
+
+    if (format == SDL_PIXELFORMAT_UNKNOWN) {
+        SDL_SetError("Unknown pixel format");
+        return NULL;
+    }
+
+    minimalPitch = SDL_CalculatePitch(format, width, SDL_TRUE);
+
+    if (pitch < 0 || ((size_t) pitch) < minimalPitch) {
+        SDL_InvalidParamError("pitch");
+        return NULL;
+    }
+
+    surface = SDL_CreateRGBSurfaceWithFormat(0, 0, 0, depth, format);
     if (surface != NULL) {
         surface->flags |= SDL_PREALLOC;
         surface->pixels = pixels;
@@ -217,6 +255,24 @@ SDL_CreateRGBSurfaceWithFormatFrom(void *pixels,
                          Uint32 format)
 {
     SDL_Surface *surface;
+    size_t minimalPitch;
+
+    if (width < 0) {
+        SDL_InvalidParamError("width");
+        return NULL;
+    }
+
+    if (height < 0) {
+        SDL_InvalidParamError("height");
+        return NULL;
+    }
+
+    minimalPitch = SDL_CalculatePitch(format, width, SDL_TRUE);
+
+    if (pitch < 0 || ((size_t) pitch) < minimalPitch) {
+        SDL_InvalidParamError("pitch");
+        return NULL;
+    }
 
     surface = SDL_CreateRGBSurfaceWithFormat(0, 0, 0, depth, format);
     if (surface != NULL) {