From: Shu Wang Date: Thu, 10 Aug 2017 07:52:16 +0000 (+0800) Subject: sched/topology: Fix memory leak in __sdt_alloc() X-Git-Tag: v4.14-rc1~171^2~4 X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=commitdiff_plain;h=213c5a459ae0a7ef0a092f576aae2d5db6819360;p=linux.git sched/topology: Fix memory leak in __sdt_alloc() Found this issue by kmemleak: the 'sg' and 'sgc' pointers from __sdt_alloc() might be leaked as each domain holds many groups' ref, but in destroy_sched_domain(), it only declined the first group ref. Onlining and offlining a CPU can trigger this leak, and cause OOM. Reproducer for my 6 CPUs machine: while true do echo 0 > /sys/devices/system/cpu/cpu5/online; echo 1 > /sys/devices/system/cpu/cpu5/online; done unreferenced object 0xffff88007d772a80 (size 64): comm "cpuhp/5", pid 39, jiffies 4294719962 (age 35.251s) hex dump (first 32 bytes): c0 22 77 7d 00 88 ff ff 02 00 00 00 01 00 00 00 ."w}............ 40 2a 77 7d 00 88 ff ff 00 00 00 00 00 00 00 00 @*w}............ backtrace: [] kmemleak_alloc+0x4a/0xa0 [] __kmalloc_node+0xf1/0x280 [] build_sched_domains+0x1e8/0xf20 [] partition_sched_domains+0x304/0x360 [] cpuset_update_active_cpus+0x17/0x40 [] sched_cpu_activate+0xae/0xc0 [] cpuhp_invoke_callback+0x90/0x400 [] cpuhp_up_callbacks+0x37/0xb0 [] cpuhp_thread_fun+0xd7/0xf0 [] smpboot_thread_fn+0x110/0x160 [] kthread+0x109/0x140 [] ret_from_fork+0x25/0x30 [] 0xffffffffffffffff unreferenced object 0xffff88007d772a40 (size 64): comm "cpuhp/5", pid 39, jiffies 4294719962 (age 35.251s) hex dump (first 32 bytes): 03 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 ................ 00 04 00 00 00 00 00 00 4f 3c fc ff 00 00 00 00 ........O<...... backtrace: [] kmemleak_alloc+0x4a/0xa0 [] __kmalloc_node+0xf1/0x280 [] build_sched_domains+0xead/0xf20 [] partition_sched_domains+0x304/0x360 [] cpuset_update_active_cpus+0x17/0x40 [] sched_cpu_activate+0xae/0xc0 [] cpuhp_invoke_callback+0x90/0x400 [] cpuhp_up_callbacks+0x37/0xb0 [] cpuhp_thread_fun+0xd7/0xf0 [] smpboot_thread_fn+0x110/0x160 [] kthread+0x109/0x140 [] ret_from_fork+0x25/0x30 [] 0xffffffffffffffff Reported-by: Chunyu Hu Signed-off-by: Shu Wang Signed-off-by: Peter Zijlstra (Intel) Acked-by: Chunyu Hu Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: liwang@redhat.com Link: http://lkml.kernel.org/r/1502351536-9108-1-git-send-email-shuwang@redhat.com Signed-off-by: Ingo Molnar --- diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c index bd8b6d6f5387..4197f1346153 100644 --- a/kernel/sched/topology.c +++ b/kernel/sched/topology.c @@ -335,7 +335,8 @@ static void free_sched_groups(struct sched_group *sg, int free_sgc) if (free_sgc && atomic_dec_and_test(&sg->sgc->ref)) kfree(sg->sgc); - kfree(sg); + if (atomic_dec_and_test(&sg->ref)) + kfree(sg); sg = tmp; } while (sg != first); } @@ -343,15 +344,11 @@ static void free_sched_groups(struct sched_group *sg, int free_sgc) static void destroy_sched_domain(struct sched_domain *sd) { /* - * If its an overlapping domain it has private groups, iterate and - * nuke them all. + * A sched domain has many groups' reference, and an overlapping + * domain has private groups, iterate and nuke them all. */ - if (sd->flags & SD_OVERLAP) { - free_sched_groups(sd->groups, 1); - } else if (atomic_dec_and_test(&sd->groups->ref)) { - kfree(sd->groups->sgc); - kfree(sd->groups); - } + free_sched_groups(sd->groups, 1); + if (sd->shared && atomic_dec_and_test(&sd->shared->ref)) kfree(sd->shared); kfree(sd); @@ -668,6 +665,7 @@ build_group_from_child_sched_domain(struct sched_domain *sd, int cpu) else cpumask_copy(sg_span, sched_domain_span(sd)); + atomic_inc(&sg->ref); return sg; }