aboutsummaryrefslogtreecommitdiffstats
path: root/security/commoncap.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/commoncap.c')
-rw-r--r--security/commoncap.c134
1 files changed, 82 insertions, 52 deletions
diff --git a/security/commoncap.c b/security/commoncap.c
index ea61bc73f6d3..5aba82679a0b 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
@@ -25,20 +25,6 @@
25#include <linux/mount.h> 25#include <linux/mount.h>
26#include <linux/sched.h> 26#include <linux/sched.h>
27 27
28#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
29/*
30 * Because of the reduced scope of CAP_SETPCAP when filesystem
31 * capabilities are in effect, it is safe to allow this capability to
32 * be available in the default configuration.
33 */
34# define CAP_INIT_BSET CAP_FULL_SET
35#else /* ie. ndef CONFIG_SECURITY_FILE_CAPABILITIES */
36# define CAP_INIT_BSET CAP_INIT_EFF_SET
37#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */
38
39kernel_cap_t cap_bset = CAP_INIT_BSET; /* systemwide capability bound */
40EXPORT_SYMBOL(cap_bset);
41
42/* Global security state */ 28/* Global security state */
43 29
44unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */ 30unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */
@@ -93,9 +79,9 @@ int cap_capget (struct task_struct *target, kernel_cap_t *effective,
93 kernel_cap_t *inheritable, kernel_cap_t *permitted) 79 kernel_cap_t *inheritable, kernel_cap_t *permitted)
94{ 80{
95 /* Derived from kernel/capability.c:sys_capget. */ 81 /* Derived from kernel/capability.c:sys_capget. */
96 *effective = cap_t (target->cap_effective); 82 *effective = target->cap_effective;
97 *inheritable = cap_t (target->cap_inheritable); 83 *inheritable = target->cap_inheritable;
98 *permitted = cap_t (target->cap_permitted); 84 *permitted = target->cap_permitted;
99 return 0; 85 return 0;
100} 86}
101 87
@@ -140,6 +126,12 @@ int cap_capset_check (struct task_struct *target, kernel_cap_t *effective,
140 /* incapable of using this inheritable set */ 126 /* incapable of using this inheritable set */
141 return -EPERM; 127 return -EPERM;
142 } 128 }
129 if (!cap_issubset(*inheritable,
130 cap_combine(target->cap_inheritable,
131 current->cap_bset))) {
132 /* no new pI capabilities outside bounding set */
133 return -EPERM;
134 }
143 135
144 /* verify restrictions on target's new Permitted set */ 136 /* verify restrictions on target's new Permitted set */
145 if (!cap_issubset (*permitted, 137 if (!cap_issubset (*permitted,
@@ -198,28 +190,50 @@ int cap_inode_killpriv(struct dentry *dentry)
198} 190}
199 191
200static inline int cap_from_disk(struct vfs_cap_data *caps, 192static inline int cap_from_disk(struct vfs_cap_data *caps,
201 struct linux_binprm *bprm, 193 struct linux_binprm *bprm, unsigned size)
202 int size)
203{ 194{
204 __u32 magic_etc; 195 __u32 magic_etc;
196 unsigned tocopy, i;
205 197
206 if (size != XATTR_CAPS_SZ) 198 if (size < sizeof(magic_etc))
207 return -EINVAL; 199 return -EINVAL;
208 200
209 magic_etc = le32_to_cpu(caps->magic_etc); 201 magic_etc = le32_to_cpu(caps->magic_etc);
210 202
211 switch ((magic_etc & VFS_CAP_REVISION_MASK)) { 203 switch ((magic_etc & VFS_CAP_REVISION_MASK)) {
212 case VFS_CAP_REVISION: 204 case VFS_CAP_REVISION_1:
213 if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) 205 if (size != XATTR_CAPS_SZ_1)
214 bprm->cap_effective = true; 206 return -EINVAL;
215 else 207 tocopy = VFS_CAP_U32_1;
216 bprm->cap_effective = false; 208 break;
217 bprm->cap_permitted = to_cap_t(le32_to_cpu(caps->permitted)); 209 case VFS_CAP_REVISION_2:
218 bprm->cap_inheritable = to_cap_t(le32_to_cpu(caps->inheritable)); 210 if (size != XATTR_CAPS_SZ_2)
219 return 0; 211 return -EINVAL;
212 tocopy = VFS_CAP_U32_2;
213 break;
220 default: 214 default:
221 return -EINVAL; 215 return -EINVAL;
222 } 216 }
217
218 if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) {
219 bprm->cap_effective = true;
220 } else {
221 bprm->cap_effective = false;
222 }
223
224 for (i = 0; i < tocopy; ++i) {
225 bprm->cap_permitted.cap[i] =
226 le32_to_cpu(caps->data[i].permitted);
227 bprm->cap_inheritable.cap[i] =
228 le32_to_cpu(caps->data[i].inheritable);
229 }
230 while (i < VFS_CAP_U32) {
231 bprm->cap_permitted.cap[i] = 0;
232 bprm->cap_inheritable.cap[i] = 0;
233 i++;
234 }
235
236 return 0;
223} 237}
224 238
225/* Locate any VFS capabilities: */ 239/* Locate any VFS capabilities: */
@@ -227,7 +241,7 @@ static int get_file_caps(struct linux_binprm *bprm)
227{ 241{
228 struct dentry *dentry; 242 struct dentry *dentry;
229 int rc = 0; 243 int rc = 0;
230 struct vfs_cap_data incaps; 244 struct vfs_cap_data vcaps;
231 struct inode *inode; 245 struct inode *inode;
232 246
233 if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID) { 247 if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID) {
@@ -240,14 +254,8 @@ static int get_file_caps(struct linux_binprm *bprm)
240 if (!inode->i_op || !inode->i_op->getxattr) 254 if (!inode->i_op || !inode->i_op->getxattr)
241 goto out; 255 goto out;
242 256
243 rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, NULL, 0); 257 rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, &vcaps,
244 if (rc > 0) { 258 XATTR_CAPS_SZ);
245 if (rc == XATTR_CAPS_SZ)
246 rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS,
247 &incaps, XATTR_CAPS_SZ);
248 else
249 rc = -EINVAL;
250 }
251 if (rc == -ENODATA || rc == -EOPNOTSUPP) { 259 if (rc == -ENODATA || rc == -EOPNOTSUPP) {
252 /* no data, that's ok */ 260 /* no data, that's ok */
253 rc = 0; 261 rc = 0;
@@ -256,7 +264,7 @@ static int get_file_caps(struct linux_binprm *bprm)
256 if (rc < 0) 264 if (rc < 0)
257 goto out; 265 goto out;
258 266
259 rc = cap_from_disk(&incaps, bprm, rc); 267 rc = cap_from_disk(&vcaps, bprm, rc);
260 if (rc) 268 if (rc)
261 printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n", 269 printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
262 __FUNCTION__, rc, bprm->filename); 270 __FUNCTION__, rc, bprm->filename);
@@ -321,10 +329,11 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
321 /* Derived from fs/exec.c:compute_creds. */ 329 /* Derived from fs/exec.c:compute_creds. */
322 kernel_cap_t new_permitted, working; 330 kernel_cap_t new_permitted, working;
323 331
324 new_permitted = cap_intersect (bprm->cap_permitted, cap_bset); 332 new_permitted = cap_intersect(bprm->cap_permitted,
325 working = cap_intersect (bprm->cap_inheritable, 333 current->cap_bset);
334 working = cap_intersect(bprm->cap_inheritable,
326 current->cap_inheritable); 335 current->cap_inheritable);
327 new_permitted = cap_combine (new_permitted, working); 336 new_permitted = cap_combine(new_permitted, working);
328 337
329 if (bprm->e_uid != current->uid || bprm->e_gid != current->gid || 338 if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
330 !cap_issubset (new_permitted, current->cap_permitted)) { 339 !cap_issubset (new_permitted, current->cap_permitted)) {
@@ -351,8 +360,10 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
351 * capability rules */ 360 * capability rules */
352 if (!is_global_init(current)) { 361 if (!is_global_init(current)) {
353 current->cap_permitted = new_permitted; 362 current->cap_permitted = new_permitted;
354 current->cap_effective = bprm->cap_effective ? 363 if (bprm->cap_effective)
355 new_permitted : 0; 364 current->cap_effective = new_permitted;
365 else
366 cap_clear(current->cap_effective);
356 } 367 }
357 368
358 /* AUD: Audit candidate if current->cap_effective is set */ 369 /* AUD: Audit candidate if current->cap_effective is set */
@@ -474,13 +485,15 @@ int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid,
474 485
475 if (!issecure (SECURE_NO_SETUID_FIXUP)) { 486 if (!issecure (SECURE_NO_SETUID_FIXUP)) {
476 if (old_fsuid == 0 && current->fsuid != 0) { 487 if (old_fsuid == 0 && current->fsuid != 0) {
477 cap_t (current->cap_effective) &= 488 current->cap_effective =
478 ~CAP_FS_MASK; 489 cap_drop_fs_set(
490 current->cap_effective);
479 } 491 }
480 if (old_fsuid != 0 && current->fsuid == 0) { 492 if (old_fsuid != 0 && current->fsuid == 0) {
481 cap_t (current->cap_effective) |= 493 current->cap_effective =
482 (cap_t (current->cap_permitted) & 494 cap_raise_fs_set(
483 CAP_FS_MASK); 495 current->cap_effective,
496 current->cap_permitted);
484 } 497 }
485 } 498 }
486 break; 499 break;
@@ -561,6 +574,23 @@ int cap_task_kill(struct task_struct *p, struct siginfo *info,
561 574
562 return -EPERM; 575 return -EPERM;
563} 576}
577
578/*
579 * called from kernel/sys.c for prctl(PR_CABSET_DROP)
580 * done without task_capability_lock() because it introduces
581 * no new races - i.e. only another task doing capget() on
582 * this task could get inconsistent info. There can be no
583 * racing writer bc a task can only change its own caps.
584 */
585long cap_prctl_drop(unsigned long cap)
586{
587 if (!capable(CAP_SETPCAP))
588 return -EPERM;
589 if (!cap_valid(cap))
590 return -EINVAL;
591 cap_lower(current->cap_bset, cap);
592 return 0;
593}
564#else 594#else
565int cap_task_setscheduler (struct task_struct *p, int policy, 595int cap_task_setscheduler (struct task_struct *p, int policy,
566 struct sched_param *lp) 596 struct sched_param *lp)
@@ -584,9 +614,9 @@ int cap_task_kill(struct task_struct *p, struct siginfo *info,
584 614
585void cap_task_reparent_to_init (struct task_struct *p) 615void cap_task_reparent_to_init (struct task_struct *p)
586{ 616{
587 p->cap_effective = CAP_INIT_EFF_SET; 617 cap_set_init_eff(p->cap_effective);
588 p->cap_inheritable = CAP_INIT_INH_SET; 618 cap_clear(p->cap_inheritable);
589 p->cap_permitted = CAP_FULL_SET; 619 cap_set_full(p->cap_permitted);
590 p->keep_capabilities = 0; 620 p->keep_capabilities = 0;
591 return; 621 return;
592} 622}