[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <0c66165d4f46fa80cd31df147e7bbcaa5fea784c.1402602126.git.vdavydov@parallels.com>
Date: Fri, 13 Jun 2014 00:38:19 +0400
From: Vladimir Davydov <vdavydov@...allels.com>
To: <akpm@...ux-foundation.org>
CC: <cl@...ux.com>, <iamjoonsoo.kim@....com>, <rientjes@...gle.com>,
<penberg@...nel.org>, <hannes@...xchg.org>, <mhocko@...e.cz>,
<linux-kernel@...r.kernel.org>, <linux-mm@...ck.org>
Subject: [PATCH -mm v3 5/8] slub: make slab_free non-preemptable
Since per memcg cache destruction is scheduled when the last slab is
freed, to avoid use-after-free in kmem_cache_free we should either
rearrange code in kmem_cache_free so that it won't dereference the cache
ptr after freeing the object, or wait for all kmem_cache_free's to
complete before proceeding to cache destruction.
The former approach isn't a good option from the future development
point of view, because every modifications to kmem_cache_free must be
done with great care then. Hence we should provide a method to wait for
all currently executing kmem_cache_free's to finish.
This patch makes SLUB's implementation of kmem_cache_free
non-preemptable. As a result, synchronize_sched() will work as a barrier
against kmem_cache_free's in flight, so that issuing it before cache
destruction will protect us against the use-after-free.
This won't affect performance of kmem_cache_free, because we already
disable preemption there, and this patch only moves preempt_enable to
the end of the function. Neither should it affect the system latency,
because kmem_cache_free is extremely short, even in its slow path.
SLAB's version of kmem_cache_free already proceeds with irqs disabled,
so we only add a comment explaining why it's necessary for kmemcg there.
Signed-off-by: Vladimir Davydov <vdavydov@...allels.com>
Acked-by: Christoph Lameter <cl@...ux.com>
---
mm/slab.c | 6 ++++++
mm/slub.c | 12 ++++++------
2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/mm/slab.c b/mm/slab.c
index 9ca3b87edabc..b3af82419251 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3450,6 +3450,12 @@ static inline void __cache_free(struct kmem_cache *cachep, void *objp,
{
struct array_cache *ac = cpu_cache_get(cachep);
+ /*
+ * Since we free objects with irqs and therefore preemption disabled,
+ * we can use synchronize_sched() to wait for all currently executing
+ * kfree's to finish. This is necessary to avoid use-after-free on
+ * per memcg cache destruction.
+ */
check_irq_off();
kmemleak_free_recursive(objp, cachep->flags);
objp = cache_free_debugcheck(cachep, objp, caller);
diff --git a/mm/slub.c b/mm/slub.c
index 35741592be8c..52565a9426ef 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2673,18 +2673,17 @@ static __always_inline void slab_free(struct kmem_cache *s,
slab_free_hook(s, x);
-redo:
/*
- * Determine the currently cpus per cpu slab.
- * The cpu may change afterward. However that does not matter since
- * data is retrieved via this pointer. If we are on the same cpu
- * during the cmpxchg then the free will succedd.
+ * We could make this function fully preemptable, but then we wouldn't
+ * have a method to wait for all currently executing kfree's to finish,
+ * which is necessary to avoid use-after-free on per memcg cache
+ * destruction.
*/
preempt_disable();
+redo:
c = this_cpu_ptr(s->cpu_slab);
tid = c->tid;
- preempt_enable();
if (likely(page == c->page)) {
set_freepointer(s, object, c->freelist);
@@ -2701,6 +2700,7 @@ redo:
} else
__slab_free(s, page, x, addr);
+ preempt_enable();
}
void kmem_cache_free(struct kmem_cache *s, void *x)
--
1.7.10.4
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists