Re: [PATCH 1/2] dma-mapping: benchmark: fix up kthread creation error handling

From: Fedor Pchelkin
Date: Fri May 03 2024 - 12:24:13 EST


Robin Murphy wrote:
> On 2024-05-02 5:18 pm, Fedor Pchelkin wrote:
> > If a kthread creation fails for some reason then uninitialized members of
> > the tasks array will be accessed on the error path since it is allocated
> > by kmalloc_array().
> >
> > Limit the bound in such case.
>
> I don't think this is right... The put_task_struct() calls on the error
> path are supposed to balance the get_task_struct() calls which only
> happen *after* all the threads are successfully created - see commit

Thanks, Robin! You're right. Now I see this..

> d17405d52bac ("dma-mapping: benchmark: fix kernel crash when
> dma_map_single fails") - although I now wonder whether that might have
> been better done by replacing kthread_stop() with kthread_stop_put(). It
> doesn't look like we've ever actually tried to free any previous threads
> from the point of allocation failure.

It should have looked like the diff below, as you say. And it's probably
better to merge the two patches together so that we eliminate task leaks
in case kthread_stop_put() returns error like it is below.

Will rework that in v2.

diff --git a/kernel/dma/map_benchmark.c b/kernel/dma/map_benchmark.c
index 02205ab53b7e..3b7658ce1599 100644
--- a/kernel/dma/map_benchmark.c
+++ b/kernel/dma/map_benchmark.c
@@ -118,6 +118,8 @@ static int do_map_benchmark(struct map_benchmark_data *map)
if (IS_ERR(tsk[i])) {
pr_err("create dma_map thread failed\n");
ret = PTR_ERR(tsk[i]);
+ while (--i >= 0)
+ kthread_stop(tsk[i]);
goto out;
}

@@ -141,7 +143,7 @@ static int do_map_benchmark(struct map_benchmark_data *map)

/* wait for the completion of benchmark threads */
for (i = 0; i < threads; i++) {
- ret = kthread_stop(tsk[i]);
+ ret = kthread_stop_put(tsk[i]);
if (ret)
goto out;
}
@@ -170,8 +172,6 @@ static int do_map_benchmark(struct map_benchmark_data *map)
}

out:
- for (i = 0; i < threads; i++)
- put_task_struct(tsk[i]);
put_device(map->dev);
kfree(tsk);
return ret;