aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Morgan <morgan@kernel.org>2007-10-18 06:05:59 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-18 17:37:24 -0400
commit72c2d5823fc7be799a12184974c3bdc57acea3c4 (patch)
tree5c17418efb57cd5b2cdc0d751f577b2c64012423
parent7058cb02ddab4bce70a46e519804fccb7ac0a060 (diff)
V3 file capabilities: alter behavior of cap_setpcap
The non-filesystem capability meaning of CAP_SETPCAP is that a process, p1, can change the capabilities of another process, p2. This is not the meaning that was intended for this capability at all, and this implementation came about purely because, without filesystem capabilities, there was no way to use capabilities without one process bestowing them on another. Since we now have a filesystem support for capabilities we can fix the implementation of CAP_SETPCAP. The most significant thing about this change is that, with it in effect, no process can set the capabilities of another process. The capabilities of a program are set via the capability convolution rules: pI(post-exec) = pI(pre-exec) pP(post-exec) = (X(aka cap_bset) & fP) | (pI(post-exec) & fI) pE(post-exec) = fE ? pP(post-exec) : 0 at exec() time. As such, the only influence the pre-exec() program can have on the post-exec() program's capabilities are through the pI capability set. The correct implementation for CAP_SETPCAP (and that enabled by this patch) is that it can be used to add extra pI capabilities to the current process - to be picked up by subsequent exec()s when the above convolution rules are applied. Here is how it works: Let's say we have a process, p. It has capability sets, pE, pP and pI. Generally, p, can change the value of its own pI to pI' where (pI' & ~pI) & ~pP = 0. That is, the only new things in pI' that were not present in pI need to be present in pP. The role of CAP_SETPCAP is basically to permit changes to pI beyond the above: if (pE & CAP_SETPCAP) { pI' = anything; /* ie., even (pI' & ~pI) & ~pP != 0 */ } This capability is useful for things like login, which (say, via pam_cap) might want to raise certain inheritable capabilities for use by the children of the logged-in user's shell, but those capabilities are not useful to or needed by the login program itself. One such use might be to limit who can run ping. You set the capabilities of the 'ping' program to be "= cap_net_raw+i", and then only shells that have (pI & CAP_NET_RAW) will be able to run it. Without CAP_SETPCAP implemented as described above, login(pam_cap) would have to also have (pP & CAP_NET_RAW) in order to raise this capability and pass it on through the inheritable set. Signed-off-by: Andrew Morgan <morgan@kernel.org> Signed-off-by: Serge E. Hallyn <serue@us.ibm.com> Cc: Stephen Smalley <sds@tycho.nsa.gov> Cc: James Morris <jmorris@namei.org> Cc: Casey Schaufler <casey@schaufler-ca.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/capability.h4
-rw-r--r--include/linux/security.h7
-rw-r--r--kernel/capability.c5
-rw-r--r--kernel/sysctl.c8
-rw-r--r--kernel/sysctl_check.c5
-rw-r--r--security/commoncap.c59
-rw-r--r--security/dummy.c16
7 files changed, 80 insertions, 24 deletions
diff --git a/include/linux/capability.h b/include/linux/capability.h
index 8961e7fb755c..7a8d7ade28a0 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -310,10 +310,6 @@ typedef __u32 kernel_cap_t;
310#define CAP_SETFCAP 31 310#define CAP_SETFCAP 31
311 311
312#ifdef __KERNEL__ 312#ifdef __KERNEL__
313/*
314 * Bounding set
315 */
316extern kernel_cap_t cap_bset;
317 313
318/* 314/*
319 * Internal kernel functions only 315 * Internal kernel functions only
diff --git a/include/linux/security.h b/include/linux/security.h
index 9b0b63c50f44..ff3f857f6957 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -34,6 +34,13 @@
34#include <linux/xfrm.h> 34#include <linux/xfrm.h>
35#include <net/flow.h> 35#include <net/flow.h>
36 36
37/*
38 * Bounding set
39 */
40extern kernel_cap_t cap_bset;
41
42extern unsigned securebits;
43
37struct ctl_table; 44struct ctl_table;
38 45
39/* 46/*
diff --git a/kernel/capability.c b/kernel/capability.c
index 4e350a36ed6a..14853be5944d 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * Copyright (C) 1997 Andrew Main <zefram@fysh.org> 4 * Copyright (C) 1997 Andrew Main <zefram@fysh.org>
5 * 5 *
6 * Integrated into 2.1.97+, Andrew G. Morgan <morgan@transmeta.com> 6 * Integrated into 2.1.97+, Andrew G. Morgan <morgan@kernel.org>
7 * 30 May 2002: Cleanup, Robert M. Love <rml@tech9.net> 7 * 30 May 2002: Cleanup, Robert M. Love <rml@tech9.net>
8 */ 8 */
9 9
@@ -14,9 +14,6 @@
14#include <linux/syscalls.h> 14#include <linux/syscalls.h>
15#include <asm/uaccess.h> 15#include <asm/uaccess.h>
16 16
17unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */
18kernel_cap_t cap_bset = CAP_INIT_EFF_SET;
19
20/* 17/*
21 * This lock protects task->cap_* for all tasks including current. 18 * This lock protects task->cap_* for all tasks including current.
22 * Locking rule: acquire this prior to tasklist_lock. 19 * Locking rule: acquire this prior to tasklist_lock.
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index c25e67e19af7..067554bda8b7 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -24,7 +24,7 @@
24#include <linux/slab.h> 24#include <linux/slab.h>
25#include <linux/sysctl.h> 25#include <linux/sysctl.h>
26#include <linux/proc_fs.h> 26#include <linux/proc_fs.h>
27#include <linux/capability.h> 27#include <linux/security.h>
28#include <linux/ctype.h> 28#include <linux/ctype.h>
29#include <linux/utsname.h> 29#include <linux/utsname.h>
30#include <linux/smp_lock.h> 30#include <linux/smp_lock.h>
@@ -371,6 +371,7 @@ static struct ctl_table kern_table[] = {
371 .proc_handler = &proc_dointvec_taint, 371 .proc_handler = &proc_dointvec_taint,
372 }, 372 },
373#endif 373#endif
374#ifdef CONFIG_SECURITY_CAPABILITIES
374 { 375 {
375 .procname = "cap-bound", 376 .procname = "cap-bound",
376 .data = &cap_bset, 377 .data = &cap_bset,
@@ -378,6 +379,7 @@ static struct ctl_table kern_table[] = {
378 .mode = 0600, 379 .mode = 0600,
379 .proc_handler = &proc_dointvec_bset, 380 .proc_handler = &proc_dointvec_bset,
380 }, 381 },
382#endif /* def CONFIG_SECURITY_CAPABILITIES */
381#ifdef CONFIG_BLK_DEV_INITRD 383#ifdef CONFIG_BLK_DEV_INITRD
382 { 384 {
383 .ctl_name = KERN_REALROOTDEV, 385 .ctl_name = KERN_REALROOTDEV,
@@ -1872,10 +1874,11 @@ static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp,
1872 return 0; 1874 return 0;
1873} 1875}
1874 1876
1877#ifdef CONFIG_SECURITY_CAPABILITIES
1875/* 1878/*
1876 * init may raise the set. 1879 * init may raise the set.
1877 */ 1880 */
1878 1881
1879int proc_dointvec_bset(struct ctl_table *table, int write, struct file *filp, 1882int proc_dointvec_bset(struct ctl_table *table, int write, struct file *filp,
1880 void __user *buffer, size_t *lenp, loff_t *ppos) 1883 void __user *buffer, size_t *lenp, loff_t *ppos)
1881{ 1884{
@@ -1889,6 +1892,7 @@ int proc_dointvec_bset(struct ctl_table *table, int write, struct file *filp,
1889 return do_proc_dointvec(table,write,filp,buffer,lenp,ppos, 1892 return do_proc_dointvec(table,write,filp,buffer,lenp,ppos,
1890 do_proc_dointvec_bset_conv,&op); 1893 do_proc_dointvec_bset_conv,&op);
1891} 1894}
1895#endif /* def CONFIG_SECURITY_CAPABILITIES */
1892 1896
1893/* 1897/*
1894 * Taint values can only be increased 1898 * Taint values can only be increased
diff --git a/kernel/sysctl_check.c b/kernel/sysctl_check.c
index f47c33d17032..3c9ef5a7d575 100644
--- a/kernel/sysctl_check.c
+++ b/kernel/sysctl_check.c
@@ -38,7 +38,10 @@ static struct trans_ctl_table trans_kern_table[] = {
38 { KERN_NODENAME, "hostname" }, 38 { KERN_NODENAME, "hostname" },
39 { KERN_DOMAINNAME, "domainname" }, 39 { KERN_DOMAINNAME, "domainname" },
40 40
41#ifdef CONFIG_SECURITY_CAPABILITIES
41 { KERN_CAP_BSET, "cap-bound" }, 42 { KERN_CAP_BSET, "cap-bound" },
43#endif /* def CONFIG_SECURITY_CAPABILITIES */
44
42 { KERN_PANIC, "panic" }, 45 { KERN_PANIC, "panic" },
43 { KERN_REALROOTDEV, "real-root-dev" }, 46 { KERN_REALROOTDEV, "real-root-dev" },
44 47
@@ -1532,7 +1535,9 @@ int sysctl_check_table(struct ctl_table *table)
1532 (table->strategy == sysctl_ms_jiffies) || 1535 (table->strategy == sysctl_ms_jiffies) ||
1533 (table->proc_handler == proc_dostring) || 1536 (table->proc_handler == proc_dostring) ||
1534 (table->proc_handler == proc_dointvec) || 1537 (table->proc_handler == proc_dointvec) ||
1538#ifdef CONFIG_SECURITY_CAPABILITIES
1535 (table->proc_handler == proc_dointvec_bset) || 1539 (table->proc_handler == proc_dointvec_bset) ||
1540#endif /* def CONFIG_SECURITY_CAPABILITIES */
1536 (table->proc_handler == proc_dointvec_minmax) || 1541 (table->proc_handler == proc_dointvec_minmax) ||
1537 (table->proc_handler == proc_dointvec_jiffies) || 1542 (table->proc_handler == proc_dointvec_jiffies) ||
1538 (table->proc_handler == proc_dointvec_userhz_jiffies) || 1543 (table->proc_handler == proc_dointvec_userhz_jiffies) ||
diff --git a/security/commoncap.c b/security/commoncap.c
index 778cb0cfc5d8..48ca5b092768 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -24,6 +24,25 @@
24#include <linux/hugetlb.h> 24#include <linux/hugetlb.h>
25#include <linux/mount.h> 25#include <linux/mount.h>
26 26
27#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
28/*
29 * Because of the reduced scope of CAP_SETPCAP when filesystem
30 * capabilities are in effect, it is safe to allow this capability to
31 * be available in the default configuration.
32 */
33# define CAP_INIT_BSET CAP_FULL_SET
34#else /* ie. ndef CONFIG_SECURITY_FILE_CAPABILITIES */
35# define CAP_INIT_BSET CAP_INIT_EFF_SET
36#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */
37
38kernel_cap_t cap_bset = CAP_INIT_BSET; /* systemwide capability bound */
39EXPORT_SYMBOL(cap_bset);
40
41/* Global security state */
42
43unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */
44EXPORT_SYMBOL(securebits);
45
27int cap_netlink_send(struct sock *sk, struct sk_buff *skb) 46int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
28{ 47{
29 NETLINK_CB(skb).eff_cap = current->cap_effective; 48 NETLINK_CB(skb).eff_cap = current->cap_effective;
@@ -73,14 +92,44 @@ int cap_capget (struct task_struct *target, kernel_cap_t *effective,
73 return 0; 92 return 0;
74} 93}
75 94
95#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
96
97static inline int cap_block_setpcap(struct task_struct *target)
98{
99 /*
100 * No support for remote process capability manipulation with
101 * filesystem capability support.
102 */
103 return (target != current);
104}
105
106static inline int cap_inh_is_capped(void)
107{
108 /*
109 * return 1 if changes to the inheritable set are limited
110 * to the old permitted set.
111 */
112 return !cap_capable(current, CAP_SETPCAP);
113}
114
115#else /* ie., ndef CONFIG_SECURITY_FILE_CAPABILITIES */
116
117static inline int cap_block_setpcap(struct task_struct *t) { return 0; }
118static inline int cap_inh_is_capped(void) { return 1; }
119
120#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */
121
76int cap_capset_check (struct task_struct *target, kernel_cap_t *effective, 122int cap_capset_check (struct task_struct *target, kernel_cap_t *effective,
77 kernel_cap_t *inheritable, kernel_cap_t *permitted) 123 kernel_cap_t *inheritable, kernel_cap_t *permitted)
78{ 124{
79 /* Derived from kernel/capability.c:sys_capset. */ 125 if (cap_block_setpcap(target)) {
80 /* verify restrictions on target's new Inheritable set */ 126 return -EPERM;
81 if (!cap_issubset (*inheritable, 127 }
82 cap_combine (target->cap_inheritable, 128 if (cap_inh_is_capped()
83 current->cap_permitted))) { 129 && !cap_issubset(*inheritable,
130 cap_combine(target->cap_inheritable,
131 current->cap_permitted))) {
132 /* incapable of using this inheritable set */
84 return -EPERM; 133 return -EPERM;
85 } 134 }
86 135
diff --git a/security/dummy.c b/security/dummy.c
index bc43d4c7383e..6d895ade73de 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,
37 kernel_cap_t * inheritable, kernel_cap_t * permitted) 37 kernel_cap_t * inheritable, kernel_cap_t * permitted)
38{ 38{
39 *effective = *inheritable = *permitted = 0; 39 *effective = *inheritable = *permitted = 0;
40 if (!issecure(SECURE_NOROOT)) { 40 if (target->euid == 0) {
41 if (target->euid == 0) { 41 *permitted |= (~0 & ~CAP_FS_MASK);
42 *permitted |= (~0 & ~CAP_FS_MASK); 42 *effective |= (~0 & ~CAP_TO_MASK(CAP_SETPCAP) & ~CAP_FS_MASK);
43 *effective |= (~0 & ~CAP_TO_MASK(CAP_SETPCAP) & ~CAP_FS_MASK); 43 }
44 } 44 if (target->fsuid == 0) {
45 if (target->fsuid == 0) { 45 *permitted |= CAP_FS_MASK;
46 *permitted |= CAP_FS_MASK; 46 *effective |= CAP_FS_MASK;
47 *effective |= CAP_FS_MASK;
48 }
49 } 47 }
50 return 0; 48 return 0;
51} 49}