Commit c02e3f36 authored by Neil Horman's avatar Neil Horman Committed by Linus Torvalds

kmod: fix race in usermodehelper code

The user mode helper code has a race in it.  call_usermodehelper_exec()
takes an allocated subprocess_info structure, which it passes to a
workqueue, and then passes it to a kernel thread which it creates, after
which it calls complete to signal to the caller of
call_usermodehelper_exec() that it can free the subprocess_info struct.

But since we use that structure in the created thread, we can't call
complete from __call_usermodehelper(), which is where we create the kernel
thread.  We need to call complete() from within the kernel thread and then
not use subprocess_info afterward in the case of UMH_WAIT_EXEC.  Tested
successfully by me.
Signed-off-by: default avatarNeil Horman <nhorman@tuxdriver.com>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 1fd7317d
...@@ -143,6 +143,7 @@ struct subprocess_info { ...@@ -143,6 +143,7 @@ struct subprocess_info {
static int ____call_usermodehelper(void *data) static int ____call_usermodehelper(void *data)
{ {
struct subprocess_info *sub_info = data; struct subprocess_info *sub_info = data;
enum umh_wait wait = sub_info->wait;
int retval; int retval;
BUG_ON(atomic_read(&sub_info->cred->usage) != 1); BUG_ON(atomic_read(&sub_info->cred->usage) != 1);
...@@ -184,9 +185,13 @@ static int ____call_usermodehelper(void *data) ...@@ -184,9 +185,13 @@ static int ____call_usermodehelper(void *data)
*/ */
set_user_nice(current, 0); set_user_nice(current, 0);
if (wait == UMH_WAIT_EXEC)
complete(sub_info->complete);
retval = kernel_execve(sub_info->path, sub_info->argv, sub_info->envp); retval = kernel_execve(sub_info->path, sub_info->argv, sub_info->envp);
/* Exec failed? */ /* Exec failed? */
if (wait != UMH_WAIT_EXEC)
sub_info->retval = retval; sub_info->retval = retval;
do_exit(0); do_exit(0);
} }
...@@ -266,16 +271,14 @@ static void __call_usermodehelper(struct work_struct *work) ...@@ -266,16 +271,14 @@ static void __call_usermodehelper(struct work_struct *work)
switch (wait) { switch (wait) {
case UMH_NO_WAIT: case UMH_NO_WAIT:
case UMH_WAIT_EXEC:
break; break;
case UMH_WAIT_PROC: case UMH_WAIT_PROC:
if (pid > 0) if (pid > 0)
break; break;
sub_info->retval = pid; sub_info->retval = pid;
/* FALLTHROUGH */ break;
case UMH_WAIT_EXEC:
complete(sub_info->complete);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment