]> xenbits.xensource.com Git - people/sstabellini/xen-unstable.git/.git/commitdiff
xmalloc: add a Kconfig option to poison free pool memory
authorPaul Durrant <paul.durrant@citrix.com>
Mon, 8 Jul 2019 08:31:35 +0000 (10:31 +0200)
committerJan Beulich <jbeulich@suse.com>
Mon, 8 Jul 2019 08:31:35 +0000 (10:31 +0200)
This patch adds XMEM_POOL_POISON to the Kconfig DEBUG options. If set,
free blocks (greater than MIN_BLOCK_SIZE) will be poisoned with 0xAA
bytes which will then be verified when memory is subsequently allocated.
This can help in spotting heap corruption, particularly use-after-free.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
xen/Kconfig.debug
xen/common/string.c
xen/common/xmalloc_tlsf.c
xen/include/xen/string.h

index daacf85141a916b74df67b58aa37f419fff7a157..e10e314e259efe4c802716206acb49e3f8072a04 100644 (file)
@@ -105,6 +105,13 @@ config DEBUG_TRACE
          either directly to the console or are printed to console in case of
          a system crash.
 
+config XMEM_POOL_POISON
+       bool "Poison free xenpool blocks"
+       default DEBUG
+       ---help---
+         Poison free blocks with 0xAA bytes and verify them when a block is
+         allocated in order to spot use-after-free issues.
+
 endif # DEBUG || EXPERT
 
 endmenu
index a2bbe7dc97beba001ae701c1078c51d7f9fed15e..af3d96ad0fa3a07fd4fc5ae48a2e859bbc080bcc 100644 (file)
@@ -423,6 +423,26 @@ void *(memchr)(const void *s, int c, size_t n)
 }
 #endif
 
+/**
+ * memchr_inv - Find an unmatching character in an area of memory.
+ * @s: The memory area
+ * @c: The byte that is expected
+ * @n: The size of the area.
+ *
+ * returns the address of the first occurrence of a character other than @c,
+ * or %NULL if the whole buffer contains just @c.
+ */
+void *memchr_inv(const void *s, int c, size_t n)
+{
+       const unsigned char *p = s;
+
+       while (n--)
+               if ((unsigned char)c != *p++)
+                       return (void *)(p - 1);
+
+       return NULL;
+}
+
 /*
  * Local variables:
  * mode: C
index e4e476a27cde167594ad51797a8023aa19a2cec8..e98ad65455e6391f618623a393a779afb2af41a5 100644 (file)
@@ -215,6 +215,8 @@ static inline void EXTRACT_BLOCK_HDR(struct bhdr *b, struct xmem_pool *p, int fl
     b->ptr.free_ptr = (struct free_ptr) {NULL, NULL};
 }
 
+#define POISON_BYTE 0xAA
+
 /**
  * Removes block(b) from free list with indexes (fl, sl)
  */
@@ -238,6 +240,12 @@ static inline void EXTRACT_BLOCK(struct bhdr *b, struct xmem_pool *p, int fl,
         }
     }
     b->ptr.free_ptr = (struct free_ptr) {NULL, NULL};
+
+#ifdef CONFIG_XMEM_POOL_POISON
+    if ( (b->size & BLOCK_SIZE_MASK) > MIN_BLOCK_SIZE )
+        ASSERT(!memchr_inv(b->ptr.buffer + MIN_BLOCK_SIZE, POISON_BYTE,
+                           (b->size & BLOCK_SIZE_MASK) - MIN_BLOCK_SIZE));
+#endif /* CONFIG_XMEM_POOL_POISON */
 }
 
 /**
@@ -245,6 +253,12 @@ static inline void EXTRACT_BLOCK(struct bhdr *b, struct xmem_pool *p, int fl,
  */
 static inline void INSERT_BLOCK(struct bhdr *b, struct xmem_pool *p, int fl, int sl)
 {
+#ifdef CONFIG_XMEM_POOL_POISON
+    if ( (b->size & BLOCK_SIZE_MASK) > MIN_BLOCK_SIZE )
+        memset(b->ptr.buffer + MIN_BLOCK_SIZE, POISON_BYTE,
+               (b->size & BLOCK_SIZE_MASK) - MIN_BLOCK_SIZE);
+#endif /* CONFIG_XMEM_POOL_POISON */
+
     b->ptr.free_ptr = (struct free_ptr) {NULL, p->matrix[fl][sl]};
     if ( p->matrix[fl][sl] )
         p->matrix[fl][sl]->ptr.free_ptr.prev = b;
index 711cb60a7de69867e486ce03ac6c42f86eb4d208..4b3b57e74fbd125c9918e6ac1bd792be0fd88874 100644 (file)
@@ -106,6 +106,8 @@ void *memchr(const void *, int, size_t);
 #define memchr(s, c, n) __builtin_memchr(s, c, n)
 #endif
 
+void *memchr_inv(const void *, int, size_t);
+
 #define is_char_array(x) __builtin_types_compatible_p(typeof(x), char[])
 
 /* safe_xxx always NUL-terminates and returns !=0 if result is truncated. */