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/module.h>
24#include <linux/sched.h>
25#include <linux/syscalls.h>
26#include <linux/unistd.h>
27#include <linux/kmod.h>
28#include <linux/smp_lock.h>
29#include <linux/slab.h>
30#include <linux/namespace.h>
31#include <linux/completion.h>
32#include <linux/file.h>
33#include <linux/workqueue.h>
34#include <linux/security.h>
35#include <linux/mount.h>
36#include <linux/kernel.h>
37#include <linux/init.h>
38#include <asm/uaccess.h>
39
40extern int max_threads;
41
42static struct workqueue_struct *khelper_wq;
43
44#ifdef CONFIG_KMOD
45
46
47
48
49char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe";
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65int request_module(const char *fmt, ...)
66{
67 va_list args;
68 char module_name[MODULE_NAME_LEN];
69 unsigned int max_modprobes;
70 int ret;
71 char *argv[] = { modprobe_path, "-q", "--", module_name, NULL };
72 static char *envp[] = { "HOME=/",
73 "TERM=linux",
74 "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
75 NULL };
76 static atomic_t kmod_concurrent = ATOMIC_INIT(0);
77#define MAX_KMOD_CONCURRENT 50
78 static int kmod_loop_msg;
79
80 va_start(args, fmt);
81 ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args);
82 va_end(args);
83 if (ret >= MODULE_NAME_LEN)
84 return -ENAMETOOLONG;
85
86
87
88
89
90
91
92
93
94
95
96
97
98 max_modprobes = min(max_threads/2, MAX_KMOD_CONCURRENT);
99 atomic_inc(&kmod_concurrent);
100 if (atomic_read(&kmod_concurrent) > max_modprobes) {
101
102 if (kmod_loop_msg++ < 5)
103 printk(KERN_ERR
104 "request_module: runaway loop modprobe %s\n",
105 module_name);
106 atomic_dec(&kmod_concurrent);
107 return -ENOMEM;
108 }
109
110 ret = call_usermodehelper(modprobe_path, argv, envp, 1);
111 atomic_dec(&kmod_concurrent);
112 return ret;
113}
114EXPORT_SYMBOL(request_module);
115#endif
116
117struct subprocess_info {
118 struct completion *complete;
119 char *path;
120 char **argv;
121 char **envp;
122 struct key *ring;
123 int wait;
124 int retval;
125};
126
127
128
129
130static int ____call_usermodehelper(void *data)
131{
132 struct subprocess_info *sub_info = data;
133 struct key *new_session, *old_session;
134 int retval;
135
136
137 new_session = key_get(sub_info->ring);
138 flush_signals(current);
139 spin_lock_irq(¤t->sighand->siglock);
140 old_session = __install_session_keyring(current, new_session);
141 flush_signal_handlers(current, 1);
142 sigemptyset(¤t->blocked);
143 recalc_sigpending();
144 spin_unlock_irq(¤t->sighand->siglock);
145
146 key_put(old_session);
147
148
149 set_cpus_allowed(current, CPU_MASK_ALL);
150
151 retval = -EPERM;
152 if (current->fs->root)
153 retval = execve(sub_info->path, sub_info->argv,sub_info->envp);
154
155
156 sub_info->retval = retval;
157 do_exit(0);
158}
159
160
161static int wait_for_helper(void *data)
162{
163 struct subprocess_info *sub_info = data;
164 pid_t pid;
165 struct k_sigaction sa;
166
167
168
169 sa.sa.sa_handler = SIG_IGN;
170 sa.sa.sa_flags = 0;
171 siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
172 do_sigaction(SIGCHLD, &sa, NULL);
173 allow_signal(SIGCHLD);
174
175 pid = kernel_thread(____call_usermodehelper, sub_info, SIGCHLD);
176 if (pid < 0) {
177 sub_info->retval = pid;
178 } else {
179
180
181
182
183
184
185
186
187
188 sys_wait4(pid, (int __user *) &sub_info->retval, 0, NULL);
189 }
190
191 complete(sub_info->complete);
192 return 0;
193}
194
195
196static void __call_usermodehelper(void *data)
197{
198 struct subprocess_info *sub_info = data;
199 pid_t pid;
200 int wait = sub_info->wait;
201
202
203
204
205 if (wait)
206 pid = kernel_thread(wait_for_helper, sub_info,
207 CLONE_FS | CLONE_FILES | SIGCHLD);
208 else
209 pid = kernel_thread(____call_usermodehelper, sub_info,
210 CLONE_VFORK | SIGCHLD);
211
212 if (pid < 0) {
213 sub_info->retval = pid;
214 complete(sub_info->complete);
215 } else if (!wait)
216 complete(sub_info->complete);
217}
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234int call_usermodehelper_keys(char *path, char **argv, char **envp,
235 struct key *session_keyring, int wait)
236{
237 DECLARE_COMPLETION_ONSTACK(done);
238 struct subprocess_info sub_info = {
239 .complete = &done,
240 .path = path,
241 .argv = argv,
242 .envp = envp,
243 .ring = session_keyring,
244 .wait = wait,
245 .retval = 0,
246 };
247 DECLARE_WORK(work, __call_usermodehelper, &sub_info);
248
249 if (!khelper_wq)
250 return -EBUSY;
251
252 if (path[0] == '\0')
253 return 0;
254
255 queue_work(khelper_wq, &work);
256 wait_for_completion(&done);
257 return sub_info.retval;
258}
259EXPORT_SYMBOL(call_usermodehelper_keys);
260
261void __init usermodehelper_init(void)
262{
263 khelper_wq = create_singlethread_workqueue("khelper");
264 BUG_ON(!khelper_wq);
265}
266