aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Micay <danielmicay@gmail.com>2017-01-23 17:33:53 -0500
committerMoyster <oysterized@gmail.com>2018-05-16 13:23:59 +0200
commit423f49a5638a6e83aa6989244d13b49cc2b98dba (patch)
tree3fbd6f5df01f60c77c4f9a204cf53ca6bdc894ce
parent0b71db97a50218f16fd49d39907710cf24fed0d7 (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.h2
-rw-r--r--mm/slub.c19
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.
diff --git a/mm/slub.c b/mm/slub.c
index 05895b54a..9f9eaefbd 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -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))