[Pixman] [PATCH 1/5] Add fence_malloc() and fence_free().

Soeren Sandmann sandmann at daimi.au.dk
Mon Sep 20 14:58:03 PDT 2010


Siarhei Siamashka <siarhei.siamashka at gmail.com> writes:

> There is the following warning in mprotect man page: "SVr4, POSIX.1-2001.  
> POSIX says that the behavior of mprotect() is unspecified if it is applied to a 
> region of memory that was not obtained via mmap(2)."

Yeah, new patch below.

> Also I wonder if it makes sense to be able to configure whether to align 
> allocated memory blocks at the lower or upper page boundary?

It probably makes sense to do that at some point. It could even
randomize the alignment.

Thanks,
Soren


commit 891869b6cb4f5c7fc7a417b1fbf1023d3d5c2406
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Mon Sep 13 14:34:34 2010 -0400

    Add fence_malloc() and fence_free().
    
    These variants of malloc() and free() try to surround the allocated
    memory with protected pages so that out-of-bounds accessess will cause
    a segmentation fault.
    
    If mprotect() and getpagesize() are not available, these functions are
    simply equivalent to malloc() and free().

diff --git a/configure.ac b/configure.ac
index dbff2a6..d3b71fa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -623,6 +623,19 @@ if test x$have_alarm = xyes; then
    AC_DEFINE(HAVE_ALARM, 1, [Whether we have alarm()])
 fi
 
+AC_CHECK_HEADER([sys/mman.h],
+   [AC_DEFINE(HAVE_SYS_MMAN_H, [1], [Define to 1 if we have <sys/mman.h>])])
+
+AC_CHECK_FUNC(mprotect, have_mprotect=yes, have_mprotect=no)
+if test x$have_mprotect = xyes; then
+   AC_DEFINE(HAVE_MPROTECT, 1, [Whether we have mprotect()])
+fi
+
+AC_CHECK_FUNC(getpagesize, have_getpagesize=yes, have_getpagesize=no)
+if test x$have_getpagesize = xyes; then
+   AC_DEFINE(HAVE_GETPAGESIZE, 1, [Whether we have getpagesize()])
+fi
+
 dnl =====================================
 dnl Thread local storage
 
diff --git a/test/utils.c b/test/utils.c
index d95cbc2..580a51d 100644
--- a/test/utils.c
+++ b/test/utils.c
@@ -5,6 +5,10 @@
 #include <unistd.h>
 #endif
 
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
 /* Random number seed
  */
 
@@ -197,10 +201,112 @@ image_endian_swap (pixman_image_t *img, int bpp)
     }
 }
 
+#define N_LEADING_PROTECTED	10
+#define N_TRAILING_PROTECTED	10
+
+typedef struct
+{
+    void *addr;
+    uint32_t len;
+    uint8_t *trailing;
+    int n_bytes;
+} info_t;
+
+#if defined(HAVE_MPROTECT) && defined(HAVE_GETPAGESIZE)
+
+void *
+fence_malloc (uint32_t len)
+{
+    unsigned long page_size = getpagesize();
+    unsigned long page_mask = page_size - 1;
+    uint32_t n_payload_bytes = (len + page_mask) & ~page_mask;
+    uint32_t n_bytes =
+	(page_size * (N_LEADING_PROTECTED + N_TRAILING_PROTECTED + 2) +
+	 n_payload_bytes) & ~page_mask;
+    uint8_t *initial_page;
+    uint8_t *leading_protected;
+    uint8_t *trailing_protected;
+    uint8_t *payload;
+    uint8_t *addr;
+
+    addr = mmap (NULL, n_bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
+		 -1, 0);
+
+    if (addr == (void *)MAP_FAILED)
+    {
+	printf ("mmap failed on %u %u\n", len, n_bytes);
+	return NULL;
+    }
+
+    initial_page = (uint8_t *)(((unsigned long)addr + page_mask) & ~page_mask);
+    leading_protected = initial_page + page_size;
+    payload = leading_protected + N_LEADING_PROTECTED * page_size;
+    trailing_protected = payload + n_payload_bytes;
+
+    ((info_t *)initial_page)->addr = addr;
+    ((info_t *)initial_page)->len = len;
+    ((info_t *)initial_page)->trailing = trailing_protected;
+    ((info_t *)initial_page)->n_bytes = n_bytes;
+
+    if (mprotect (leading_protected, N_LEADING_PROTECTED * page_size,
+		  PROT_NONE) == -1)
+    {
+	free (addr);
+	return NULL;
+    }
+
+    if (mprotect (trailing_protected, N_TRAILING_PROTECTED * page_size,
+		  PROT_NONE) == -1)
+    {
+	mprotect (leading_protected, N_LEADING_PROTECTED * page_size,
+		  PROT_READ | PROT_WRITE);
+
+	free (addr);
+	return NULL;
+    }
+
+    return payload;
+}
+
+void
+fence_free (void *data)
+{
+    uint32_t page_size = getpagesize();
+    uint8_t *payload = data;
+    uint8_t *leading_protected = payload - N_LEADING_PROTECTED * page_size;
+    uint8_t *initial_page = leading_protected - page_size;
+    info_t *info = (info_t *)initial_page;
+    uint8_t *trailing_protected = info->trailing;
+
+    mprotect (leading_protected, N_LEADING_PROTECTED * page_size,
+	      PROT_READ | PROT_WRITE);
+
+    mprotect (trailing_protected, N_LEADING_PROTECTED * page_size,
+	      PROT_READ | PROT_WRITE);
+
+    munmap (info->addr, info->n_bytes);
+}
+
+#else
+
+void *
+fence_malloc (uint32_t len)
+{
+    return malloc (len);
+}
+
+void
+fence_free (void *data)
+{
+    free (data);
+}
+
+#endif
+
 uint8_t *
 make_random_bytes (int n_bytes)
 {
-    uint8_t *bytes = malloc (n_bytes);
+    uint8_t *bytes = fence_malloc (n_bytes);
     int i;
 
     if (!bytes)
diff --git a/test/utils.h b/test/utils.h
index a39af02..14e3c8b 100644
--- a/test/utils.h
+++ b/test/utils.h
@@ -51,7 +51,16 @@ compute_crc32 (uint32_t    in_crc32,
 void
 image_endian_swap (pixman_image_t *img, int bpp);
 
-/* Generate n_bytes random bytes in malloced memory */
+/* Allocate memory that is bounded by protected pages,
+ * so that out-of-bounds access will cause segfaults
+ */
+void *
+fence_malloc (uint32_t len);
+
+void
+fence_free (void *data);
+
+/* Generate n_bytes random bytes in fence_malloced memory */
 uint8_t *
 make_random_bytes (int n_bytes);
 


More information about the Pixman mailing list