diff src/video/SDL_stretch.c @ 4109:cd2ab40f1219 SDL-1.2

Made the mprotect() fix for SDL_SoftStretch() more general for hardened linux, etc.
author Sam Lantinga <slouken@libsdl.org>
date Sat, 29 Dec 2007 05:18:33 +0000
parents 3feb94233f90
children a1b03ba2fcd0
line wrap: on
line diff
--- a/src/video/SDL_stretch.c	Sat Dec 29 03:50:29 2007 +0000
+++ b/src/video/SDL_stretch.c	Sat Dec 29 05:18:33 2007 +0000
@@ -42,14 +42,15 @@
 
 #ifdef USE_ASM_STRETCH
 
-/* OpenBSD has non-executable memory by default, so use mprotect() */
-#ifdef __OpenBSD__
-#define USE_MPROTECT
-#endif
-#ifdef USE_MPROTECT
+#ifdef HAVE_MPROTECT
 #include <sys/types.h>
 #include <sys/mman.h>
 #endif
+#ifdef __GNUC__
+#define PAGE_ALIGNED __attribute__((__aligned__(4096)))
+#else
+#define PAGE_ALIGNED
+#endif
 
 #if defined(_M_IX86) || defined(i386)
 #define PREFIX16	0x66
@@ -62,7 +63,7 @@
 #error Need assembly opcodes for this architecture
 #endif
 
-static unsigned char copy_row[4096];
+static unsigned char copy_row[4096] PAGE_ALIGNED;
 
 static int generate_rowbytes(int src_w, int dst_w, int bpp)
 {
@@ -70,6 +71,7 @@
 		int bpp;
 		int src_w;
 		int dst_w;
+		int status;
 	} last;
 
 	int i;
@@ -80,11 +82,12 @@
 	/* See if we need to regenerate the copy buffer */
 	if ( (src_w == last.src_w) &&
 	     (dst_w == last.dst_w) && (bpp == last.bpp) ) {
-		return(0);
+		return(last.status);
 	}
 	last.bpp = bpp;
 	last.src_w = src_w;
 	last.dst_w = dst_w;
+	last.status = -1;
 
 	switch (bpp) {
 	    case 1:
@@ -100,9 +103,6 @@
 		SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp);
 		return(-1);
 	}
-#ifdef USE_MPROTECT
-	mprotect(copy_row, sizeof(copy_row), PROT_READ|PROT_WRITE|PROT_EXEC);
-#endif
 	pos = 0x10000;
 	inc = (src_w << 16) / dst_w;
 	eip = copy_row;
@@ -122,15 +122,23 @@
 	}
 	*eip++ = RETURN;
 
-	/* Verify that we didn't overflow (too late) */
+	/* Verify that we didn't overflow (too late!!!) */
 	if ( eip > (copy_row+sizeof(copy_row)) ) {
 		SDL_SetError("Copy buffer overflow");
 		return(-1);
 	}
+#ifdef HAVE_MPROTECT
+	/* Make the code executable */
+	if ( mprotect(copy_row, sizeof(copy_row), PROT_READ|PROT_WRITE|PROT_EXEC) < 0 ) {
+		SDL_SetError("Couldn't make copy buffer executable");
+		return(-1);
+	}
+#endif
+	last.status = 0;
 	return(0);
 }
 
-#else
+#endif /* USE_ASM_STRETCH */
 
 #define DEFINE_COPY_ROW(name, type)			\
 void name(type *src, int src_w, type *dst, int dst_w)	\
@@ -154,8 +162,6 @@
 DEFINE_COPY_ROW(copy_row2, Uint16)
 DEFINE_COPY_ROW(copy_row4, Uint32)
 
-#endif /* USE_ASM_STRETCH */
-
 /* The ASM code doesn't handle 24-bpp stretch blits */
 void copy_row3(Uint8 *src, int src_w, Uint8 *dst, int dst_w)
 {
@@ -195,9 +201,12 @@
 	Uint8 *dstp;
 	SDL_Rect full_src;
 	SDL_Rect full_dst;
-#if defined(USE_ASM_STRETCH) && defined(__GNUC__)
+#ifdef USE_ASM_STRETCH
+	SDL_bool use_asm = SDL_TRUE;
+#ifdef __GNUC__
 	int u1, u2;
 #endif
+#endif /* USE_ASM_STRETCH */
 	const int bpp = dst->format->BytesPerPixel;
 
 	if ( src->format->BitsPerPixel != dst->format->BitsPerPixel ) {
@@ -266,9 +275,9 @@
 
 #ifdef USE_ASM_STRETCH
 	/* Write the opcodes for this stretch */
-	if ( (bpp != 3) &&
+	if ( (bpp == 3) ||
 	     (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0) ) {
-		return(-1);
+		use_asm = SDL_FALSE;
 	}
 #endif
 
@@ -283,11 +292,7 @@
 			pos -= 0x10000L;
 		}
 #ifdef USE_ASM_STRETCH
-		switch (bpp) {
-		    case 3:
-			copy_row3(srcp, srcrect->w, dstp, dstrect->w);
-			break;
-		    default:
+		if (use_asm) {
 #ifdef __GNUC__
 			__asm__ __volatile__ (
 			"call *%4"
@@ -311,9 +316,8 @@
 #else
 #error Need inline assembly for this compiler
 #endif
-			break;
-		}
-#else
+		} else
+#endif
 		switch (bpp) {
 		    case 1:
 			copy_row1(srcp, srcrect->w, dstp, dstrect->w);
@@ -330,7 +334,6 @@
 			          (Uint32 *)dstp, dstrect->w);
 			break;
 		}
-#endif
 		pos += inc;
 	}