aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/capability.c4
-rw-r--r--kernel/cred.c6
-rw-r--r--kernel/kmod.c100
-rw-r--r--kernel/sysctl.c6
4 files changed, 109 insertions, 7 deletions
diff --git a/kernel/capability.c b/kernel/capability.c
index 32a80e08ff4b..283c529f8b1c 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -22,12 +22,8 @@
22 */ 22 */
23 23
24const kernel_cap_t __cap_empty_set = CAP_EMPTY_SET; 24const kernel_cap_t __cap_empty_set = CAP_EMPTY_SET;
25const kernel_cap_t __cap_full_set = CAP_FULL_SET;
26const kernel_cap_t __cap_init_eff_set = CAP_INIT_EFF_SET;
27 25
28EXPORT_SYMBOL(__cap_empty_set); 26EXPORT_SYMBOL(__cap_empty_set);
29EXPORT_SYMBOL(__cap_full_set);
30EXPORT_SYMBOL(__cap_init_eff_set);
31 27
32int file_caps_enabled = 1; 28int file_caps_enabled = 1;
33 29
diff --git a/kernel/cred.c b/kernel/cred.c
index 8093c16b84b1..e12c8af793f8 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -49,10 +49,10 @@ struct cred init_cred = {
49 .magic = CRED_MAGIC, 49 .magic = CRED_MAGIC,
50#endif 50#endif
51 .securebits = SECUREBITS_DEFAULT, 51 .securebits = SECUREBITS_DEFAULT,
52 .cap_inheritable = CAP_INIT_INH_SET, 52 .cap_inheritable = CAP_EMPTY_SET,
53 .cap_permitted = CAP_FULL_SET, 53 .cap_permitted = CAP_FULL_SET,
54 .cap_effective = CAP_INIT_EFF_SET, 54 .cap_effective = CAP_FULL_SET,
55 .cap_bset = CAP_INIT_BSET, 55 .cap_bset = CAP_FULL_SET,
56 .user = INIT_USER, 56 .user = INIT_USER,
57 .user_ns = &init_user_ns, 57 .user_ns = &init_user_ns,
58 .group_info = &init_groups, 58 .group_info = &init_groups,
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 9cd0591c96a2..06fdea2819b6 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);
@@ -153,6 +162,19 @@ static int ____call_usermodehelper(void *data)
153 goto fail; 162 goto fail;
154 } 163 }
155 164
165 retval = -ENOMEM;
166 new = prepare_kernel_cred(current);
167 if (!new)
168 goto fail;
169
170 spin_lock(&umh_sysctl_lock);
171 new->cap_bset = cap_intersect(usermodehelper_bset, new->cap_bset);
172 new->cap_inheritable = cap_intersect(usermodehelper_inheritable,
173 new->cap_inheritable);
174 spin_unlock(&umh_sysctl_lock);
175
176 commit_creds(new);
177
156 retval = kernel_execve(sub_info->path, 178 retval = kernel_execve(sub_info->path,
157 (const char *const *)sub_info->argv, 179 (const char *const *)sub_info->argv,
158 (const char *const *)sub_info->envp); 180 (const char *const *)sub_info->envp);
@@ -418,6 +440,84 @@ unlock:
418} 440}
419EXPORT_SYMBOL(call_usermodehelper_exec); 441EXPORT_SYMBOL(call_usermodehelper_exec);
420 442
443static int proc_cap_handler(struct ctl_table *table, int write,
444 void __user *buffer, size_t *lenp, loff_t *ppos)
445{
446 struct ctl_table t;
447 unsigned long cap_array[_KERNEL_CAPABILITY_U32S];
448 kernel_cap_t new_cap;
449 int err, i;
450
451 if (write && (!capable(CAP_SETPCAP) ||
452 !capable(CAP_SYS_MODULE)))
453 return -EPERM;
454
455 /*
456 * convert from the global kernel_cap_t to the ulong array to print to
457 * userspace if this is a read.
458 */
459 spin_lock(&umh_sysctl_lock);
460 for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++) {
461 if (table->data == CAP_BSET)
462 cap_array[i] = usermodehelper_bset.cap[i];
463 else if (table->data == CAP_PI)
464 cap_array[i] = usermodehelper_inheritable.cap[i];
465 else
466 BUG();
467 }
468 spin_unlock(&umh_sysctl_lock);
469
470 t = *table;
471 t.data = &cap_array;
472
473 /*
474 * actually read or write and array of ulongs from userspace. Remember
475 * these are least significant 32 bits first
476 */
477 err = proc_doulongvec_minmax(&t, write, buffer, lenp, ppos);
478 if (err < 0)
479 return err;
480
481 /*
482 * convert from the sysctl array of ulongs to the kernel_cap_t
483 * internal representation
484 */
485 for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++)
486 new_cap.cap[i] = cap_array[i];
487
488 /*
489 * Drop everything not in the new_cap (but don't add things)
490 */
491 spin_lock(&umh_sysctl_lock);
492 if (write) {
493 if (table->data == CAP_BSET)
494 usermodehelper_bset = cap_intersect(usermodehelper_bset, new_cap);
495 if (table->data == CAP_PI)
496 usermodehelper_inheritable = cap_intersect(usermodehelper_inheritable, new_cap);
497 }
498 spin_unlock(&umh_sysctl_lock);
499
500 return 0;
501}
502
503struct ctl_table usermodehelper_table[] = {
504 {
505 .procname = "bset",
506 .data = CAP_BSET,
507 .maxlen = _KERNEL_CAPABILITY_U32S * sizeof(unsigned long),
508 .mode = 0600,
509 .proc_handler = proc_cap_handler,
510 },
511 {
512 .procname = "inheritable",
513 .data = CAP_PI,
514 .maxlen = _KERNEL_CAPABILITY_U32S * sizeof(unsigned long),
515 .mode = 0600,
516 .proc_handler = proc_cap_handler,
517 },
518 { }
519};
520
421void __init usermodehelper_init(void) 521void __init usermodehelper_init(void)
422{ 522{
423 khelper_wq = create_singlethread_workqueue("khelper"); 523 khelper_wq = create_singlethread_workqueue("khelper");
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index c0bb32414b17..965134bed6cd 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -56,6 +56,7 @@
56#include <linux/kprobes.h> 56#include <linux/kprobes.h>
57#include <linux/pipe_fs_i.h> 57#include <linux/pipe_fs_i.h>
58#include <linux/oom.h> 58#include <linux/oom.h>
59#include <linux/kmod.h>
59 60
60#include <asm/uaccess.h> 61#include <asm/uaccess.h>
61#include <asm/processor.h> 62#include <asm/processor.h>
@@ -616,6 +617,11 @@ static struct ctl_table kern_table[] = {
616 .child = random_table, 617 .child = random_table,
617 }, 618 },
618 { 619 {
620 .procname = "usermodehelper",
621 .mode = 0555,
622 .child = usermodehelper_table,
623 },
624 {
619 .procname = "overflowuid", 625 .procname = "overflowuid",
620 .data = &overflowuid, 626 .data = &overflowuid,
621 .maxlen = sizeof(int), 627 .maxlen = sizeof(int),