Two threads calling KCOV_DF_INIT_TRACK concurrently could both observe df->area == NULL, drop the lock to allocate, and then both assign their allocation to df->area, leaking one buffer.
Fix by rechecking df->area after re-acquiring the lock. If another thread won the race, free the allocation and return -EBUSY. This matches the pattern used by KCOV_INIT_TRACE in kernel/kcov.c. Reported-by: sashiko-bot <[email protected]> Closes: https://sashiko.dev/#/patchset/20260603-kcov-dataflow-next-20260603-v2-0-fee0939de2c4%40est.tech Signed-off-by: Yunseong Kim <[email protected]> --- kernel/kcov_dataflow.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/kernel/kcov_dataflow.c b/kernel/kcov_dataflow.c index 721f742cbfe5..df7e8bf70bfa 100644 --- a/kernel/kcov_dataflow.c +++ b/kernel/kcov_dataflow.c @@ -268,11 +268,20 @@ static long kcov_df_ioctl(struct file *filep, unsigned int cmd, unsigned long ar break; } spin_unlock_irqrestore(&df->lock, flags); - df->area = vmalloc_user(size * sizeof(u64)); - if (!df->area) - return -ENOMEM; - spin_lock_irqsave(&df->lock, flags); - df->size = size; + { + void *area = vmalloc_user(size * sizeof(u64)); + + if (!area) + return -ENOMEM; + spin_lock_irqsave(&df->lock, flags); + if (df->area) { + spin_unlock_irqrestore(&df->lock, flags); + vfree(area); + return -EBUSY; + } + df->area = area; + df->size = size; + } break; case KCOV_DF_ENABLE: -- 2.43.0

