1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#define __KERNEL_SYSCALLS__
22
23#include <linux/config.h>
24#include <linux/module.h>
25#include <linux/sched.h>
26#include <linux/syscalls.h>
27#include <linux/unistd.h>
28#include <linux/kmod.h>
29#include <linux/smp_lock.h>
30#include <linux/slab.h>
31#include <linux/namespace.h>
32#include <linux/completion.h>
33#include <linux/file.h>
34#include <linux/workqueue.h>
35#include <linux/security.h>
36#include <linux/mount.h>
37#include <linux/kernel.h>
38#include <linux/init.h>
39#include <asm/uaccess.h>
40
41extern int max_threads;
42
43static struct workqueue_struct *khelper_wq;
44
45#ifdef CONFIG_KMOD
46
47
48
49
50char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe";
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66int request_module(const char *fmt, ...)
67{
68 va_list args;
69 char module_name[MODULE_NAME_LEN];
70 unsigned int max_modprobes;
71 int ret;
72 char *argv[] = { modprobe_path, "-q", "--", module_name, NULL };
73 static char *envp[] = { "HOME=/",
74 "TERM=linux",
75 "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
76 NULL };
77 static atomic_t kmod_concurrent = ATOMIC_INIT(0);
78#define MAX_KMOD_CONCURRENT 50
79 static int kmod_loop_msg;
80
81 va_start(args, fmt);
82 ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args);
83 va_end(args);
84 if (ret >= MODULE_NAME_LEN)
85 return -ENAMETOOLONG;
86
87
88
89
90
91
92
93
94
95
96
97
98
99 max_modprobes = min(max_threads/2, MAX_KMOD_CONCURRENT);
100 atomic_inc(&kmod_concurrent);
101 if (atomic_read(&kmod_concurrent) > max_modprobes) {
102
103 if (kmod_loop_msg++ < 5)
104 printk(KERN_ERR
105 "request_module: runaway loop modprobe %s\n",
106 module_name);
107 atomic_dec(&kmod_concurrent);
108 return -ENOMEM;
109 }
110
111 ret = call_usermodehelper(modprobe_path, argv, envp, 1);
112 atomic_dec(&kmod_concurrent);
113 return ret;
114}
115EXPORT_SYMBOL(request_module);
116#endif
117
118#ifdef CONFIG_HOTPLUG
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135char hotplug_path[KMOD_PATH_LEN] = "/sbin/hotplug";
136
137EXPORT_SYMBOL(hotplug_path);
138
139#endif
140
141struct subprocess_info {
142 struct completion *complete;
143 char *path;
144 char **argv;
145 char **envp;
146 struct key *ring;
147 int wait;
148 int retval;
149};
150
151
152
153
154static int ____exec_usermodehelper(char *path, char **argv, char **envp,
155 struct key *session_keyring)
156{
157 struct key *new_session, *old_session;
158 int retval;
159
160
161 new_session = key_get(session_keyring);
162 flush_signals(current);
163 spin_lock_irq(¤t->sighand->siglock);
164 old_session = __install_session_keyring(current, new_session);
165 flush_signal_handlers(current, 1);
166 sigemptyset(¤t->blocked);
167 recalc_sigpending();
168 spin_unlock_irq(¤t->sighand->siglock);
169
170 key_put(old_session);
171
172 retval = -EPERM;
173 if (current->fs->root)
174 retval = execve(path, argv, envp);
175
176 return retval;
177}
178
179int __exec_usermodehelper(char *path, char **argv, char **envp)
180{
181 return ____exec_usermodehelper(path, argv, envp, NULL);
182}
183
184EXPORT_SYMBOL_GPL(__exec_usermodehelper);
185
186
187
188
189static int ____call_usermodehelper(void *data)
190{
191 struct subprocess_info *sub_info = data;
192 int retval;
193
194
195 set_cpus_allowed(current, CPU_MASK_ALL);
196
197 retval = ____exec_usermodehelper(sub_info->path,
198 sub_info->argv, sub_info->envp, sub_info->ring);
199
200
201 sub_info->retval = retval;
202 do_exit(0);
203}
204
205
206static int wait_for_helper(void *data)
207{
208 struct subprocess_info *sub_info = data;
209 pid_t pid;
210 struct k_sigaction sa;
211
212
213
214 sa.sa.sa_handler = SIG_IGN;
215 sa.sa.sa_flags = 0;
216 siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
217 do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
218 allow_signal(SIGCHLD);
219
220 pid = kernel_thread(____call_usermodehelper, sub_info, SIGCHLD);
221 if (pid < 0) {
222 sub_info->retval = pid;
223 } else {
224
225
226
227
228
229
230
231
232
233 sys_wait4(pid, (int __user *) &sub_info->retval, 0, NULL);
234 }
235
236 complete(sub_info->complete);
237 return 0;
238}
239
240
241static void __call_usermodehelper(void *data)
242{
243 struct subprocess_info *sub_info = data;
244 pid_t pid;
245 int wait = sub_info->wait;
246
247
248
249
250 if (wait)
251 pid = kernel_thread(wait_for_helper, sub_info,
252 CLONE_FS | CLONE_FILES | SIGCHLD);
253 else
254 pid = kernel_thread(____call_usermodehelper, sub_info,
255 CLONE_VFORK | SIGCHLD);
256
257 if (pid < 0) {
258 sub_info->retval = pid;
259 complete(sub_info->complete);
260 } else if (!wait)
261 complete(sub_info->complete);
262}
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278int call_usermodehelper(char *path, char **argv, char **envp, int wait)
279{
280 DECLARE_COMPLETION(done);
281 struct subprocess_info sub_info = {
282 .complete = &done,
283 .path = path,
284 .argv = argv,
285 .envp = envp,
286 .wait = wait,
287 .retval = 0,
288 };
289 DECLARE_WORK(work, __call_usermodehelper, &sub_info);
290
291 if (!khelper_wq)
292 return -EBUSY;
293
294 if (path[0] == '\0')
295 return 0;
296
297 queue_work(khelper_wq, &work);
298 wait_for_completion(&done);
299 return sub_info.retval;
300}
301EXPORT_SYMBOL(call_usermodehelper);
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318int call_usermodehelper_keys(char *path, char **argv, char **envp,
319 struct key *session_keyring, int wait)
320{
321 DECLARE_COMPLETION(done);
322 struct subprocess_info sub_info = {
323 .complete = &done,
324 .path = path,
325 .argv = argv,
326 .envp = envp,
327 .ring = session_keyring,
328 .wait = wait,
329 .retval = 0,
330 };
331 DECLARE_WORK(work, __call_usermodehelper, &sub_info);
332
333 if (!khelper_wq)
334 return -EBUSY;
335
336 if (path[0] == '\0')
337 return 0;
338
339 queue_work(khelper_wq, &work);
340 wait_for_completion(&done);
341 return sub_info.retval;
342}
343EXPORT_SYMBOL(call_usermodehelper_keys);
344
345void __init usermodehelper_init(void)
346{
347 khelper_wq = create_singlethread_workqueue("khelper");
348 BUG_ON(!khelper_wq);
349}
350