[SDL] [proposal] use mprotect() in code generation

Sam Hocevar sam at zoy.org
Wed Mar 1 15:01:42 PST 2006


   This patch uses mprotect() on the page containing the dynamically
generated code from SDL_stretch.c. It is useful on systems that enforce
a security policy such as forbidding writable pages to be executed.

   Ideally this patch should check for various headers on the system at
the configure step, but I just hardcoded a #ifdef __linux__ test for
now. Let me know if there is interest in it and I will send a polished
patch.

Regards,
-- 
Sam.
-------------- next part --------------
diff -puriN SDL-1.2.9.orig/src/video/SDL_stretch.c SDL-1.2.9/src/video/SDL_stretch.c
--- SDL-1.2.9.orig/src/video/SDL_stretch.c	2004-05-16 23:08:55 +0200
+++ SDL-1.2.9/src/video/SDL_stretch.c	2006-03-01 13:28:46 +0100
@@ -43,10 +43,23 @@ static char rcsid =
      !defined(__WATCOMC__) && !defined(__LCC__) && !defined(__FREEBCC__)) || \
     (defined(i386) && defined(__GNUC__) && defined(USE_ASMBLIT))
 #define USE_ASM_STRETCH
+#if defined(__linux__)
+#define USE_MPROTECT
+#endif
 #endif
 
 #ifdef USE_ASM_STRETCH
 
+#ifdef USE_MPROTECT
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+#ifndef PAGESIZE
+#define PAGESIZE 4096
+#endif
+#include <sys/mman.h>
+#endif
+
 #if defined(WIN32) || defined(i386)
 #define PREFIX16	0x66
 #define STORE_BYTE	0xAA
@@ -58,10 +71,16 @@ static char rcsid =
 #error Need assembly opcodes for this architecture
 #endif
 
+#define MAX_CODE_LENGTH 4096
+
 #if defined(__ELF__) && defined(__GNUC__)
-extern unsigned char _copy_row[4096] __attribute__ ((alias ("copy_row")));
+extern unsigned char *_copy_row __attribute__ ((alias ("copy_row")));
+#endif
+#ifdef USE_MPROTECT
+static unsigned char *copy_row;
+#else
+static unsigned char copy_row[MAX_CODE_LENGTH];
 #endif
-static unsigned char copy_row[4096];
 
 static int generate_rowbytes(int src_w, int dst_w, int bpp)
 {
@@ -70,12 +89,25 @@ static int generate_rowbytes(int src_w, 
 		int src_w;
 		int dst_w;
 	} last;
+#ifdef USE_MPROTECT
+	static unsigned char *code_buffer;
+#endif
 
 	int i;
 	int pos, inc;
 	unsigned char *eip;
 	unsigned char load, store;
 
+#ifdef USE_MPROTECT
+	if ( ! copy_row ) {
+		code_buffer = malloc(MAX_CODE_LENGTH + PAGESIZE - 1);
+		if ( ! code_buffer ) {
+			return(-1);
+		}
+		copy_row = (unsigned char *)(((uintptr_t)code_buffer + PAGESIZE - 1) & ~(uintptr_t)(PAGESIZE - 1));
+	}
+#endif
+
 	/* See if we need to regenerate the copy buffer */
 	if ( (src_w == last.src_w) &&
 	     (dst_w == last.dst_w) && (bpp == last.bpp) ) {
@@ -99,6 +131,9 @@ static int generate_rowbytes(int src_w, 
 		SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp);
 		return(-1);
 	}
+#ifdef USE_MPROTECT
+	mprotect(copy_row, MAX_CODE_LENGTH, PROT_READ|PROT_WRITE);
+#endif
 	pos = 0x10000;
 	inc = (src_w << 16) / dst_w;
 	eip = copy_row;
@@ -119,10 +154,13 @@ static int generate_rowbytes(int src_w, 
 	*eip++ = RETURN;
 
 	/* Verify that we didn't overflow (too late) */
-	if ( eip > (copy_row+sizeof(copy_row)) ) {
+	if ( eip > (copy_row+MAX_CODE_LENGTH) ) {
 		SDL_SetError("Copy buffer overflow");
 		return(-1);
 	}
+#ifdef USE_MPROTECT
+	mprotect(copy_row, MAX_CODE_LENGTH, PROT_READ|PROT_EXEC);
+#endif
 	return(0);
 }
 
@@ -284,15 +322,20 @@ int SDL_SoftStretch(SDL_Surface *src, SD
 			copy_row3(srcp, srcrect->w, dstp, dstrect->w);
 			break;
 		    default:
+		{
+#ifdef USE_MPROTECT
+			void *code = copy_row;
+#else
+			void *code = &copy_row;
+#endif
 #ifdef __GNUC__
 			__asm__ __volatile__ (
-			"call _copy_row"
+			"call %4"
 			: "=&D" (u1), "=&S" (u2)
-			: "0" (dstp), "1" (srcp)
+			: "0" (dstp), "1" (srcp), "r" (code)
 			: "memory" );
 #else
 #ifdef WIN32
-		{ void *code = &copy_row;
 			__asm {
 				push edi
 				push esi
@@ -304,11 +347,11 @@ int SDL_SoftStretch(SDL_Surface *src, SD
 				pop esi
 				pop edi
 			}
-		}
 #else
 #error Need inline assembly for this compiler
 #endif
 #endif /* __GNUC__ */
+		}
 			break;
 		}
 #else


More information about the SDL mailing list