summaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorGreg Thelen <gthelen@google.com>2017-02-24 18:00:05 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-02-24 20:46:56 -0500
commitf9fa1d919c696e90c887d8742198023e7639d139 (patch)
treeacc56d7b44857938665f29c17d51b122697dc8f5 /mm
parentdc18d706a4367454ad1fc51e06148d54e8ecfaa0 (diff)
kasan: drain quarantine of memcg slab objects
Per memcg slab accounting and kasan have a problem with kmem_cache destruction. - kmem_cache_create() allocates a kmem_cache, which is used for allocations from processes running in root (top) memcg. - Processes running in non root memcg and allocating with either __GFP_ACCOUNT or from a SLAB_ACCOUNT cache use a per memcg kmem_cache. - Kasan catches use-after-free by having kfree() and kmem_cache_free() defer freeing of objects. Objects are placed in a quarantine. - kmem_cache_destroy() destroys root and non root kmem_caches. It takes care to drain the quarantine of objects from the root memcg's kmem_cache, but ignores objects associated with non root memcg. This causes leaks because quarantined per memcg objects refer to per memcg kmem cache being destroyed. To see the problem: 1) create a slab cache with kmem_cache_create(,,,SLAB_ACCOUNT,) 2) from non root memcg, allocate and free a few objects from cache 3) dispose of the cache with kmem_cache_destroy() kmem_cache_destroy() will trigger a "Slab cache still has objects" warning indicating that the per memcg kmem_cache structure was leaked. Fix the leak by draining kasan quarantined objects allocated from non root memcg. Racing memcg deletion is tricky, but handled. kmem_cache_destroy() => shutdown_memcg_caches() => __shutdown_memcg_cache() => shutdown_cache() flushes per memcg quarantined objects, even if that memcg has been rmdir'd and gone through memcg_deactivate_kmem_caches(). This leak only affects destroyed SLAB_ACCOUNT kmem caches when kasan is enabled. So I don't think it's worth patching stable kernels. Link: http://lkml.kernel.org/r/1482257462-36948-1-git-send-email-gthelen@google.com Signed-off-by: Greg Thelen <gthelen@google.com> Reviewed-by: Vladimir Davydov <vdavydov.dev@gmail.com> Acked-by: Andrey Ryabinin <aryabinin@virtuozzo.com> Cc: Alexander Potapenko <glider@google.com> Cc: Dmitry Vyukov <dvyukov@google.com> Cc: Christoph Lameter <cl@linux.com> Cc: Pekka Enberg <penberg@kernel.org> Cc: David Rientjes <rientjes@google.com> Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/kasan/kasan.c2
-rw-r--r--mm/kasan/quarantine.c1
-rw-r--r--mm/slab_common.c4
3 files changed, 5 insertions, 2 deletions
diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c
index b2a0cff2bb35..25f0e6521f36 100644
--- a/mm/kasan/kasan.c
+++ b/mm/kasan/kasan.c
@@ -435,7 +435,7 @@ void kasan_cache_shrink(struct kmem_cache *cache)
435 quarantine_remove_cache(cache); 435 quarantine_remove_cache(cache);
436} 436}
437 437
438void kasan_cache_destroy(struct kmem_cache *cache) 438void kasan_cache_shutdown(struct kmem_cache *cache)
439{ 439{
440 quarantine_remove_cache(cache); 440 quarantine_remove_cache(cache);
441} 441}
diff --git a/mm/kasan/quarantine.c b/mm/kasan/quarantine.c
index dae929c02bbb..6f1ed1630873 100644
--- a/mm/kasan/quarantine.c
+++ b/mm/kasan/quarantine.c
@@ -274,6 +274,7 @@ static void per_cpu_remove_cache(void *arg)
274 qlist_free_all(&to_free, cache); 274 qlist_free_all(&to_free, cache);
275} 275}
276 276
277/* Free all quarantined objects belonging to cache. */
277void quarantine_remove_cache(struct kmem_cache *cache) 278void quarantine_remove_cache(struct kmem_cache *cache)
278{ 279{
279 unsigned long flags, i; 280 unsigned long flags, i;
diff --git a/mm/slab_common.c b/mm/slab_common.c
index 23ff74e61838..09d0e849b07f 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -528,6 +528,9 @@ static void slab_caches_to_rcu_destroy_workfn(struct work_struct *work)
528 528
529static int shutdown_cache(struct kmem_cache *s) 529static int shutdown_cache(struct kmem_cache *s)
530{ 530{
531 /* free asan quarantined objects */
532 kasan_cache_shutdown(s);
533
531 if (__kmem_cache_shutdown(s) != 0) 534 if (__kmem_cache_shutdown(s) != 0)
532 return -EBUSY; 535 return -EBUSY;
533 536
@@ -816,7 +819,6 @@ void kmem_cache_destroy(struct kmem_cache *s)
816 get_online_cpus(); 819 get_online_cpus();
817 get_online_mems(); 820 get_online_mems();
818 821
819 kasan_cache_destroy(s);
820 mutex_lock(&slab_mutex); 822 mutex_lock(&slab_mutex);
821 823
822 s->refcount--; 824 s->refcount--;