diff options
| author | Daniel Micay <danielmicay@gmail.com> | 2017-01-23 17:33:53 -0500 |
|---|---|---|
| committer | Moyster <oysterized@gmail.com> | 2018-05-16 13:23:59 +0200 |
| commit | 423f49a5638a6e83aa6989244d13b49cc2b98dba (patch) | |
| tree | 3fbd6f5df01f60c77c4f9a204cf53ca6bdc894ce | |
| parent | 0b71db97a50218f16fd49d39907710cf24fed0d7 (diff) | |
add slub free list XOR encryption
Based on the grsecurity feature, but with a per-cache random value.
| -rw-r--r-- | include/linux/slub_def.h | 2 | ||||
| -rw-r--r-- | mm/slub.c | 19 |
2 files changed, 17 insertions, 4 deletions
diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h index b1af36a2a..fd2dfb600 100644 --- a/include/linux/slub_def.h +++ b/include/linux/slub_def.h @@ -98,6 +98,8 @@ struct kmem_cache { #endif #endif + unsigned long random; + #ifdef CONFIG_NUMA /* * Defragmentation by allocating from a remote node. @@ -34,6 +34,7 @@ #include <linux/stacktrace.h> #include <linux/prefetch.h> #include <linux/memcontrol.h> +#include <linux/random.h> #include <linux/aee.h> #include <trace/events/kmem.h> @@ -298,20 +299,28 @@ static inline int check_valid_pointer(struct kmem_cache *s, static inline void *get_freepointer(struct kmem_cache *s, void *object) { - return *(void **)(object + s->offset); + unsigned long freepointer_addr = (unsigned long)object + s->offset; + return (void *)(*(unsigned long *)freepointer_addr ^ s->random ^ freepointer_addr); } static void prefetch_freepointer(const struct kmem_cache *s, void *object) { - prefetch(object + s->offset); + unsigned long freepointer_addr = (unsigned long)object + s->offset; + if (object) { + void **freepointer_ptr = (void **)(*(unsigned long *)freepointer_addr ^ s->random ^ freepointer_addr); + prefetch(freepointer_ptr); + } } static inline void *get_freepointer_safe(struct kmem_cache *s, void *object) { + unsigned long __maybe_unused freepointer_addr; void *p; #ifdef CONFIG_DEBUG_PAGEALLOC - probe_kernel_read(&p, (void **)(object + s->offset), sizeof(p)); + freepointer_addr = (unsigned long)object + s->offset; + probe_kernel_read(&p, (void **)freepointer_addr, sizeof(p)); + return (void *)((unsigned long)p ^ s->random ^ freepointer_addr); #else p = get_freepointer(s, object); #endif @@ -320,7 +329,8 @@ static inline void *get_freepointer_safe(struct kmem_cache *s, void *object) static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp) { - *(void **)(object + s->offset) = fp; + unsigned long freepointer_addr = (unsigned long)object + s->offset; + *(void **)freepointer_addr = (void *)((unsigned long)fp ^ s->random ^ freepointer_addr); } /* Loop over all objects in a slab */ @@ -3256,6 +3266,7 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order) static int kmem_cache_open(struct kmem_cache *s, unsigned long flags) { s->flags = kmem_cache_flags(s->size, flags, s->name, s->ctor); + s->random = get_random_long(); s->reserved = 0; if (need_reserve_slab_rcu && (s->flags & SLAB_DESTROY_BY_RCU)) |
