Skip to content

Commit 6c82d45

Browse files
Kuan-Ying Leetorvalds
Kuan-Ying Lee
authored andcommitted
kasan: fix object remaining in offline per-cpu quarantine
We hit this issue in our internal test. When enabling generic kasan, a kfree()'d object is put into per-cpu quarantine first. If the cpu goes offline, object still remains in the per-cpu quarantine. If we call kmem_cache_destroy() now, slub will report "Objects remaining" error. ============================================================================= BUG test_module_slab (Not tainted): Objects remaining in test_module_slab on __kmem_cache_shutdown() ----------------------------------------------------------------------------- Disabling lock debugging due to kernel taint INFO: Slab 0x(____ptrval____) objects=34 used=1 fp=0x(____ptrval____) flags=0x2ffff00000010200 CPU: 3 PID: 176 Comm: cat Tainted: G B 5.10.0-rc1-00007-g4525c8781ec0-dirty #10 Hardware name: linux,dummy-virt (DT) Call trace: dump_backtrace+0x0/0x2b0 show_stack+0x18/0x68 dump_stack+0xfc/0x168 slab_err+0xac/0xd4 __kmem_cache_shutdown+0x1e4/0x3c8 kmem_cache_destroy+0x68/0x130 test_version_show+0x84/0xf0 module_attr_show+0x40/0x60 sysfs_kf_seq_show+0x128/0x1c0 kernfs_seq_show+0xa0/0xb8 seq_read+0x1f0/0x7e8 kernfs_fop_read+0x70/0x338 vfs_read+0xe4/0x250 ksys_read+0xc8/0x180 __arm64_sys_read+0x44/0x58 el0_svc_common.constprop.0+0xac/0x228 do_el0_svc+0x38/0xa0 el0_sync_handler+0x170/0x178 el0_sync+0x174/0x180 INFO: Object 0x(____ptrval____) @offset=15848 INFO: Allocated in test_version_show+0x98/0xf0 age=8188 cpu=6 pid=172 stack_trace_save+0x9c/0xd0 set_track+0x64/0xf0 alloc_debug_processing+0x104/0x1a0 ___slab_alloc+0x628/0x648 __slab_alloc.isra.0+0x2c/0x58 kmem_cache_alloc+0x560/0x588 test_version_show+0x98/0xf0 module_attr_show+0x40/0x60 sysfs_kf_seq_show+0x128/0x1c0 kernfs_seq_show+0xa0/0xb8 seq_read+0x1f0/0x7e8 kernfs_fop_read+0x70/0x338 vfs_read+0xe4/0x250 ksys_read+0xc8/0x180 __arm64_sys_read+0x44/0x58 el0_svc_common.constprop.0+0xac/0x228 kmem_cache_destroy test_module_slab: Slab cache still has objects Register a cpu hotplug function to remove all objects in the offline per-cpu quarantine when cpu is going offline. Set a per-cpu variable to indicate this cpu is offline. [qiang.zhang@windriver.com: fix slab double free when cpu-hotplug] Link: https://lkml.kernel.org/r/20201204102206.20237-1-qiang.zhang@windriver.com Link: https://lkml.kernel.org/r/1606895585-17382-2-git-send-email-Kuan-Ying.Lee@mediatek.com Signed-off-by: Kuan-Ying Lee <Kuan-Ying.Lee@mediatek.com> Signed-off-by: Zqiang <qiang.zhang@windriver.com> Suggested-by: Dmitry Vyukov <dvyukov@google.com> Reported-by: Guangye Yang <guangye.yang@mediatek.com> Reviewed-by: Dmitry Vyukov <dvyukov@google.com> Cc: Andrey Ryabinin <aryabinin@virtuozzo.com> Cc: Alexander Potapenko <glider@google.com> Cc: Matthias Brugger <matthias.bgg@gmail.com> Cc: Nicholas Tang <nicholas.tang@mediatek.com> Cc: Miles Chen <miles.chen@mediatek.com> Cc: Qian Cai <qcai@redhat.com> Cc: Stephen Rothwell <sfr@canb.auug.org.au> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 6e7b64b commit 6c82d45

File tree

1 file changed

+39
-0
lines changed

1 file changed

+39
-0
lines changed

mm/kasan/quarantine.c

+39
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <linux/srcu.h>
3030
#include <linux/string.h>
3131
#include <linux/types.h>
32+
#include <linux/cpuhotplug.h>
3233

3334
#include "../slab.h"
3435
#include "kasan.h"
@@ -43,6 +44,7 @@ struct qlist_head {
4344
struct qlist_node *head;
4445
struct qlist_node *tail;
4546
size_t bytes;
47+
bool offline;
4648
};
4749

4850
#define QLIST_INIT { NULL, NULL, 0 }
@@ -188,6 +190,10 @@ void quarantine_put(struct kasan_free_meta *info, struct kmem_cache *cache)
188190
local_irq_save(flags);
189191

190192
q = this_cpu_ptr(&cpu_quarantine);
193+
if (q->offline) {
194+
local_irq_restore(flags);
195+
return;
196+
}
191197
qlist_put(q, &info->quarantine_link, cache->size);
192198
if (unlikely(q->bytes > QUARANTINE_PERCPU_SIZE)) {
193199
qlist_move_all(q, &temp);
@@ -328,3 +334,36 @@ void quarantine_remove_cache(struct kmem_cache *cache)
328334

329335
synchronize_srcu(&remove_cache_srcu);
330336
}
337+
338+
static int kasan_cpu_online(unsigned int cpu)
339+
{
340+
this_cpu_ptr(&cpu_quarantine)->offline = false;
341+
return 0;
342+
}
343+
344+
static int kasan_cpu_offline(unsigned int cpu)
345+
{
346+
struct qlist_head *q;
347+
348+
q = this_cpu_ptr(&cpu_quarantine);
349+
/* Ensure the ordering between the writing to q->offline and
350+
* qlist_free_all. Otherwise, cpu_quarantine may be corrupted
351+
* by interrupt.
352+
*/
353+
WRITE_ONCE(q->offline, true);
354+
barrier();
355+
qlist_free_all(q, NULL);
356+
return 0;
357+
}
358+
359+
static int __init kasan_cpu_quarantine_init(void)
360+
{
361+
int ret = 0;
362+
363+
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mm/kasan:online",
364+
kasan_cpu_online, kasan_cpu_offline);
365+
if (ret < 0)
366+
pr_err("kasan cpu quarantine register failed [%d]\n", ret);
367+
return ret;
368+
}
369+
late_initcall(kasan_cpu_quarantine_init);

0 commit comments

Comments
 (0)