mempool: introduce poison attribute
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Sat, 9 Mar 2024 21:14:54 +0000 (16:14 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Sat, 9 Mar 2024 21:14:54 +0000 (16:14 -0500)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Change-Id: I056c0d8c4f0d5b1d2c401592a08b22ff6f239d11

include/rseq/mempool.h
src/rseq-mempool.c
tests/mempool_test.c

index 0b552dfdf272de0b3dbfd10bad4f834072302915..81884d4593b85536810a94e57f21ebdafdb63b19 100644 (file)
@@ -8,6 +8,7 @@
 #include <stddef.h>
 #include <sys/types.h>
 #include <sys/mman.h>
+#include <stdint.h>
 
 /*
  * rseq/mempool.h: rseq memory pool allocator.
@@ -476,6 +477,18 @@ int rseq_mempool_attr_set_global(struct rseq_mempool_attr *attr, size_t stride);
 int rseq_mempool_attr_set_max_nr_ranges(struct rseq_mempool_attr *attr,
                unsigned long max_nr_ranges);
 
+/*
+ * rseq_mempool_attr_set_poison: Set pool poison value.
+ *
+ * Set a poison value to be set over freed pool entries. This can be
+ * used to anonymize freed memory, and for memory corruption checks
+ * with the robust attribute.
+ *
+ * Returns 0 on success, -1 with errno=EINVAL if arguments are invalid.
+ */
+int rseq_mempool_attr_set_poison(struct rseq_mempool_attr *attr,
+               uintptr_t poison);
+
 /*
  * rseq_mempool_range_init_numa: NUMA initialization helper for memory range.
  *
index bf569a603a2c653c8cb835138ab0d89854374000..a68d1f887cb3c41e494eaee31c831d4b02ab21b6 100644 (file)
@@ -80,6 +80,9 @@ struct rseq_mempool_attr {
        int max_nr_cpus;
 
        unsigned long max_nr_ranges;
+
+       bool poison_set;
+       uintptr_t poison;
 };
 
 struct rseq_mempool_range;
@@ -149,6 +152,23 @@ void rseq_percpu_zero_item(struct rseq_mempool *pool,
        }
 }
 
+static
+void rseq_percpu_poison_item(struct rseq_mempool *pool,
+               struct rseq_mempool_range *range, uintptr_t item_offset)
+{
+       uintptr_t poison = pool->attr.poison;
+       int i;
+
+       for (i = 0; i < pool->attr.max_nr_cpus; i++) {
+               char *p = __rseq_pool_range_percpu_ptr(range, i,
+                               item_offset, pool->attr.stride);
+               size_t offset;
+
+               for (offset = 0; offset < pool->item_len; offset += sizeof(uintptr_t))
+                       *((uintptr_t *) p) = poison;
+       }
+}
+
 #ifdef HAVE_LIBNUMA
 int rseq_mempool_range_init_numa(void *addr, size_t len, int cpu, int numa_flags)
 {
@@ -725,8 +745,14 @@ void librseq_mempool_percpu_free(void __rseq_percpu *_ptr, size_t stride)
        clear_alloc_slot(pool, range, item_offset);
        /* Add ptr to head of free list */
        head = pool->free_list_head;
+       if (pool->attr.poison_set)
+               rseq_percpu_poison_item(pool, range, item_offset);
        /* Free-list is in CPU 0 range. */
        item = (struct free_list_node *) ptr;
+       /*
+        * Setting the next pointer will overwrite the first uintptr_t
+        * poison for CPU 0.
+        */
        item->next = head;
        pool->free_list_head = item;
        pthread_mutex_unlock(&pool->lock);
@@ -919,6 +945,18 @@ int rseq_mempool_attr_set_max_nr_ranges(struct rseq_mempool_attr *attr,
        return 0;
 }
 
+int rseq_mempool_attr_set_poison(struct rseq_mempool_attr *attr,
+               uintptr_t poison)
+{
+       if (!attr) {
+               errno = EINVAL;
+               return -1;
+       }
+       attr->poison_set = true;
+       attr->poison = poison;
+       return 0;
+}
+
 int rseq_mempool_get_max_nr_cpus(struct rseq_mempool *mempool)
 {
        if (!mempool || mempool->attr.type != MEMPOOL_TYPE_PERCPU) {
index e02a95dbac315c2d3a33b49f0891d7e2402c45ef..05108cb251de87dc5136ef01ec53d6db1f7d74f2 100644 (file)
 #include "list.h"
 #include "tap.h"
 
+#if RSEQ_BITS_PER_LONG == 64
+# define POISON_VALUE  0xABCDABCDABCDABCDULL
+#else
+# define POISON_VALUE  0xABCDABCDUL
+#endif
+
 struct test_data {
        uintptr_t value;
        struct test_data __rseq_percpu *backref;
@@ -48,6 +54,8 @@ static void test_mempool_fill(unsigned long max_nr_ranges, size_t stride)
        ok(ret == 0, "Setting mempool percpu type");
        ret = rseq_mempool_attr_set_max_nr_ranges(attr, max_nr_ranges);
        ok(ret == 0, "Setting mempool max_nr_ranges=%lu", max_nr_ranges);
+       ret = rseq_mempool_attr_set_poison(attr, POISON_VALUE);
+       ok(ret == 0, "Setting mempool poison");
        mempool = rseq_mempool_create("test_data",
                        sizeof(struct test_data), attr);
        ok(mempool, "Create mempool of size %zu", stride);
This page took 0.025956 seconds and 4 git commands to generate.