aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorAndrew Morgan <morgan@kernel.org>2008-02-05 01:29:42 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-05 12:44:20 -0500
commite338d263a76af78fe8f38a72131188b58fceb591 (patch)
treef3f046fc6fd66de43de7191830f0daf3bc4ec8eb /security
parent8f6936f4d29aa14e54a2470b954a2e1f96322988 (diff)
Add 64-bit capability support to the kernel
The patch supports legacy (32-bit) capability userspace, and where possible translates 32-bit capabilities to/from userspace and the VFS to 64-bit kernel space capabilities. If a capability set cannot be compressed into 32-bits for consumption by user space, the system call fails, with -ERANGE. FWIW libcap-2.00 supports this change (and earlier capability formats) http://www.kernel.org/pub/linux/libs/security/linux-privs/kernel-2.6/ [akpm@linux-foundation.org: coding-syle fixes] [akpm@linux-foundation.org: use get_task_comm()] [ezk@cs.sunysb.edu: build fix] [akpm@linux-foundation.org: do not initialise statics to 0 or NULL] [akpm@linux-foundation.org: unused var] [serue@us.ibm.com: export __cap_ symbols] Signed-off-by: Andrew G. Morgan <morgan@kernel.org> Cc: Stephen Smalley <sds@tycho.nsa.gov> Acked-by: Serge Hallyn <serue@us.ibm.com> Cc: Chris Wright <chrisw@sous-sol.org> Cc: James Morris <jmorris@namei.org> Cc: Casey Schaufler <casey@schaufler-ca.com> Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'security')
-rw-r--r--security/commoncap.c87
-rw-r--r--security/dummy.c17
2 files changed, 68 insertions, 36 deletions
diff --git a/security/commoncap.c b/security/commoncap.c
index b06617b35b93..01ab47845dcf 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -1,4 +1,4 @@
1/* Common capabilities, needed by capability.o and root_plug.o 1/* Common capabilities, needed by capability.o and root_plug.o
2 * 2 *
3 * This program is free software; you can redistribute it and/or modify 3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by 4 * it under the terms of the GNU General Public License as published by
@@ -93,9 +93,9 @@ int cap_capget (struct task_struct *target, kernel_cap_t *effective,
93 kernel_cap_t *inheritable, kernel_cap_t *permitted) 93 kernel_cap_t *inheritable, kernel_cap_t *permitted)
94{ 94{
95 /* Derived from kernel/capability.c:sys_capget. */ 95 /* Derived from kernel/capability.c:sys_capget. */
96 *effective = cap_t (target->cap_effective); 96 *effective = target->cap_effective;
97 *inheritable = cap_t (target->cap_inheritable); 97 *inheritable = target->cap_inheritable;
98 *permitted = cap_t (target->cap_permitted); 98 *permitted = target->cap_permitted;
99 return 0; 99 return 0;
100} 100}
101 101
@@ -197,28 +197,51 @@ int cap_inode_killpriv(struct dentry *dentry)
197 return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS); 197 return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS);
198} 198}
199 199
200static inline int cap_from_disk(__le32 *caps, struct linux_binprm *bprm, 200static inline int cap_from_disk(struct vfs_cap_data *caps,
201 int size) 201 struct linux_binprm *bprm, unsigned size)
202{ 202{
203 __u32 magic_etc; 203 __u32 magic_etc;
204 unsigned tocopy, i;
204 205
205 if (size != XATTR_CAPS_SZ) 206 if (size < sizeof(magic_etc))
206 return -EINVAL; 207 return -EINVAL;
207 208
208 magic_etc = le32_to_cpu(caps[0]); 209 magic_etc = le32_to_cpu(caps->magic_etc);
209 210
210 switch ((magic_etc & VFS_CAP_REVISION_MASK)) { 211 switch ((magic_etc & VFS_CAP_REVISION_MASK)) {
211 case VFS_CAP_REVISION: 212 case VFS_CAP_REVISION_1:
212 if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) 213 if (size != XATTR_CAPS_SZ_1)
213 bprm->cap_effective = true; 214 return -EINVAL;
214 else 215 tocopy = VFS_CAP_U32_1;
215 bprm->cap_effective = false; 216 break;
216 bprm->cap_permitted = to_cap_t(le32_to_cpu(caps[1])); 217 case VFS_CAP_REVISION_2:
217 bprm->cap_inheritable = to_cap_t(le32_to_cpu(caps[2])); 218 if (size != XATTR_CAPS_SZ_2)
218 return 0; 219 return -EINVAL;
220 tocopy = VFS_CAP_U32_2;
221 break;
219 default: 222 default:
220 return -EINVAL; 223 return -EINVAL;
221 } 224 }
225
226 if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) {
227 bprm->cap_effective = true;
228 } else {
229 bprm->cap_effective = false;
230 }
231
232 for (i = 0; i < tocopy; ++i) {
233 bprm->cap_permitted.cap[i] =
234 le32_to_cpu(caps->data[i].permitted);
235 bprm->cap_inheritable.cap[i] =
236 le32_to_cpu(caps->data[i].inheritable);
237 }
238 while (i < VFS_CAP_U32) {
239 bprm->cap_permitted.cap[i] = 0;
240 bprm->cap_inheritable.cap[i] = 0;
241 i++;
242 }
243
244 return 0;
222} 245}
223 246
224/* Locate any VFS capabilities: */ 247/* Locate any VFS capabilities: */
@@ -226,7 +249,7 @@ static int get_file_caps(struct linux_binprm *bprm)
226{ 249{
227 struct dentry *dentry; 250 struct dentry *dentry;
228 int rc = 0; 251 int rc = 0;
229 __le32 v1caps[XATTR_CAPS_SZ]; 252 struct vfs_cap_data vcaps;
230 struct inode *inode; 253 struct inode *inode;
231 254
232 if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID) { 255 if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID) {
@@ -239,8 +262,8 @@ static int get_file_caps(struct linux_binprm *bprm)
239 if (!inode->i_op || !inode->i_op->getxattr) 262 if (!inode->i_op || !inode->i_op->getxattr)
240 goto out; 263 goto out;
241 264
242 rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, &v1caps, 265 rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, &vcaps,
243 XATTR_CAPS_SZ); 266 XATTR_CAPS_SZ);
244 if (rc == -ENODATA || rc == -EOPNOTSUPP) { 267 if (rc == -ENODATA || rc == -EOPNOTSUPP) {
245 /* no data, that's ok */ 268 /* no data, that's ok */
246 rc = 0; 269 rc = 0;
@@ -249,7 +272,7 @@ static int get_file_caps(struct linux_binprm *bprm)
249 if (rc < 0) 272 if (rc < 0)
250 goto out; 273 goto out;
251 274
252 rc = cap_from_disk(v1caps, bprm, rc); 275 rc = cap_from_disk(&vcaps, bprm, rc);
253 if (rc) 276 if (rc)
254 printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n", 277 printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
255 __FUNCTION__, rc, bprm->filename); 278 __FUNCTION__, rc, bprm->filename);
@@ -344,8 +367,10 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
344 * capability rules */ 367 * capability rules */
345 if (!is_global_init(current)) { 368 if (!is_global_init(current)) {
346 current->cap_permitted = new_permitted; 369 current->cap_permitted = new_permitted;
347 current->cap_effective = bprm->cap_effective ? 370 if (bprm->cap_effective)
348 new_permitted : 0; 371 current->cap_effective = new_permitted;
372 else
373 cap_clear(current->cap_effective);
349 } 374 }
350 375
351 /* AUD: Audit candidate if current->cap_effective is set */ 376 /* AUD: Audit candidate if current->cap_effective is set */
@@ -467,13 +492,15 @@ int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid,
467 492
468 if (!issecure (SECURE_NO_SETUID_FIXUP)) { 493 if (!issecure (SECURE_NO_SETUID_FIXUP)) {
469 if (old_fsuid == 0 && current->fsuid != 0) { 494 if (old_fsuid == 0 && current->fsuid != 0) {
470 cap_t (current->cap_effective) &= 495 current->cap_effective =
471 ~CAP_FS_MASK; 496 cap_drop_fs_set(
497 current->cap_effective);
472 } 498 }
473 if (old_fsuid != 0 && current->fsuid == 0) { 499 if (old_fsuid != 0 && current->fsuid == 0) {
474 cap_t (current->cap_effective) |= 500 current->cap_effective =
475 (cap_t (current->cap_permitted) & 501 cap_raise_fs_set(
476 CAP_FS_MASK); 502 current->cap_effective,
503 current->cap_permitted);
477 } 504 }
478 } 505 }
479 break; 506 break;
@@ -577,9 +604,9 @@ int cap_task_kill(struct task_struct *p, struct siginfo *info,
577 604
578void cap_task_reparent_to_init (struct task_struct *p) 605void cap_task_reparent_to_init (struct task_struct *p)
579{ 606{
580 p->cap_effective = CAP_INIT_EFF_SET; 607 cap_set_init_eff(p->cap_effective);
581 p->cap_inheritable = CAP_INIT_INH_SET; 608 cap_clear(p->cap_inheritable);
582 p->cap_permitted = CAP_FULL_SET; 609 cap_set_full(p->cap_permitted);
583 p->keep_capabilities = 0; 610 p->keep_capabilities = 0;
584 return; 611 return;
585} 612}
diff --git a/security/dummy.c b/security/dummy.c
index c505122e22db..649326bf64ea 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -36,14 +36,19 @@ static int dummy_ptrace (struct task_struct *parent, struct task_struct *child)
36static int dummy_capget (struct task_struct *target, kernel_cap_t * effective, 36static 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;
40 if (target->euid == 0) { 39 if (target->euid == 0) {
41 *permitted |= (~0 & ~CAP_FS_MASK); 40 cap_set_full(*permitted);
42 *effective |= (~0 & ~CAP_TO_MASK(CAP_SETPCAP) & ~CAP_FS_MASK); 41 cap_set_init_eff(*effective);
42 } else {
43 cap_clear(*permitted);
44 cap_clear(*effective);
43 } 45 }
44 if (target->fsuid == 0) { 46
45 *permitted |= CAP_FS_MASK; 47 cap_clear(*inheritable);
46 *effective |= CAP_FS_MASK; 48
49 if (target->fsuid != 0) {
50 *permitted = cap_drop_fs_set(*permitted);
51 *effective = cap_drop_fs_set(*effective);
47 } 52 }
48 return 0; 53 return 0;
49} 54}