diff options
-rw-r--r-- | include/linux/capability.h | 4 | ||||
-rw-r--r-- | include/linux/security.h | 7 | ||||
-rw-r--r-- | kernel/capability.c | 5 | ||||
-rw-r--r-- | kernel/sysctl.c | 8 | ||||
-rw-r--r-- | kernel/sysctl_check.c | 5 | ||||
-rw-r--r-- | security/commoncap.c | 59 | ||||
-rw-r--r-- | security/dummy.c | 16 |
7 files changed, 80 insertions, 24 deletions
diff --git a/include/linux/capability.h b/include/linux/capability.h index 8961e7fb755..7a8d7ade28a 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -310,10 +310,6 @@ typedef __u32 kernel_cap_t; #define CAP_SETFCAP 31 #ifdef __KERNEL__ -/* - * Bounding set - */ -extern kernel_cap_t cap_bset; /* * Internal kernel functions only diff --git a/include/linux/security.h b/include/linux/security.h index 9b0b63c50f4..ff3f857f695 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -34,6 +34,13 @@ #include <linux/xfrm.h> #include <net/flow.h> +/* + * Bounding set + */ +extern kernel_cap_t cap_bset; + +extern unsigned securebits; + struct ctl_table; /* diff --git a/kernel/capability.c b/kernel/capability.c index 4e350a36ed6..14853be5944 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -3,7 +3,7 @@ * * Copyright (C) 1997 Andrew Main <zefram@fysh.org> * - * Integrated into 2.1.97+, Andrew G. Morgan <morgan@transmeta.com> + * Integrated into 2.1.97+, Andrew G. Morgan <morgan@kernel.org> * 30 May 2002: Cleanup, Robert M. Love <rml@tech9.net> */ @@ -14,9 +14,6 @@ #include <linux/syscalls.h> #include <asm/uaccess.h> -unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */ -kernel_cap_t cap_bset = CAP_INIT_EFF_SET; - /* * This lock protects task->cap_* for all tasks including current. * Locking rule: acquire this prior to tasklist_lock. diff --git a/kernel/sysctl.c b/kernel/sysctl.c index c25e67e19af..067554bda8b 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -24,7 +24,7 @@ #include <linux/slab.h> #include <linux/sysctl.h> #include <linux/proc_fs.h> -#include <linux/capability.h> +#include <linux/security.h> #include <linux/ctype.h> #include <linux/utsname.h> #include <linux/smp_lock.h> @@ -371,6 +371,7 @@ static struct ctl_table kern_table[] = { .proc_handler = &proc_dointvec_taint, }, #endif +#ifdef CONFIG_SECURITY_CAPABILITIES { .procname = "cap-bound", .data = &cap_bset, @@ -378,6 +379,7 @@ static struct ctl_table kern_table[] = { .mode = 0600, .proc_handler = &proc_dointvec_bset, }, +#endif /* def CONFIG_SECURITY_CAPABILITIES */ #ifdef CONFIG_BLK_DEV_INITRD { .ctl_name = KERN_REALROOTDEV, @@ -1872,10 +1874,11 @@ static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp, return 0; } +#ifdef CONFIG_SECURITY_CAPABILITIES /* * init may raise the set. */ - + int proc_dointvec_bset(struct ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -1889,6 +1892,7 @@ int proc_dointvec_bset(struct ctl_table *table, int write, struct file *filp, return do_proc_dointvec(table,write,filp,buffer,lenp,ppos, do_proc_dointvec_bset_conv,&op); } +#endif /* def CONFIG_SECURITY_CAPABILITIES */ /* * Taint values can only be increased diff --git a/kernel/sysctl_check.c b/kernel/sysctl_check.c index f47c33d1703..3c9ef5a7d57 100644 --- a/kernel/sysctl_check.c +++ b/kernel/sysctl_check.c @@ -38,7 +38,10 @@ static struct trans_ctl_table trans_kern_table[] = { { KERN_NODENAME, "hostname" }, { KERN_DOMAINNAME, "domainname" }, +#ifdef CONFIG_SECURITY_CAPABILITIES { KERN_CAP_BSET, "cap-bound" }, +#endif /* def CONFIG_SECURITY_CAPABILITIES */ + { KERN_PANIC, "panic" }, { KERN_REALROOTDEV, "real-root-dev" }, @@ -1532,7 +1535,9 @@ int sysctl_check_table(struct ctl_table *table) (table->strategy == sysctl_ms_jiffies) || (table->proc_handler == proc_dostring) || (table->proc_handler == proc_dointvec) || +#ifdef CONFIG_SECURITY_CAPABILITIES (table->proc_handler == proc_dointvec_bset) || +#endif /* def CONFIG_SECURITY_CAPABILITIES */ (table->proc_handler == proc_dointvec_minmax) || (table->proc_handler == proc_dointvec_jiffies) || (table->proc_handler == proc_dointvec_userhz_jiffies) || diff --git a/security/commoncap.c b/security/commoncap.c index 778cb0cfc5d..48ca5b09276 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -24,6 +24,25 @@ #include <linux/hugetlb.h> #include <linux/mount.h> +#ifdef CONFIG_SECURITY_FILE_CAPABILITIES +/* + * Because of the reduced scope of CAP_SETPCAP when filesystem + * capabilities are in effect, it is safe to allow this capability to + * be available in the default configuration. + */ +# define CAP_INIT_BSET CAP_FULL_SET +#else /* ie. ndef CONFIG_SECURITY_FILE_CAPABILITIES */ +# define CAP_INIT_BSET CAP_INIT_EFF_SET +#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */ + +kernel_cap_t cap_bset = CAP_INIT_BSET; /* systemwide capability bound */ +EXPORT_SYMBOL(cap_bset); + +/* Global security state */ + +unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */ +EXPORT_SYMBOL(securebits); + int cap_netlink_send(struct sock *sk, struct sk_buff *skb) { NETLINK_CB(skb).eff_cap = current->cap_effective; @@ -73,14 +92,44 @@ int cap_capget (struct task_struct *target, kernel_cap_t *effective, return 0; } +#ifdef CONFIG_SECURITY_FILE_CAPABILITIES + +static inline int cap_block_setpcap(struct task_struct *target) +{ + /* + * No support for remote process capability manipulation with + * filesystem capability support. + */ + return (target != current); +} + +static inline int cap_inh_is_capped(void) +{ + /* + * return 1 if changes to the inheritable set are limited + * to the old permitted set. + */ + return !cap_capable(current, CAP_SETPCAP); +} + +#else /* ie., ndef CONFIG_SECURITY_FILE_CAPABILITIES */ + +static inline int cap_block_setpcap(struct task_struct *t) { return 0; } +static inline int cap_inh_is_capped(void) { return 1; } + +#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */ + int cap_capset_check (struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted) { - /* Derived from kernel/capability.c:sys_capset. */ - /* verify restrictions on target's new Inheritable set */ - if (!cap_issubset (*inheritable, - cap_combine (target->cap_inheritable, - current->cap_permitted))) { + if (cap_block_setpcap(target)) { + return -EPERM; + } + if (cap_inh_is_capped() + && !cap_issubset(*inheritable, + cap_combine(target->cap_inheritable, + current->cap_permitted))) { + /* incapable of using this inheritable set */ return -EPERM; } diff --git a/security/dummy.c b/security/dummy.c index bc43d4c7383..6d895ade73d 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -37,15 +37,13 @@ static int dummy_capget (struct task_struct *target, kernel_cap_t * effective, kernel_cap_t * inheritable, kernel_cap_t * permitted) { *effective = *inheritable = *permitted = 0; - if (!issecure(SECURE_NOROOT)) { - if (target->euid == 0) { - *permitted |= (~0 & ~CAP_FS_MASK); - *effective |= (~0 & ~CAP_TO_MASK(CAP_SETPCAP) & ~CAP_FS_MASK); - } - if (target->fsuid == 0) { - *permitted |= CAP_FS_MASK; - *effective |= CAP_FS_MASK; - } + if (target->euid == 0) { + *permitted |= (~0 & ~CAP_FS_MASK); + *effective |= (~0 & ~CAP_TO_MASK(CAP_SETPCAP) & ~CAP_FS_MASK); + } + if (target->fsuid == 0) { + *permitted |= CAP_FS_MASK; + *effective |= CAP_FS_MASK; } return 0; } |