History

workqueue: Fix wq->cpu_pwq leak in alloc_and_link_pwqs() WQ_UNBOUND path

For WQ_UNBOUND workqueues, alloc_and_link_pwqs() allocates wq->cpu_pwq via alloc_percpu() and then calls apply_workqueue_attrs_locked(). On failure it returns the error directly, bypassing the enomem: label which holds the only free_percpu(wq->cpu_pwq) in this function. The caller's error path kfree()s wq without touching wq->cpu_pwq, leaking one percpu pointer table (nr_cpu_ids * sizeof(void *) bytes) per failed call. If kmemleak is enabled, we can see: unreferenced object (percpu) 0xc0fffa5b121048 (size 8): comm "insmod", pid 776, jiffies 4294682844 backtrace (crc 0): pcpu_alloc_noprof+0x665/0xac0 __alloc_workqueue+0x33f/0xa20 alloc_workqueue_noprof+0x60/0x100 Route the error through the existing enomem: cleanup and any error before this one.

Breno Leitao committed 6 months ago

Commit 01430331 parent a7488f01 file · +3 −1Browse files

Showing the changes to kernel/workqueue.c (1 of 1 file). Show all

Unified · Split

kernel/workqueue.c+3−1
@@ -5654,7 +5654,9 @@ static int alloc_and_link_pwqs(struct workqueue_struct *wq) · 5653 unmodified lines
5654 ret = apply_workqueue_attrs_locked(wq, unbound_std_wq_attrs[highpri]);5654 ret = apply_workqueue_attrs_locked(wq, unbound_std_wq_attrs[highpri]);
5655 }5655 }
5656 5656
5657 return ret;5657 if (ret)
5658 goto enomem;
5659 return 0;
5658 5660
5659enomem:5661enomem:
5660 if (wq->cpu_pwq) {5662 if (wq->cpu_pwq) {