[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <caa13441-5f95-b7d6-dd5d-1cf49e709714@I-love.SAKURA.ne.jp>
Date: Sat, 4 Feb 2023 09:48:39 +0900
From: Tetsuo Handa <penguin-kernel@...ove.SAKURA.ne.jp>
To: Peter Zijlstra <peterz@...radead.org>
Cc: Ingo Molnar <mingo@...nel.org>,
"Rafael J. Wysocki" <rafael.j.wysocki@...el.com>,
linux-kernel@...r.kernel.org, mcgrof@...nel.org,
Linus Torvalds <torvalds@...ux-foundation.org>,
syzkaller-bugs@...glegroups.com,
syzbot <syzbot+6cd18e123583550cf469@...kaller.appspotmail.com>,
Hillf Danton <hdanton@...a.com>
Subject: Re: [syzbot] WARNING: locking bug in umh_complete
On 2023/02/03 23:31, Peter Zijlstra wrote:
> Yes, I meant something like so.
>
>
> diff --git a/kernel/umh.c b/kernel/umh.c
> index 850631518665..0e69e1e4b6fe 100644
> --- a/kernel/umh.c
> +++ b/kernel/umh.c
> @@ -438,21 +438,24 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)
> if (wait == UMH_NO_WAIT) /* task has freed sub_info */
> goto unlock;
>
> - if (wait & UMH_KILLABLE)
> - state |= TASK_KILLABLE;
> -
> - if (wait & UMH_FREEZABLE)
> + if (wait & UMH_FREEZABLE) {
> state |= TASK_FREEZABLE;
>
> - retval = wait_for_completion_state(&done, state);
> - if (!retval)
> - goto wait_done;
> -
> if (wait & UMH_KILLABLE) {
> + retval = wait_for_completion_state(&done, state | TASK_KILLABLE);
> + if (!retval)
> + goto wait_done;
> +
> /* umh_complete() will see NULL and free sub_info */
> if (xchg(&sub_info->complete, NULL))
> goto unlock;
> +
> + /*
> + * fallthrough; in case of -ERESTARTSYS now do uninterruptible
> + * wait_for_completion().
> + */
> }
> + wait_for_completion_state(&done, state);
>
> wait_done:
> retval = sub_info->retval;
Please fold below diff, provided that wait_for_completion_state(TASK_FREEZABLE)
does not return when the current thread was frozen. (If
wait_for_completion_state(TASK_FREEZABLE) returns when the current thread was
frozen, we will fail to execute the
retval = sub_info->retval;
line in order to get the exit code after the current thread is thawed...)
diff --git a/kernel/umh.c b/kernel/umh.c
index 0e69e1e4b6fe..a776920ec051 100644
--- a/kernel/umh.c
+++ b/kernel/umh.c
@@ -431,35 +431,38 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)
* This makes it possible to use umh_complete to free
* the data structure in case of UMH_NO_WAIT.
*/
sub_info->complete = (wait == UMH_NO_WAIT) ? NULL : &done;
sub_info->wait = wait;
queue_work(system_unbound_wq, &sub_info->work);
if (wait == UMH_NO_WAIT) /* task has freed sub_info */
goto unlock;
- if (wait & UMH_FREEZABLE) {
+ if (wait & UMH_FREEZABLE)
state |= TASK_FREEZABLE;
if (wait & UMH_KILLABLE) {
retval = wait_for_completion_state(&done, state | TASK_KILLABLE);
if (!retval)
goto wait_done;
/* umh_complete() will see NULL and free sub_info */
if (xchg(&sub_info->complete, NULL))
goto unlock;
/*
* fallthrough; in case of -ERESTARTSYS now do uninterruptible
- * wait_for_completion().
+ * wait_for_completion_state(). Since umh_complete() shall call
+ * complete() in a moment if xchg() above returned NULL, this
+ * uninterruptible wait_for_completion_state() will not block
+ * SIGKILL'ed process for so long.
*/
}
wait_for_completion_state(&done, state);
wait_done:
retval = sub_info->retval;
out:
call_usermodehelper_freeinfo(sub_info);
unlock:
helper_unlock();
Powered by blists - more mailing lists