6ed69d
From 7cafd3e820489f17f86d0d897ad9719ef54599f1 Mon Sep 17 00:00:00 2001
6ed69d
From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
6ed69d
Date: Mon, 18 Feb 2019 13:53:16 +0100
6ed69d
Subject: [PATCH 11/11] CVE-2019-7637: Fix in integer overflow in
6ed69d
 SDL_CalculatePitch
6ed69d
MIME-Version: 1.0
6ed69d
Content-Type: text/plain; charset=UTF-8
6ed69d
Content-Transfer-Encoding: 8bit
6ed69d
6ed69d
If a too large width is passed to SDL_SetVideoMode() the width travels
6ed69d
to SDL_CalculatePitch() where the width (e.g. 65535) is multiplied by
6ed69d
BytesPerPixel (e.g. 4) and the result is stored into Uint16 pitch
6ed69d
variable. During this arithmetics an integer overflow can happen (e.g.
6ed69d
the value is clamped as 65532). As a result SDL_Surface with a pitch
6ed69d
smaller than width * BytesPerPixel is created, too small pixel buffer
6ed69d
is allocated and when the SDL_Surface is processed in SDL_FillRect()
6ed69d
a buffer overflow occurs.
6ed69d
6ed69d
This can be reproduced with "./graywin -width 21312312313123213213213"
6ed69d
command.
6ed69d
6ed69d
This patch fixes is by using a very careful arithmetics in
6ed69d
SDL_CalculatePitch(). If an overflow is detected, an error is reported
6ed69d
back as a special 0 value. We assume that 0-width surfaces do not
6ed69d
occur in the wild. Since SDL_CalculatePitch() is a private function,
6ed69d
we can change the semantics.
6ed69d
6ed69d
CVE-2019-7637
6ed69d
https://bugzilla.libsdl.org/show_bug.cgi?id=4497
6ed69d
6ed69d
Signed-off-by: Petr Písař <ppisar@redhat.com>
6ed69d
---
6ed69d
 src/video/SDL_pixels.c          | 41 +++++++++++++++++++++++++++------
6ed69d
 src/video/gapi/SDL_gapivideo.c  |  3 +++
6ed69d
 src/video/nanox/SDL_nxvideo.c   |  4 ++++
6ed69d
 src/video/ps2gs/SDL_gsvideo.c   |  3 +++
6ed69d
 src/video/ps3/SDL_ps3video.c    |  3 +++
6ed69d
 src/video/windib/SDL_dibvideo.c |  3 +++
6ed69d
 src/video/windx5/SDL_dx5video.c |  3 +++
6ed69d
 src/video/x11/SDL_x11video.c    |  4 ++++
6ed69d
 8 files changed, 57 insertions(+), 7 deletions(-)
6ed69d
6ed69d
diff --git a/src/video/SDL_pixels.c b/src/video/SDL_pixels.c
6ed69d
index 1a7fd518f..44626b749 100644
6ed69d
--- a/src/video/SDL_pixels.c
6ed69d
+++ b/src/video/SDL_pixels.c
6ed69d
@@ -286,26 +286,53 @@ void SDL_DitherColors(SDL_Color *colors, int bpp)
6ed69d
 	}
6ed69d
 }
6ed69d
 /* 
6ed69d
- * Calculate the pad-aligned scanline width of a surface
6ed69d
+ * Calculate the pad-aligned scanline width of a surface. Return 0 in case of
6ed69d
+ * an error.
6ed69d
  */
6ed69d
 Uint16 SDL_CalculatePitch(SDL_Surface *surface)
