aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/kmod.h4
-rw-r--r--kernel/kmod.c55
2 files changed, 58 insertions, 1 deletions
diff --git a/include/linux/kmod.h b/include/linux/kmod.h
index 0db22a1ab474..10f505c8431d 100644
--- a/include/linux/kmod.h
+++ b/include/linux/kmod.h
@@ -47,4 +47,8 @@ call_usermodehelper(char *path, char **argv, char **envp, int wait)
47 47
48extern void usermodehelper_init(void); 48extern void usermodehelper_init(void);
49 49
50struct file;
51extern int call_usermodehelper_pipe(char *path, char *argv[], char *envp[],
52 struct file **filp);
53
50#endif /* __LINUX_KMOD_H__ */ 54#endif /* __LINUX_KMOD_H__ */
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 842f8015d7fd..5c63c53014a9 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -122,6 +122,7 @@ struct subprocess_info {
122 struct key *ring; 122 struct key *ring;
123 int wait; 123 int wait;
124 int retval; 124 int retval;
125 struct file *stdin;
125}; 126};
126 127
127/* 128/*
@@ -145,12 +146,26 @@ static int ____call_usermodehelper(void *data)
145 146
146 key_put(old_session); 147 key_put(old_session);
147 148
149 /* Install input pipe when needed */
150 if (sub_info->stdin) {
151 struct files_struct *f = current->files;
152 struct fdtable *fdt;
153 /* no races because files should be private here */
154 sys_close(0);
155 fd_install(0, sub_info->stdin);
156 spin_lock(&f->file_lock);
157 fdt = files_fdtable(f);
158 FD_SET(0, fdt->open_fds);
159 FD_CLR(0, fdt->close_on_exec);
160 spin_unlock(&f->file_lock);
161 }
162
148 /* We can run anywhere, unlike our parent keventd(). */ 163 /* We can run anywhere, unlike our parent keventd(). */
149 set_cpus_allowed(current, CPU_MASK_ALL); 164 set_cpus_allowed(current, CPU_MASK_ALL);
150 165
151 retval = -EPERM; 166 retval = -EPERM;
152 if (current->fs->root) 167 if (current->fs->root)
153 retval = execve(sub_info->path, sub_info->argv,sub_info->envp); 168 retval = execve(sub_info->path, sub_info->argv, sub_info->envp);
154 169
155 /* Exec failed? */ 170 /* Exec failed? */
156 sub_info->retval = retval; 171 sub_info->retval = retval;
@@ -268,6 +283,44 @@ int call_usermodehelper_keys(char *path, char **argv, char **envp,
268} 283}
269EXPORT_SYMBOL(call_usermodehelper_keys); 284EXPORT_SYMBOL(call_usermodehelper_keys);
270 285
286int call_usermodehelper_pipe(char *path, char **argv, char **envp,
287 struct file **filp)
288{
289 DECLARE_COMPLETION(done);
290 struct subprocess_info sub_info = {
291 .complete = &done,
292 .path = path,
293 .argv = argv,
294 .envp = envp,
295 .retval = 0,
296 };
297 struct file *f;
298 DECLARE_WORK(work, __call_usermodehelper, &sub_info);
299
300 if (!khelper_wq)
301 return -EBUSY;
302
303 if (path[0] == '\0')
304 return 0;
305
306 f = create_write_pipe();
307 if (!f)
308 return -ENOMEM;
309 *filp = f;
310
311 f = create_read_pipe(f);
312 if (!f) {
313 free_write_pipe(*filp);
314 return -ENOMEM;
315 }
316 sub_info.stdin = f;
317
318 queue_work(khelper_wq, &work);
319 wait_for_completion(&done);
320 return sub_info.retval;
321}
322EXPORT_SYMBOL(call_usermodehelper_pipe);
323
271void __init usermodehelper_init(void) 324void __init usermodehelper_init(void)
272{ 325{
273 khelper_wq = create_singlethread_workqueue("khelper"); 326 khelper_wq = create_singlethread_workqueue("khelper");