Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kunit: Fix race condition in try-catch completion

KUnit's try-catch infrastructure now uses vfork_done, which is always
set to a valid completion when a kthread is created, but which is set to
NULL once the thread terminates. This creates a race condition, where
the kthread exits before we can wait on it.

Keep a copy of vfork_done, which is taken before we wake_up_process()
and so valid, and wait on that instead.

Fixes: 93533996100c ("kunit: Handle test faults")
Reported-by: Linux Kernel Functional Testing <lkft@linaro.org>
Closes: https://lore.kernel.org/lkml/20240410102710.35911-1-naresh.kamboju@linaro.org/
Tested-by: Linux Kernel Functional Testing <lkft@linaro.org>
Acked-by: Mickaël Salaün <mic@digikod.net>
Signed-off-by: David Gow <davidgow@google.com>
Reviewed-by: Rae Moar <rmoar@google.com>
Tested-by: Miguel Ojeda <ojeda@kernel.org>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>

authored by

David Gow and committed by
Shuah Khan
1eb69ded 170c3173

+7 -3
+7 -3
lib/kunit/try-catch.c
··· 63 63 { 64 64 struct kunit *test = try_catch->test; 65 65 struct task_struct *task_struct; 66 + struct completion *task_done; 66 67 int exit_code, time_remaining; 67 68 68 69 try_catch->context = context; ··· 76 75 return; 77 76 } 78 77 get_task_struct(task_struct); 79 - wake_up_process(task_struct); 80 78 /* 81 79 * As for a vfork(2), task_struct->vfork_done (pointing to the 82 80 * underlying kthread->exited) can be used to wait for the end of a 83 - * kernel thread. 81 + * kernel thread. It is set to NULL when the thread exits, so we 82 + * keep a copy here. 84 83 */ 85 - time_remaining = wait_for_completion_timeout(task_struct->vfork_done, 84 + task_done = task_struct->vfork_done; 85 + wake_up_process(task_struct); 86 + 87 + time_remaining = wait_for_completion_timeout(task_done, 86 88 kunit_test_timeout()); 87 89 if (time_remaining == 0) { 88 90 try_catch->try_result = -ETIMEDOUT;