aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/kmod.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kmod.c')
-rw-r--r--kernel/kmod.c124
1 files changed, 114 insertions, 10 deletions
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 9cd0591c96a2..47613dfb7b28 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -25,6 +25,7 @@
25#include <linux/kmod.h> 25#include <linux/kmod.h>
26#include <linux/slab.h> 26#include <linux/slab.h>
27#include <linux/completion.h> 27#include <linux/completion.h>
28#include <linux/cred.h>
28#include <linux/file.h> 29#include <linux/file.h>
29#include <linux/fdtable.h> 30#include <linux/fdtable.h>
30#include <linux/workqueue.h> 31#include <linux/workqueue.h>
@@ -43,6 +44,13 @@ extern int max_threads;
43 44
44static struct workqueue_struct *khelper_wq; 45static struct workqueue_struct *khelper_wq;
45 46
47#define CAP_BSET (void *)1
48#define CAP_PI (void *)2
49
50static kernel_cap_t usermodehelper_bset = CAP_FULL_SET;
51static kernel_cap_t usermodehelper_inheritable = CAP_FULL_SET;
52static DEFINE_SPINLOCK(umh_sysctl_lock);
53
46#ifdef CONFIG_MODULES 54#ifdef CONFIG_MODULES
47 55
48/* 56/*
@@ -132,6 +140,7 @@ EXPORT_SYMBOL(__request_module);
132static int ____call_usermodehelper(void *data) 140static int ____call_usermodehelper(void *data)
133{ 141{
134 struct subprocess_info *sub_info = data; 142 struct subprocess_info *sub_info = data;
143 struct cred *new;
135 int retval; 144 int retval;
136 145
137 spin_lock_irq(&current->sighand->siglock); 146 spin_lock_irq(&current->sighand->siglock);
@@ -147,12 +156,27 @@ static int ____call_usermodehelper(void *data)
147 */ 156 */
148 set_user_nice(current, 0); 157 set_user_nice(current, 0);
149 158
159 retval = -ENOMEM;
160 new = prepare_kernel_cred(current);
161 if (!new)
162 goto fail;
163
164 spin_lock(&umh_sysctl_lock);
165 new->cap_bset = cap_intersect(usermodehelper_bset, new->cap_bset);
166 new->cap_inheritable = cap_intersect(usermodehelper_inheritable,
167 new->cap_inheritable);
168 spin_unlock(&umh_sysctl_lock);
169
150 if (sub_info->init) { 170 if (sub_info->init) {
151 retval = sub_info->init(sub_info); 171 retval = sub_info->init(sub_info, new);
152 if (retval) 172 if (retval) {
173 abort_creds(new);
153 goto fail; 174 goto fail;
175 }
154 } 176 }
155 177
178 commit_creds(new);
179
156 retval = kernel_execve(sub_info->path, 180 retval = kernel_execve(sub_info->path,
157 (const char *const *)sub_info->argv, 181 (const char *const *)sub_info->argv,
158 (const char *const *)sub_info->envp); 182 (const char *const *)sub_info->envp);
@@ -245,7 +269,6 @@ static void __call_usermodehelper(struct work_struct *work)
245 } 269 }
246} 270}
247 271
248#ifdef CONFIG_PM_SLEEP
249/* 272/*
250 * If set, call_usermodehelper_exec() will exit immediately returning -EBUSY 273 * If set, call_usermodehelper_exec() will exit immediately returning -EBUSY
251 * (used for preventing user land processes from being created after the user 274 * (used for preventing user land processes from being created after the user
@@ -301,6 +324,15 @@ void usermodehelper_enable(void)
301 usermodehelper_disabled = 0; 324 usermodehelper_disabled = 0;
302} 325}
303 326
327/**
328 * usermodehelper_is_disabled - check if new helpers are allowed to be started
329 */
330bool usermodehelper_is_disabled(void)
331{
332 return usermodehelper_disabled;
333}
334EXPORT_SYMBOL_GPL(usermodehelper_is_disabled);
335
304static void helper_lock(void) 336static void helper_lock(void)
305{ 337{
306 atomic_inc(&running_helpers); 338 atomic_inc(&running_helpers);
@@ -312,12 +344,6 @@ static void helper_unlock(void)
312 if (atomic_dec_and_test(&running_helpers)) 344 if (atomic_dec_and_test(&running_helpers))
313 wake_up(&running_helpers_waitq); 345 wake_up(&running_helpers_waitq);
314} 346}
315#else /* CONFIG_PM_SLEEP */
316#define usermodehelper_disabled 0
317
318static inline void helper_lock(void) {}
319static inline void helper_unlock(void) {}
320#endif /* CONFIG_PM_SLEEP */
321 347
322/** 348/**
323 * call_usermodehelper_setup - prepare to call a usermode helper 349 * call_usermodehelper_setup - prepare to call a usermode helper
@@ -364,7 +390,7 @@ EXPORT_SYMBOL(call_usermodehelper_setup);
364 * context in which call_usermodehelper_exec is called. 390 * context in which call_usermodehelper_exec is called.
365 */ 391 */
366void call_usermodehelper_setfns(struct subprocess_info *info, 392void call_usermodehelper_setfns(struct subprocess_info *info,
367 int (*init)(struct subprocess_info *info), 393 int (*init)(struct subprocess_info *info, struct cred *new),
368 void (*cleanup)(struct subprocess_info *info), 394 void (*cleanup)(struct subprocess_info *info),
369 void *data) 395 void *data)
370{ 396{
@@ -418,6 +444,84 @@ unlock:
418} 444}
419EXPORT_SYMBOL(call_usermodehelper_exec); 445EXPORT_SYMBOL(call_usermodehelper_exec);
420 446
447static int proc_cap_handler(struct ctl_table *table, int write,
448 void __user *buffer, size_t *lenp, loff_t *ppos)
449{
450 struct ctl_table t;
451 unsigned long cap_array[_KERNEL_CAPABILITY_U32S];
452 kernel_cap_t new_cap;
453 int err, i;
454
455 if (write && (!capable(CAP_SETPCAP) ||
456 !capable(CAP_SYS_MODULE)))
457 return -EPERM;
458
459 /*
460 * convert from the global kernel_cap_t to the ulong array to print to
461 * userspace if this is a read.
462 */
463 spin_lock(&umh_sysctl_lock);
464 for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++) {
465 if (table->data == CAP_BSET)
466 cap_array[i] = usermodehelper_bset.cap[i];
467 else if (table->data == CAP_PI)
468 cap_array[i] = usermodehelper_inheritable.cap[i];
469 else
470 BUG();
471 }
472 spin_unlock(&umh_sysctl_lock);
473
474 t = *table;
475 t.data = &cap_array;
476
477 /*
478 * actually read or write and array of ulongs from userspace. Remember
479 * these are least significant 32 bits first
480 */
481 err = proc_doulongvec_minmax(&t, write, buffer, lenp, ppos);
482 if (err < 0)
483 return err;
484
485 /*
486 * convert from the sysctl array of ulongs to the kernel_cap_t
487 * internal representation
488 */
489 for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++)
490 new_cap.cap[i] = cap_array[i];
491
492 /*
493 * Drop everything not in the new_cap (but don't add things)
494 */
495 spin_lock(&umh_sysctl_lock);
496 if (write) {
497 if (table->data == CAP_BSET)
498 usermodehelper_bset = cap_intersect(usermodehelper_bset, new_cap);
499 if (table->data == CAP_PI)
500 usermodehelper_inheritable = cap_intersect(usermodehelper_inheritable, new_cap);
501 }
502 spin_unlock(&umh_sysctl_lock);
503
504 return 0;
505}
506
507struct ctl_table usermodehelper_table[] = {
508 {
509 .procname = "bset",
510 .data = CAP_BSET,
511 .maxlen = _KERNEL_CAPABILITY_U32S * sizeof(unsigned long),
512 .mode = 0600,
513 .proc_handler = proc_cap_handler,
514 },
515 {
516 .procname = "inheritable",
517 .data = CAP_PI,
518 .maxlen = _KERNEL_CAPABILITY_U32S * sizeof(unsigned long),
519 .mode = 0600,
520 .proc_handler = proc_cap_handler,
521 },
522 { }
523};
524
421void __init usermodehelper_init(void) 525void __init usermodehelper_init(void)
422{ 526{
423 khelper_wq = create_singlethread_workqueue("khelper"); 527 khelper_wq = create_singlethread_workqueue("khelper");