6ed69d
 {
6ed69d
-	Uint16 pitch;
6ed69d
+	unsigned int pitch = 0;
6ed69d
 
6ed69d
 	/* Surface should be 4-byte aligned for speed */
6ed69d
-	pitch = surface->w*surface->format->BytesPerPixel;
6ed69d
+	/* The code tries to prevent from an Uint16 overflow. */;
6ed69d
+	for (Uint8 byte = surface->format->BytesPerPixel; byte; byte--) {
6ed69d
+		pitch += (unsigned int)surface->w;
6ed69d
+		if (pitch < surface->w) {
6ed69d
+			SDL_SetError("A scanline is too wide");
6ed69d
+			return(0);
6ed69d
+		}
6ed69d
+	}
6ed69d
 	switch (surface->format->BitsPerPixel) {
6ed69d
 		case 1:
6ed69d
-			pitch = (pitch+7)/8;
6ed69d
+			if (pitch % 8) {
6ed69d
+				pitch = pitch / 8 + 1;
6ed69d
+			} else {
6ed69d
+				pitch = pitch / 8;
6ed69d
+			}
6ed69d
 			break;
6ed69d
 		case 4:
6ed69d
-			pitch = (pitch+1)/2;
6ed69d
+			if (pitch % 2) {
6ed69d
+				pitch = pitch / 2 + 1;
6ed69d
+			} else {
6ed69d
+				pitch = pitch / 2;
6ed69d
+			}
6ed69d
 			break;
6ed69d
 		default:
6ed69d
 			break;
6ed69d
 	}
6ed69d
-	pitch = (pitch + 3) & ~3;	/* 4-byte aligning */
6ed69d
-	return(pitch);
6ed69d
+	/* 4-byte aligning */
6ed69d
+	if (pitch & 3) {
6ed69d
+		if (pitch + 3 < pitch) {
6ed69d
+			SDL_SetError("A scanline is too wide");
6ed69d
+			return(0);
6ed69d
+		}
6ed69d
+		pitch = (pitch + 3) & ~3;
6ed69d
+	}
6ed69d
+	if (pitch > 0xFFFF) {
6ed69d
+		SDL_SetError("A scanline is too wide");
6ed69d
+		return(0);
6ed69d
+	}
6ed69d
+	return((Uint16)pitch);
6ed69d
 }
6ed69d
 /*
6ed69d
  * Match an RGB value to a particular palette index
6ed69d
diff --git a/src/video/gapi/SDL_gapivideo.c b/src/video/gapi/SDL_gapivideo.c
6ed69d
index 86deadc75..8a0648536 100644
6ed69d
--- a/src/video/gapi/SDL_gapivideo.c
6ed69d
+++ b/src/video/gapi/SDL_gapivideo.c
6ed69d
@@ -733,6 +733,9 @@ SDL_Surface *GAPI_SetVideoMode(_THIS, SDL_Surface *current,
6ed69d
 	video->w = gapi->w = width;
6ed69d
 	video->h = gapi->h = height;
6ed69d
 	video->pitch = SDL_CalculatePitch(video); 
6ed69d
+	if (!current->pitch) {
6ed69d
+		return(NULL);
6ed69d
+	}
6ed69d
 
6ed69d
 	/* Small fix for WinCE/Win32 - when activating window
6ed69d
 	   SDL_VideoSurface is equal to zero, so activating code
6ed69d
diff --git a/src/video/nanox/SDL_nxvideo.c b/src/video/nanox/SDL_nxvideo.c
6ed69d
index b188e0958..cbdd09a08 100644
6ed69d
--- a/src/video/nanox/SDL_nxvideo.c
6ed69d
+++ b/src/video/nanox/SDL_nxvideo.c
6ed69d
@@ -378,6 +378,10 @@ SDL_Surface * NX_SetVideoMode (_THIS, SDL_Surface * current,
6ed69d
         current -> w = width ;
6ed69d
         current -> h = height ;
6ed69d
         current -> pitch = SDL_CalculatePitch (current) ;
6ed69d
+        if (!current->pitch) {
6ed69d
+            current = NULL;
6ed69d
+            goto done;
6ed69d
+        }
6ed69d
         NX_ResizeImage (this, current, flags) ;
6ed69d
     }
6ed69d
 
6ed69d
diff --git a/src/video/ps2gs/SDL_gsvideo.c b/src/video/ps2gs/SDL_gsvideo.c
6ed69d
index e172c60dc..329086680 100644
6ed69d
--- a/src/video/ps2gs/SDL_gsvideo.c
6ed69d
+++ b/src/video/ps2gs/SDL_gsvideo.c
6ed69d
@@ -479,6 +479,9 @@ static SDL_Surface *GS_SetVideoMode(_THIS, SDL_Surface *current,
6ed69d
 	current->w = width;
6ed69d
 	current->h = height;
6ed69d
 	current->pitch = SDL_CalculatePitch(current);
6ed69d
+	if (!current->pitch) {
6ed69d
+		return(NULL);
6ed69d
+	}
6ed69d
 
6ed69d
 	/* Memory map the DMA area for block memory transfer */
