|
|
Message-Id: <1477757996-22468-6-git-send-email-dwindsor@gmail.com>
Date: Sat, 29 Oct 2016 12:19:56 -0400
From: David Windsor <dwindsor@...il.com>
To: kernel-hardening@...ts.openwall.com
Cc: keescook@...omium.org,
elena.reshetova@...el.com,
ishkamiel@...il.com,
takahiro.akashi@...aro.org,
colin@...dal.org,
dwindsor@...il.com
Subject: [RFC PATCH 5/5] mm: add overflow protection to struct kmem_cache.refcount
Change type of struct kmem_cache.refcount to atomic_t. This enables overflow
protection: when CONFIG_HARDENED_ATOMIC is enabled, atomic_t variables
cannot be overflowed.
The copyright for the original PAX_REFCOUNT code:
- all REFCOUNT code in general: PaX Team <pageexec@...email.hu>
- various false positive fixes: Mathias Krause <minipli@...glemail.com>
---
include/linux/slab_def.h | 2 +-
include/linux/slub_def.h | 2 +-
mm/slab.c | 2 +-
mm/slab.h | 2 +-
mm/slab_common.c | 12 ++++++------
mm/slub.c | 10 +++++-----
6 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/include/linux/slab_def.h b/include/linux/slab_def.h
index 601c69a..d018db5 100644
--- a/include/linux/slab_def.h
+++ b/include/linux/slab_def.h
@@ -40,7 +40,7 @@ struct kmem_cache {
/* 4) cache creation/removal */
const char *name;
struct list_head list;
- int refcount;
+ atomic_t refcount;
int object_size;
int align;
diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h
index 75f56c2..32710ff 100644
--- a/include/linux/slub_def.h
+++ b/include/linux/slub_def.h
@@ -74,7 +74,7 @@ struct kmem_cache {
struct kmem_cache_order_objects max;
struct kmem_cache_order_objects min;
gfp_t allocflags; /* gfp flags to use on each alloc */
- int refcount; /* Refcount for slab cache destroy */
+ atomic_t refcount; /* Refcount for slab cache destroy */
void (*ctor)(void *);
int inuse; /* Offset to metadata */
int align; /* Alignment */
diff --git a/mm/slab.c b/mm/slab.c
index 3113caf..e0cf1b4 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1919,7 +1919,7 @@ __kmem_cache_alias(const char *name, size_t size, size_t align,
cachep = find_mergeable(size, align, flags, name, ctor);
if (cachep) {
- cachep->refcount++;
+ atomic_inc(&cachep->refcount);
/*
* Adjust the object sizes so that we clear
diff --git a/mm/slab.h b/mm/slab.h
index 9653f2e..9b49151 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -22,7 +22,7 @@ struct kmem_cache {
unsigned int align; /* Alignment as calculated */
unsigned long flags; /* Active flags on the slab */
const char *name; /* Slab name for sysfs */
- int refcount; /* Use counter */
+ atomic_t refcount; /* Use counter */
void (*ctor)(void *); /* Called on object slot creation */
struct list_head list; /* List of all slab caches on the system */
};
diff --git a/mm/slab_common.c b/mm/slab_common.c
index 71f0b28..869d29f 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -244,7 +244,7 @@ int slab_unmergeable(struct kmem_cache *s)
/*
* We may have set a slab to be unmergeable during bootstrap.
*/
- if (s->refcount < 0)
+ if (atomic_read(&s->refcount) < 0)
return 1;
return 0;
@@ -348,7 +348,7 @@ static struct kmem_cache *create_cache(const char *name,
if (err)
goto out_free_cache;
- s->refcount = 1;
+ atomic_set(&s->refcount, 1);
list_add(&s->list, &slab_caches);
out:
if (err)
@@ -718,8 +718,8 @@ void kmem_cache_destroy(struct kmem_cache *s)
kasan_cache_destroy(s);
mutex_lock(&slab_mutex);
- s->refcount--;
- if (s->refcount)
+ atomic_dec(&s->refcount);
+ if (atomic_read(&s->refcount))
goto out_unlock;
err = shutdown_memcg_caches(s, &release, &need_rcu_barrier);
@@ -786,7 +786,7 @@ void __init create_boot_cache(struct kmem_cache *s, const char *name, size_t siz
panic("Creation of kmalloc slab %s size=%zu failed. Reason %d\n",
name, size, err);
- s->refcount = -1; /* Exempt from merging for now */
+ atomic_set(&s->refcount, -1); /* Exempt from merging for now */
}
struct kmem_cache *__init create_kmalloc_cache(const char *name, size_t size,
@@ -799,7 +799,7 @@ struct kmem_cache *__init create_kmalloc_cache(const char *name, size_t size,
create_boot_cache(s, name, size, flags);
list_add(&s->list, &slab_caches);
- s->refcount = 1;
+ atomic_set(&s->refcount, 1);
return s;
}
diff --git a/mm/slub.c b/mm/slub.c
index 2b3e740..d981fe3 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -4180,7 +4180,7 @@ __kmem_cache_alias(const char *name, size_t size, size_t align,
s = find_mergeable(size, align, flags, name, ctor);
if (s) {
- s->refcount++;
+ atomic_inc(&s->refcount);
/*
* Adjust the object sizes so that we clear
@@ -4196,7 +4196,7 @@ __kmem_cache_alias(const char *name, size_t size, size_t align,
}
if (sysfs_slab_alias(s, name)) {
- s->refcount--;
+ atomic_dec(&s->refcount);
s = NULL;
}
}
@@ -4903,7 +4903,7 @@ SLAB_ATTR_RO(ctor);
static ssize_t aliases_show(struct kmem_cache *s, char *buf)
{
- return sprintf(buf, "%d\n", s->refcount < 0 ? 0 : s->refcount - 1);
+ return sprintf(buf, "%d\n", atomic_read(&s->refcount) < 0 ? 0 : atomic_read(&s->refcount) - 1);
}
SLAB_ATTR_RO(aliases);
@@ -5046,7 +5046,7 @@ static ssize_t trace_store(struct kmem_cache *s, const char *buf,
* as well as cause other issues like converting a mergeable
* cache into an umergeable one.
*/
- if (s->refcount > 1)
+ if (atomic_read(&s->refcount) > 1)
return -EINVAL;
s->flags &= ~SLAB_TRACE;
@@ -5164,7 +5164,7 @@ static ssize_t failslab_show(struct kmem_cache *s, char *buf)
static ssize_t failslab_store(struct kmem_cache *s, const char *buf,
size_t length)
{
- if (s->refcount > 1)
+ if (atomic_read(&s->refcount) > 1)
return -EINVAL;
s->flags &= ~SLAB_FAILSLAB;
--
2.7.4
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.