Blame SOURCES/0011-CVE-2019-7637-Fix-in-integer-overflow-in-SDL_Calcula.patch

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