6ed69d
 	if ( ! mapped_mem ) {
6ed69d
diff --git a/src/video/ps3/SDL_ps3video.c b/src/video/ps3/SDL_ps3video.c
6ed69d
index d5519e051..17848e33a 100644
6ed69d
--- a/src/video/ps3/SDL_ps3video.c
6ed69d
+++ b/src/video/ps3/SDL_ps3video.c
6ed69d
@@ -339,6 +339,9 @@ static SDL_Surface *PS3_SetVideoMode(_THIS, SDL_Surface * current, int width, in
6ed69d
 	current->w = width;
6ed69d
 	current->h = height;
6ed69d
 	current->pitch = SDL_CalculatePitch(current);
6ed69d
+	if (!current->pitch) {
6ed69d
+		return(NULL);
6ed69d
+	}
6ed69d
 
6ed69d
 	/* Alloc aligned mem for current->pixels */
6ed69d
 	s_pixels = memalign(16, current->h * current->pitch);
6ed69d
diff --git a/src/video/windib/SDL_dibvideo.c b/src/video/windib/SDL_dibvideo.c
6ed69d
index 6187bfcf7..86ebb12a3 100644
6ed69d
--- a/src/video/windib/SDL_dibvideo.c
6ed69d
+++ b/src/video/windib/SDL_dibvideo.c
6ed69d
@@ -675,6 +675,9 @@ SDL_Surface *DIB_SetVideoMode(_THIS, SDL_Surface *current,
6ed69d
 	video->w = width;
6ed69d
 	video->h = height;
6ed69d
 	video->pitch = SDL_CalculatePitch(video);
6ed69d
+	if (!current->pitch) {
6ed69d
+		return(NULL);
6ed69d
+	}
6ed69d
 
6ed69d
 	/* Small fix for WinCE/Win32 - when activating window
6ed69d
 	   SDL_VideoSurface is equal to zero, so activating code
6ed69d
diff --git a/src/video/windx5/SDL_dx5video.c b/src/video/windx5/SDL_dx5video.c
6ed69d
index f80ca97b0..39fc4fc37 100644
6ed69d
--- a/src/video/windx5/SDL_dx5video.c
6ed69d
+++ b/src/video/windx5/SDL_dx5video.c
6ed69d
@@ -1127,6 +1127,9 @@ SDL_Surface *DX5_SetVideoMode(_THIS, SDL_Surface *current,
6ed69d
 		video->w = width;
6ed69d
 		video->h = height;
6ed69d
 		video->pitch = SDL_CalculatePitch(video);
6ed69d
+		if (!current->pitch) {
6ed69d
+			return(NULL);
6ed69d
+		}
6ed69d
 
6ed69d
 #ifndef NO_CHANGEDISPLAYSETTINGS
6ed69d
 		/* Set fullscreen mode if appropriate.
6ed69d
diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c
6ed69d
index 79e60f971..45d1f79be 100644
6ed69d
--- a/src/video/x11/SDL_x11video.c
6ed69d
+++ b/src/video/x11/SDL_x11video.c
6ed69d
@@ -1220,6 +1220,10 @@ SDL_Surface *X11_SetVideoMode(_THIS, SDL_Surface *current,
6ed69d
 		current->w = width;
6ed69d
 		current->h = height;
6ed69d
 		current->pitch = SDL_CalculatePitch(current);
6ed69d
+		if (!current->pitch) {
6ed69d
+			current = NULL;
6ed69d
+			goto done;
6ed69d
+		}
6ed69d
 		if (X11_ResizeImage(this, current, flags) < 0) {
6ed69d
 			current = NULL;
6ed69d
 			goto done;
6ed69d
-- 
6ed69d
2.21.0
6ed69d