diff --git a/include/linux/capability.h b/include/linux/capability.h index 8961e7fb755c34bc4f1ea346fbb83854286bc932..7a8d7ade28a035b106cf025c4faa74c18ee8b229 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 9b0b63c50f445717c8645962c7a06c77042115d6..ff3f857f69571c3c6e6372322cb55f58ad5fd619 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -34,6 +34,13 @@ #include #include +/* + * 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 4e350a36ed6a177a5422cf097c8120269490d785..14853be5944d8ffd6da305fde581ea2a29d62d87 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -3,7 +3,7 @@ * * Copyright (C) 1997 Andrew Main * - * Integrated into 2.1.97+, Andrew G. Morgan + * Integrated into 2.1.97+, Andrew G. Morgan * 30 May 2002: Cleanup, Robert M. Love */ @@ -14,9 +14,6 @@ #include #include -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 c25e67e19af7b402ee57201f6f41491933feca78..067554bda8b79ba3954f2dc653dfa4f25f98f09c 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include @@ -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 f47c33d17032b75852dc2d24ed2b5d646eb8651a..3c9ef5a7d5754e26608a905042401f3f2940becd 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 778cb0cfc5d892fa9ae3f001d35d2560779dd15c..48ca5b092768fdde28e1df98b6420e47af0e82b1 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -24,6 +24,25 @@ #include #include +#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 bc43d4c7383e89e5675e3ab1b031aa33fe7d7fc2..6d895ade73de485d9ceab48a28094068550e79b0 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; }