* [PATCH] Deprecate exec_usermodehelper, fix request_module.
@ 2003-01-02 9:36 Rusty Russell
2003-01-02 17:14 ` Marcel Holtmann
0 siblings, 1 reply; 7+ messages in thread
From: Rusty Russell @ 2003-01-02 9:36 UTC (permalink / raw)
To: torvalds
Cc: linux-kernel, akpm, Thomas Sailer, Marcel Holtmann,
Jose Orlando Pereira, J.E.J.Bottomley
I got a report from Urban Widmark that modprobe dropped its privs on
executing an install command: turns out request_module
(ie. exec_usermodehelper) doesn't set the real uid or gid (so bash
drops privs).
These efforts to "clean" the current process are *always* going to be
buggy: we should use the event thread all the time, rather than
forking a random thread and trying to clean it. This fixes
request_module to do that (kevent threads can't block, so we
double-fork).
There are still three
(obscure) users of exec_usermodehelper in the tree:
drivers/net/hamradio/baycom_epp.c
drivers/bluetooth/bt3c_cs.c
arch/i386/mach-voyager/voyager_thread.c
Any comments? (Patch size due to some required reshuffling).
Rusty.
--
Anyone who quotes me in their sig is an idiot. -- Rusty Russell.
Name: Make request_module use call_usermodehelper
Author: Rusty Russell
Status: Tested on 2.5.54
D: Urban Widmark points out that modprobe calls system() in many
D: configurations, which drops privs since request_module() doesn't
D: doesn't set ruid and rguid.
D:
D: Use a known-clean environment (as call_usermodehelper does).
D: Deprecate exec_usermodehelper, since it's probably buggy, maybe
D: exploitable.
diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.54/include/linux/kmod.h working-2.5.54-kmod/include/linux/kmod.h
--- linux-2.5.54/include/linux/kmod.h Thu Jan 2 12:35:15 2003
+++ working-2.5.54-kmod/include/linux/kmod.h Thu Jan 2 16:44:17 2003
@@ -21,6 +21,7 @@
#include <linux/config.h>
#include <linux/errno.h>
+#include <linux/compiler.h>
#ifdef CONFIG_KMOD
extern int request_module(const char * name);
@@ -29,7 +30,7 @@ static inline int request_module(const c
#endif
#define try_then_request_module(x, mod) ((x) ?: request_module(mod), (x))
-extern int exec_usermodehelper(char *program_path, char *argv[], char *envp[]);
+extern int exec_usermodehelper(char *program_path, char *argv[], char *envp[]) __deprecated;
extern int call_usermodehelper(char *path, char *argv[], char *envp[]);
#ifdef CONFIG_HOTPLUG
diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.54/kernel/kmod.c working-2.5.54-kmod/kernel/kmod.c
--- linux-2.5.54/kernel/kmod.c Thu Jan 2 12:37:03 2003
+++ working-2.5.54-kmod/kernel/kmod.c Thu Jan 2 20:15:52 2003
@@ -14,8 +14,10 @@
Unblock all signals when we exec a usermode process.
Shuu Yamaguchi <shuu@wondernetworkresources.com> December 2000
-*/
+ Fixed request_module to use call_usermodehelper path. Jan 2003.
+ Rusty Russell <rusty@rustcorp.com.au>
+*/
#define __KERNEL_SYSCALLS__
#include <linux/config.h>
@@ -31,6 +33,7 @@
#include <linux/workqueue.h>
#include <linux/security.h>
#include <linux/mount.h>
+#include <linux/kernel.h>
#include <asm/uaccess.h>
extern int max_threads, system_running;
@@ -141,41 +144,87 @@ int exec_usermodehelper(char *program_pa
set_fs(KERNEL_DS);
/* Go, go, go... */
+ printk("Execing %s\n", program_path);
if (execve(program_path, argv, envp) < 0)
return -errno;
return 0;
}
-#ifdef CONFIG_KMOD
+struct subprocess_info {
+ struct completion *complete;
+ char *path;
+ char **argv;
+ char **envp;
+ int wait;
+ pid_t retval;
+};
/*
- modprobe_path is set via /proc/sys.
-*/
-char modprobe_path[256] = "/sbin/modprobe";
+ * This is the task which runs the usermode application
+ */
+static int ____call_usermodehelper(void *data)
+{
+ struct subprocess_info *sub_info = data;
+ int retval;
-static int exec_modprobe(void * module_name)
+ retval = -EPERM;
+ if (current->fs->root)
+ retval = exec_usermodehelper(sub_info->path, sub_info->argv, sub_info->envp);
+
+ /* Exec failed? */
+ sub_info->retval = (pid_t)retval;
+ do_exit(0);
+}
+
+/* Keventd can't block, but this (a child) can. */
+static int wait_for_helper(void *data)
{
- static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
- char *argv[] = { modprobe_path, "--", (char*)module_name, NULL };
- int ret;
+ struct subprocess_info *sub_info = data;
+ pid_t pid;
- if (!system_running)
- return -EBUSY;
+ pid = kernel_thread(____call_usermodehelper, sub_info,
+ CLONE_VFORK | SIGCHLD);
+ if (pid < 0)
+ sub_info->retval = pid;
+ else
+ sys_wait4(pid, NULL, 0, NULL);
- ret = exec_usermodehelper(modprobe_path, argv, envp);
- if (ret) {
- static unsigned long last;
- unsigned long now = jiffies;
- if (now - last > HZ) {
- last = now;
- printk(KERN_DEBUG
- "kmod: failed to exec %s -s -k %s, errno = %d\n",
- modprobe_path, (char*) module_name, errno);
- }
- }
- return ret;
+ complete(sub_info->complete);
+ return 0;
+}
+
+/*
+ * This is run by keventd.
+ */
+static void __call_usermodehelper(void *data)
+{
+ struct subprocess_info *sub_info = data;
+ pid_t pid;
+
+ /* CLONE_VFORK: wait until the usermode helper has execve'd
+ * successfully We need the data structures to stay around
+ * until that is done. */
+ if (sub_info->wait)
+ pid = kernel_thread(wait_for_helper, sub_info,
+ CLONE_KERNEL | SIGCHLD);
+ else
+ pid = kernel_thread(____call_usermodehelper, sub_info,
+ CLONE_VFORK | SIGCHLD);
+
+ if (pid < 0) {
+ sub_info->retval = pid;
+ complete(sub_info->complete);
+ } else if (!sub_info->wait)
+ complete(sub_info->complete);
}
+#ifdef CONFIG_KMOD
+
+/*
+ modprobe_path is set via /proc/sys.
+*/
+char modprobe_path[256] = "/sbin/modprobe";
+
/**
* request_module - try to load a kernel module
* @module_name: Name of module
@@ -189,24 +238,33 @@ static int exec_modprobe(void * module_n
* If module auto-loading support is disabled then this function
* becomes a no-operation.
*/
-int request_module(const char * module_name)
+int request_module(const char *module_name)
{
- pid_t pid;
- int waitpid_result;
- sigset_t tmpsig;
- int i, ret;
+ unsigned int max_modprobes;
+ DECLARE_COMPLETION(done);
+ char *argv[] = { modprobe_path, "--", (char*)module_name, NULL };
+ static char *envp[] = { "HOME=/",
+ "TERM=linux",
+ "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
+ NULL };
+ struct subprocess_info sub_info = {
+ .complete = &done,
+ .path = modprobe_path,
+ .argv = argv,
+ .envp = envp,
+ .wait = 1, /* We need to wait. */
+ .retval = 0,
+ };
+ DECLARE_WORK(work, __call_usermodehelper, &sub_info);
static atomic_t kmod_concurrent = ATOMIC_INIT(0);
#define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */
static int kmod_loop_msg;
- unsigned long saved_policy = current->policy;
- current->policy = SCHED_NORMAL;
- /* Don't allow request_module() when the system isn't set up */
- if ( ! system_running ) {
- printk(KERN_ERR "request_module[%s]: not ready\n", module_name);
- ret = -EPERM;
- goto out;
- }
+ if (!system_running)
+ return -EBUSY;
+
+ if (modprobe_path[0] == '\0')
+ return 0;
/* If modprobe needs a service that is in a module, we get a recursive
* loop. Limit the number of running kmod threads to max_threads/2 or
@@ -216,52 +274,39 @@ int request_module(const char * module_n
* process tables to get the command line, proc_pid_cmdline is static
* and it is not worth changing the proc code just to handle this case.
* KAO.
+ *
+
+ * "trace the ppid" is simple, but will fail if someone's
+ * parent exits. I think this is as good as it gets. --RR
*/
- i = max_threads/2;
- if (i > MAX_KMOD_CONCURRENT)
- i = MAX_KMOD_CONCURRENT;
+ max_modprobes = min(max_threads/2, MAX_KMOD_CONCURRENT);
atomic_inc(&kmod_concurrent);
- if (atomic_read(&kmod_concurrent) > i) {
+ if (atomic_read(&kmod_concurrent) > max_modprobes) {
+ /* We may be blaming an innocent here, but unlikely */
if (kmod_loop_msg++ < 5)
printk(KERN_ERR
- "kmod: runaway modprobe loop assumed and stopped\n");
- atomic_dec(&kmod_concurrent);
- ret = -ENOMEM;
- goto out;
- }
-
- pid = kernel_thread(exec_modprobe, (void*) module_name, 0);
- if (pid < 0) {
- printk(KERN_ERR "request_module[%s]: fork failed, errno %d\n", module_name, -pid);
+ "request_module: runaway loop modprobe %s\n",
+ module_name);
atomic_dec(&kmod_concurrent);
- ret = pid;
- goto out;
+ return -ENOMEM;
}
- /* Block everything but SIGKILL/SIGSTOP */
- spin_lock_irq(¤t->sig->siglock);
- tmpsig = current->blocked;
- siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
- recalc_sigpending();
- spin_unlock_irq(¤t->sig->siglock);
-
- waitpid_result = waitpid(pid, NULL, __WCLONE);
- atomic_dec(&kmod_concurrent);
-
- /* Allow signals again.. */
- spin_lock_irq(¤t->sig->siglock);
- current->blocked = tmpsig;
- recalc_sigpending();
- spin_unlock_irq(¤t->sig->siglock);
+ schedule_work(&work);
+ wait_for_completion(&done);
- if (waitpid_result != pid) {
- printk(KERN_ERR "request_module[%s]: waitpid(%d,...) failed, errno %d\n",
- module_name, pid, -waitpid_result);
+ /* This is exec failing, not modprobe failing. */
+ if (sub_info.retval < 0) {
+ static unsigned long last;
+ unsigned long now = jiffies;
+ if (now - last > HZ) {
+ last = now;
+ printk(KERN_DEBUG
+ "request_module: failed %s -- %s. error = %d\n",
+ modprobe_path, module_name, sub_info.retval);
+ }
}
- ret = 0;
-out:
- current->policy = saved_policy;
- return ret;
+ atomic_dec(&kmod_concurrent);
+ return sub_info.retval;
}
#endif /* CONFIG_KMOD */
@@ -289,49 +334,6 @@ EXPORT_SYMBOL(hotplug_path);
#endif /* CONFIG_HOTPLUG */
-struct subprocess_info {
- struct completion *complete;
- char *path;
- char **argv;
- char **envp;
- pid_t retval;
-};
-
-/*
- * This is the task which runs the usermode application
- */
-static int ____call_usermodehelper(void *data)
-{
- struct subprocess_info *sub_info = data;
- int retval;
-
- retval = -EPERM;
- if (current->fs->root)
- retval = exec_usermodehelper(sub_info->path, sub_info->argv, sub_info->envp);
-
- /* Exec failed? */
- sub_info->retval = (pid_t)retval;
- do_exit(0);
-}
-
-/*
- * This is run by keventd.
- */
-static void __call_usermodehelper(void *data)
-{
- struct subprocess_info *sub_info = data;
- pid_t pid;
-
- /*
- * CLONE_VFORK: wait until the usermode helper has execve'd successfully
- * We need the data structures to stay around until that is done.
- */
- pid = kernel_thread(____call_usermodehelper, sub_info, CLONE_VFORK | SIGCHLD);
- if (pid < 0)
- sub_info->retval = pid;
- complete(sub_info->complete);
-}
-
/**
* call_usermodehelper - start a usermode application
* @path: pathname for the application
@@ -353,6 +355,7 @@ int call_usermodehelper(char *path, char
.path = path,
.argv = argv,
.envp = envp,
+ .wait = 0,
.retval = 0,
};
DECLARE_WORK(work, __call_usermodehelper, &sub_info);
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH] Deprecate exec_usermodehelper, fix request_module. 2003-01-02 9:36 [PATCH] Deprecate exec_usermodehelper, fix request_module Rusty Russell @ 2003-01-02 17:14 ` Marcel Holtmann 2003-01-02 19:08 ` Thomas Sailer 0 siblings, 1 reply; 7+ messages in thread From: Marcel Holtmann @ 2003-01-02 17:14 UTC (permalink / raw) To: Rusty Russell Cc: Linus Torvalds, Linux Kernel Mailing List, akpm, Thomas Sailer, Jose Orlando Pereira, J.E.J.Bottomley Hi Rusty, > I got a report from Urban Widmark that modprobe dropped its privs on > executing an install command: turns out request_module > (ie. exec_usermodehelper) doesn't set the real uid or gid (so bash > drops privs). > > These efforts to "clean" the current process are *always* going to be > buggy: we should use the event thread all the time, rather than > forking a random thread and trying to clean it. This fixes > request_module to do that (kevent threads can't block, so we > double-fork). > > There are still three > (obscure) users of exec_usermodehelper in the tree: > > drivers/net/hamradio/baycom_epp.c > drivers/bluetooth/bt3c_cs.c > arch/i386/mach-voyager/voyager_thread.c for the bt3c_cs driver I need to run a user space program that downloads the firmware into the card and the kernel part have to wait until this program has finished. So what is the best way to do this now? Regards Marcel ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Deprecate exec_usermodehelper, fix request_module. 2003-01-02 17:14 ` Marcel Holtmann @ 2003-01-02 19:08 ` Thomas Sailer 2003-01-03 5:08 ` Rusty Russell 0 siblings, 1 reply; 7+ messages in thread From: Thomas Sailer @ 2003-01-02 19:08 UTC (permalink / raw) To: Marcel Holtmann Cc: Rusty Russell, Linux Kernel Mailing List, akpm, Jose Orlando Pereira, J.E.J.Bottomley On Thu, 2003-01-02 at 18:14, Marcel Holtmann wrote: > for the bt3c_cs driver I need to run a user space program that downloads > the firmware into the card and the kernel part have to wait until this > program has finished. So what is the best way to do this now? We all seem to have the same problem 8-) Rusty's new proposal with the wait argument seems to solve our problem, except that it would be nice if there was a way to retrieve the exit status of the user mode helper program. Tom ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Deprecate exec_usermodehelper, fix request_module. 2003-01-02 19:08 ` Thomas Sailer @ 2003-01-03 5:08 ` Rusty Russell 2003-01-03 6:21 ` Brad Hards 0 siblings, 1 reply; 7+ messages in thread From: Rusty Russell @ 2003-01-03 5:08 UTC (permalink / raw) To: Thomas Sailer Cc: Linux Kernel Mailing List, akpm, Jose Orlando Pereira, J.E.J.Bottomley In message <1041534508.2074.32.camel@gamecube> you write: > On Thu, 2003-01-02 at 18:14, Marcel Holtmann wrote: > > > for the bt3c_cs driver I need to run a user space program that downloads > > the firmware into the card and the kernel part have to wait until this > > program has finished. So what is the best way to do this now? > > We all seem to have the same problem 8-) > > Rusty's new proposal with the wait argument seems to solve our problem, > except that it would be nice if there was a way to retrieve the exit > status of the user mode helper program. OK, how's this. Positive means it's the exit code (only if wait is set). Cheers! Rusty. -- Anyone who quotes me in their sig is an idiot. -- Rusty Russell. Name: call_usermodehelper can wait for us: exec_usermodehelper sucks Author: Rusty Russell Status: Tested on 2.5.54 D: Urban Widmark points out that modprobe calls system() in many D: configurations, which drops privs since request_module() doesn't D: doesn't set ruid and rguid. D: D: Use a known-clean environment (as call_usermodehelper does). D: Deprecate exec_usermodehelper, since it's probably buggy, maybe D: exploitable. diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5-bk/include/linux/kmod.h working-2.5-bk-kmod-noclean/include/linux/kmod.h --- linux-2.5-bk/include/linux/kmod.h Thu Jan 2 12:35:15 2003 +++ working-2.5-bk-kmod-noclean/include/linux/kmod.h Fri Jan 3 14:50:30 2003 @@ -21,6 +21,7 @@ #include <linux/config.h> #include <linux/errno.h> +#include <linux/compiler.h> #ifdef CONFIG_KMOD extern int request_module(const char * name); @@ -29,8 +30,8 @@ static inline int request_module(const c #endif #define try_then_request_module(x, mod) ((x) ?: request_module(mod), (x)) -extern int exec_usermodehelper(char *program_path, char *argv[], char *envp[]); -extern int call_usermodehelper(char *path, char *argv[], char *envp[]); +extern int exec_usermodehelper(char *program_path, char *argv[], char *envp[]) __deprecated; +extern int call_usermodehelper(char *path, char *argv[], char *envp[], int wait); #ifdef CONFIG_HOTPLUG extern char hotplug_path []; diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5-bk/kernel/kmod.c working-2.5-bk-kmod-noclean/kernel/kmod.c --- linux-2.5-bk/kernel/kmod.c Thu Jan 2 12:37:03 2003 +++ working-2.5-bk-kmod-noclean/kernel/kmod.c Fri Jan 3 16:02:55 2003 @@ -14,8 +14,10 @@ Unblock all signals when we exec a usermode process. Shuu Yamaguchi <shuu@wondernetworkresources.com> December 2000 -*/ + call_usermodehelper wait flag, and deprecate exec_usermodehelper. + Rusty Russell <rusty@rustcorp.com.au> Jan 2003 +*/ #define __KERNEL_SYSCALLS__ #include <linux/config.h> @@ -31,6 +33,7 @@ #include <linux/workqueue.h> #include <linux/security.h> #include <linux/mount.h> +#include <linux/kernel.h> #include <asm/uaccess.h> extern int max_threads, system_running; @@ -153,29 +156,6 @@ int exec_usermodehelper(char *program_pa */ char modprobe_path[256] = "/sbin/modprobe"; -static int exec_modprobe(void * module_name) -{ - static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; - char *argv[] = { modprobe_path, "--", (char*)module_name, NULL }; - int ret; - - if (!system_running) - return -EBUSY; - - ret = exec_usermodehelper(modprobe_path, argv, envp); - if (ret) { - static unsigned long last; - unsigned long now = jiffies; - if (now - last > HZ) { - last = now; - printk(KERN_DEBUG - "kmod: failed to exec %s -s -k %s, errno = %d\n", - modprobe_path, (char*) module_name, errno); - } - } - return ret; -} - /** * request_module - try to load a kernel module * @module_name: Name of module @@ -189,24 +169,18 @@ static int exec_modprobe(void * module_n * If module auto-loading support is disabled then this function * becomes a no-operation. */ -int request_module(const char * module_name) +int request_module(const char *module_name) { - pid_t pid; - int waitpid_result; - sigset_t tmpsig; - int i, ret; + unsigned int max_modprobes; + int ret; + char *argv[] = { modprobe_path, "--", (char*)module_name, NULL }; + static char *envp[] = { "HOME=/", + "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", + NULL }; static atomic_t kmod_concurrent = ATOMIC_INIT(0); #define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */ static int kmod_loop_msg; - unsigned long saved_policy = current->policy; - - current->policy = SCHED_NORMAL; - /* Don't allow request_module() when the system isn't set up */ - if ( ! system_running ) { - printk(KERN_ERR "request_module[%s]: not ready\n", module_name); - ret = -EPERM; - goto out; - } /* If modprobe needs a service that is in a module, we get a recursive * loop. Limit the number of running kmod threads to max_threads/2 or @@ -216,56 +190,39 @@ int request_module(const char * module_n * process tables to get the command line, proc_pid_cmdline is static * and it is not worth changing the proc code just to handle this case. * KAO. + * + + * "trace the ppid" is simple, but will fail if someone's + * parent exits. I think this is as good as it gets. --RR */ - i = max_threads/2; - if (i > MAX_KMOD_CONCURRENT) - i = MAX_KMOD_CONCURRENT; + max_modprobes = min(max_threads/2, MAX_KMOD_CONCURRENT); atomic_inc(&kmod_concurrent); - if (atomic_read(&kmod_concurrent) > i) { + if (atomic_read(&kmod_concurrent) > max_modprobes) { + /* We may be blaming an innocent here, but unlikely */ if (kmod_loop_msg++ < 5) printk(KERN_ERR - "kmod: runaway modprobe loop assumed and stopped\n"); + "request_module: runaway loop modprobe %s\n", + module_name); atomic_dec(&kmod_concurrent); - ret = -ENOMEM; - goto out; + return -ENOMEM; } - pid = kernel_thread(exec_modprobe, (void*) module_name, 0); - if (pid < 0) { - printk(KERN_ERR "request_module[%s]: fork failed, errno %d\n", module_name, -pid); - atomic_dec(&kmod_concurrent); - ret = pid; - goto out; + ret = call_usermodehelper(modprobe_path, argv, envp, 1); + if (ret < 0) { /* Exec failed, or fork failed or something bad */ + static unsigned long last; + unsigned long now = jiffies; + if (now - last > HZ) { + last = now; + printk(KERN_DEBUG + "request_module: failed %s -- %s. error = %d\n", + modprobe_path, module_name, -ret); + } } - - /* Block everything but SIGKILL/SIGSTOP */ - spin_lock_irq(¤t->sig->siglock); - tmpsig = current->blocked; - siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)); - recalc_sigpending(); - spin_unlock_irq(¤t->sig->siglock); - - waitpid_result = waitpid(pid, NULL, __WCLONE); atomic_dec(&kmod_concurrent); - - /* Allow signals again.. */ - spin_lock_irq(¤t->sig->siglock); - current->blocked = tmpsig; - recalc_sigpending(); - spin_unlock_irq(¤t->sig->siglock); - - if (waitpid_result != pid) { - printk(KERN_ERR "request_module[%s]: waitpid(%d,...) failed, errno %d\n", - module_name, pid, -waitpid_result); - } - ret = 0; -out: - current->policy = saved_policy; - return ret; + return ret < 0 ? ret : 0; } #endif /* CONFIG_KMOD */ - #ifdef CONFIG_HOTPLUG /* hotplug path is set via /proc/sys @@ -294,7 +251,8 @@ struct subprocess_info { char *path; char **argv; char **envp; - pid_t retval; + int wait; + int retval; }; /* @@ -310,10 +268,27 @@ static int ____call_usermodehelper(void retval = exec_usermodehelper(sub_info->path, sub_info->argv, sub_info->envp); /* Exec failed? */ - sub_info->retval = (pid_t)retval; + sub_info->retval = retval; do_exit(0); } +/* Keventd can't block, but this (a child) can. */ +static int wait_for_helper(void *data) +{ + struct subprocess_info *sub_info = data; + pid_t pid; + + pid = kernel_thread(____call_usermodehelper, sub_info, + CLONE_VFORK | SIGCHLD); + if (pid < 0) + sub_info->retval = pid; + else + sys_wait4(pid, (unsigned int *)&sub_info->retval, 0, NULL); + + complete(sub_info->complete); + return 0; +} + /* * This is run by keventd. */ @@ -322,14 +297,21 @@ static void __call_usermodehelper(void * struct subprocess_info *sub_info = data; pid_t pid; - /* - * CLONE_VFORK: wait until the usermode helper has execve'd successfully - * We need the data structures to stay around until that is done. - */ - pid = kernel_thread(____call_usermodehelper, sub_info, CLONE_VFORK | SIGCHLD); - if (pid < 0) + /* CLONE_VFORK: wait until the usermode helper has execve'd + * successfully We need the data structures to stay around + * until that is done. */ + if (sub_info->wait) + pid = kernel_thread(wait_for_helper, sub_info, + CLONE_KERNEL | SIGCHLD); + else + pid = kernel_thread(____call_usermodehelper, sub_info, + CLONE_VFORK | SIGCHLD); + + if (pid < 0) { sub_info->retval = pid; - complete(sub_info->complete); + complete(sub_info->complete); + } else if (!sub_info->wait) + complete(sub_info->complete); } /** @@ -337,15 +319,17 @@ static void __call_usermodehelper(void * * @path: pathname for the application * @argv: null-terminated argument list * @envp: null-terminated environment list + * @wait: wait for the application to finish and return status. * - * Runs a user-space application. The application is started asynchronously. It - * runs as a child of keventd. It runs with full root capabilities. keventd silently - * reaps the child when it exits. + * Runs a user-space application. The application is started + * asynchronously if wait is not set, and runs as a child of keventd. + * (ie. it runs with full root capabilities). * - * Must be called from process context. Returns zero on success, else a negative - * error code. + * Must be called from process context. Returns a negative error code + * if program was not execed successfully, or (exitcode << 8 + signal) + * of the application (0 if wait is not set). */ -int call_usermodehelper(char *path, char **argv, char **envp) +int call_usermodehelper(char *path, char **argv, char **envp, int wait) { DECLARE_COMPLETION(done); struct subprocess_info sub_info = { @@ -353,6 +337,7 @@ int call_usermodehelper(char *path, char .path = path, .argv = argv, .envp = envp, + .wait = wait, .retval = 0, }; DECLARE_WORK(work, __call_usermodehelper, &sub_info); diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5-bk/drivers/acpi/thermal.c working-2.5-bk-kmod-noclean/drivers/acpi/thermal.c --- linux-2.5-bk/drivers/acpi/thermal.c Thu Jan 2 12:47:01 2003 +++ working-2.5-bk-kmod-noclean/drivers/acpi/thermal.c Fri Jan 3 14:50:30 2003 @@ -431,7 +431,7 @@ acpi_thermal_call_usermode ( envp[0] = "HOME=/"; envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; - call_usermodehelper(argv[0], argv, envp); + call_usermodehelper(argv[0], argv, envp, 0); return_VALUE(0); } diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5-bk/drivers/base/hotplug.c working-2.5-bk-kmod-noclean/drivers/base/hotplug.c --- linux-2.5-bk/drivers/base/hotplug.c Thu Jan 2 12:46:16 2003 +++ working-2.5-bk-kmod-noclean/drivers/base/hotplug.c Fri Jan 3 14:50:30 2003 @@ -114,7 +114,7 @@ static int do_hotplug (struct device *de pr_debug ("%s: %s %s %s %s %s %s\n", __FUNCTION__, argv [0], argv[1], envp[0], envp[1], envp[2], envp[3]); - retval = call_usermodehelper (argv [0], argv, envp); + retval = call_usermodehelper (argv [0], argv, envp, 0); if (retval) pr_debug ("%s - call_usermodehelper returned %d\n", __FUNCTION__, retval); diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5-bk/drivers/ieee1394/nodemgr.c working-2.5-bk-kmod-noclean/drivers/ieee1394/nodemgr.c --- linux-2.5-bk/drivers/ieee1394/nodemgr.c Thu Jan 2 12:46:17 2003 +++ working-2.5-bk-kmod-noclean/drivers/ieee1394/nodemgr.c Fri Jan 3 14:50:30 2003 @@ -786,7 +786,7 @@ static void nodemgr_call_policy(char *ve #ifdef CONFIG_IEEE1394_VERBOSEDEBUG HPSB_DEBUG("NodeMgr: %s %s %016Lx", argv[0], verb, (long long unsigned)ud->ne->guid); #endif - value = call_usermodehelper(argv[0], argv, envp); + value = call_usermodehelper(argv[0], argv, envp, 0); kfree(buf); kfree(envp); if (value != 0) diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5-bk/drivers/input/input.c working-2.5-bk-kmod-noclean/drivers/input/input.c --- linux-2.5-bk/drivers/input/input.c Thu Jan 2 12:30:27 2003 +++ working-2.5-bk-kmod-noclean/drivers/input/input.c Fri Jan 3 14:50:30 2003 @@ -383,7 +383,7 @@ static void input_call_hotplug(char *ver argv[0], argv[1], envp[0], envp[1], envp[2], envp[3], envp[4]); #endif - value = call_usermodehelper(argv [0], argv, envp); + value = call_usermodehelper(argv [0], argv, envp, 0); kfree(buf); kfree(envp); diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5-bk/drivers/isdn/hardware/eicon/divasmain.c working-2.5-bk-kmod-noclean/drivers/isdn/hardware/eicon/divasmain.c --- linux-2.5-bk/drivers/isdn/hardware/eicon/divasmain.c Thu Jan 2 12:45:18 2003 +++ working-2.5-bk-kmod-noclean/drivers/isdn/hardware/eicon/divasmain.c Fri Jan 3 14:50:30 2003 @@ -263,7 +263,7 @@ static void diva_adapter_trapped(void *c pdpc->card_failed = 0; argv[2] = &adapter[0]; - ret = call_usermodehelper(argv[0], argv, envp); + ret = call_usermodehelper(argv[0], argv, envp, 0); if (ret) { printk(KERN_ERR diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5-bk/drivers/pnp/pnpbios/core.c working-2.5-bk-kmod-noclean/drivers/pnp/pnpbios/core.c --- linux-2.5-bk/drivers/pnp/pnpbios/core.c Thu Jan 2 14:47:59 2003 +++ working-2.5-bk-kmod-noclean/drivers/pnp/pnpbios/core.c Fri Jan 3 14:50:30 2003 @@ -602,7 +602,7 @@ static int pnp_dock_event(int dock, stru info->location_id, info->serial, info->capabilities); envp[i] = 0; - value = call_usermodehelper (argv [0], argv, envp); + value = call_usermodehelper (argv [0], argv, envp, 0); kfree (buf); kfree (envp); return 0; diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5-bk/net/bluetooth/hci_core.c working-2.5-bk-kmod-noclean/net/bluetooth/hci_core.c --- linux-2.5-bk/net/bluetooth/hci_core.c Thu Jan 2 12:33:56 2003 +++ working-2.5-bk-kmod-noclean/net/bluetooth/hci_core.c Fri Jan 3 14:50:30 2003 @@ -114,7 +114,7 @@ static int hci_run_hotplug(char *dev, ch envp[3] = astr; envp[4] = NULL; - return call_usermodehelper(argv[0], argv, envp); + return call_usermodehelper(argv[0], argv, envp, 0); } #else #define hci_run_hotplug(A...) diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5-bk/net/core/dev.c working-2.5-bk-kmod-noclean/net/core/dev.c --- linux-2.5-bk/net/core/dev.c Thu Jan 2 14:48:01 2003 +++ working-2.5-bk-kmod-noclean/net/core/dev.c Fri Jan 3 14:50:30 2003 @@ -2918,6 +2918,6 @@ static int net_run_sbin_hotplug(struct n envp [i++] = action_str; envp [i] = 0; - return call_usermodehelper(argv [0], argv, envp); + return call_usermodehelper(argv [0], argv, envp, 0); } #endif ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Deprecate exec_usermodehelper, fix request_module. 2003-01-03 5:08 ` Rusty Russell @ 2003-01-03 6:21 ` Brad Hards 2003-01-03 7:25 ` Jeff Garzik 2003-01-03 7:36 ` Andrew Morton 0 siblings, 2 replies; 7+ messages in thread From: Brad Hards @ 2003-01-03 6:21 UTC (permalink / raw) To: Rusty Russell; +Cc: Linux Kernel Mailing List -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Fri, 3 Jan 2003 16:08, Rusty Russell wrote: > + * Must be called from process context. Returns a negative error code > + * if program was not execed successfully, or (exitcode << 8 + signal) > + * of the application (0 if wait is not set). Any chance that you can remove this (existing) restriction. It'd be good to be able to use this in some networking code (eg netif_carrier_[off|on]() ), but that might be in interrupt context. It may be just a matter of duplicating the arguments, but I really know SFA about this stuff, and am loath to touch it least it turn to mush in my fingers. Brad - -- http://linux.conf.au. 22-25Jan2003. Perth, Aust. I'm registered. Are you? -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.0.6 (GNU/Linux) Comment: For info see http://www.gnupg.org iD8DBQE+FSwLW6pHgIdAuOMRAgMxAKChfs9HtklDxSUfFDkcrPf/Sk269gCfUYvX er/EOyc0FZGZV031E0+Ymy4= =SvBh -----END PGP SIGNATURE----- ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Deprecate exec_usermodehelper, fix request_module. 2003-01-03 6:21 ` Brad Hards @ 2003-01-03 7:25 ` Jeff Garzik 2003-01-03 7:36 ` Andrew Morton 1 sibling, 0 replies; 7+ messages in thread From: Jeff Garzik @ 2003-01-03 7:25 UTC (permalink / raw) To: Brad Hards; +Cc: Rusty Russell, Linux Kernel Mailing List On Fri, Jan 03, 2003 at 05:21:57PM +1100, Brad Hards wrote: > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > On Fri, 3 Jan 2003 16:08, Rusty Russell wrote: > > + * Must be called from process context. Returns a negative error code > > + * if program was not execed successfully, or (exitcode << 8 + signal) > > + * of the application (0 if wait is not set). > Any chance that you can remove this (existing) restriction. It'd be good to be > able to use this in some networking code (eg netif_carrier_[off|on]() ), but > that might be in interrupt context. The link up/down notifications added in recent 2.5.x should eliminate a need to fiddle while in interrupt context... ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Deprecate exec_usermodehelper, fix request_module. 2003-01-03 6:21 ` Brad Hards 2003-01-03 7:25 ` Jeff Garzik @ 2003-01-03 7:36 ` Andrew Morton 1 sibling, 0 replies; 7+ messages in thread From: Andrew Morton @ 2003-01-03 7:36 UTC (permalink / raw) To: Brad Hards; +Cc: Rusty Russell, Linux Kernel Mailing List Brad Hards wrote: > > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > On Fri, 3 Jan 2003 16:08, Rusty Russell wrote: > > + * Must be called from process context. Returns a negative error code > > + * if program was not execed successfully, or (exitcode << 8 + signal) > > + * of the application (0 if wait is not set). > Any chance that you can remove this (existing) restriction. It'd be good to be > able to use this in some networking code (eg netif_carrier_[off|on]() ), but > that might be in interrupt context. > > It may be just a matter of duplicating the arguments, but I really know SFA > about this stuff, and am loath to touch it least it turn to mush in my > fingers. > I vaguely seem to recall having done that once. It wasn't very pretty: int gfp_flags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; Patch against 2.4.0-test13 is at http://www.zip.com.au/~akpm/linux/1.txt ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2003-01-03 7:28 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2003-01-02 9:36 [PATCH] Deprecate exec_usermodehelper, fix request_module Rusty Russell 2003-01-02 17:14 ` Marcel Holtmann 2003-01-02 19:08 ` Thomas Sailer 2003-01-03 5:08 ` Rusty Russell 2003-01-03 6:21 ` Brad Hards 2003-01-03 7:25 ` Jeff Garzik 2003-01-03 7:36 ` Andrew Morton
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox