aboutsummaryrefslogtreecommitdiffstats
path: root/security/commoncap.c
diff options
context:
space:
mode:
authorAndrew G. Morgan <morgan@kernel.org>2008-04-28 05:13:40 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-28 11:58:26 -0400
commit3898b1b4ebff8dcfbcf1807e0661585e06c9a91c (patch)
tree69a338864dfe654f68064a599c5d0da460df34ac /security/commoncap.c
parent4016a1390d07f15b267eecb20e76a48fd5c524ef (diff)
capabilities: implement per-process securebits
Filesystem capability support makes it possible to do away with (set)uid-0 based privilege and use capabilities instead. That is, with filesystem support for capabilities but without this present patch, it is (conceptually) possible to manage a system with capabilities alone and never need to obtain privilege via (set)uid-0. Of course, conceptually isn't quite the same as currently possible since few user applications, certainly not enough to run a viable system, are currently prepared to leverage capabilities to exercise privilege. Further, many applications exist that may never get upgraded in this way, and the kernel will continue to want to support their setuid-0 base privilege needs. Where pure-capability applications evolve and replace setuid-0 binaries, it is desirable that there be a mechanisms by which they can contain their privilege. In addition to leveraging the per-process bounding and inheritable sets, this should include suppressing the privilege of the uid-0 superuser from the process' tree of children. The feature added by this patch can be leveraged to suppress the privilege associated with (set)uid-0. This suppression requires CAP_SETPCAP to initiate, and only immediately affects the 'current' process (it is inherited through fork()/exec()). This reimplementation differs significantly from the historical support for securebits which was system-wide, unwieldy and which has ultimately withered to a dead relic in the source of the modern kernel. With this patch applied a process, that is capable(CAP_SETPCAP), can now drop all legacy privilege (through uid=0) for itself and all subsequently fork()'d/exec()'d children with: prctl(PR_SET_SECUREBITS, 0x2f); This patch represents a no-op unless CONFIG_SECURITY_FILE_CAPABILITIES is enabled at configure time. [akpm@linux-foundation.org: fix uninitialised var warning] [serue@us.ibm.com: capabilities: use cap_task_prctl when !CONFIG_SECURITY] Signed-off-by: Andrew G. Morgan <morgan@kernel.org> Acked-by: Serge Hallyn <serue@us.ibm.com> Reviewed-by: James Morris <jmorris@namei.org> Cc: Stephen Smalley <sds@tycho.nsa.gov> Cc: Paul Moore <paul.moore@hp.com> Signed-off-by: Serge E. Hallyn <serue@us.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'security/commoncap.c')
-rw-r--r--security/commoncap.c103
1 files changed, 94 insertions, 9 deletions
diff --git a/security/commoncap.c b/security/commoncap.c
index 852905789caf..e8c3f5e46705 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -24,11 +24,8 @@
24#include <linux/hugetlb.h> 24#include <linux/hugetlb.h>
25#include <linux/mount.h> 25#include <linux/mount.h>
26#include <linux/sched.h> 26#include <linux/sched.h>
27 27#include <linux/prctl.h>
28/* Global security state */ 28#include <linux/securebits.h>
29
30unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */
31EXPORT_SYMBOL(securebits);
32 29
33int cap_netlink_send(struct sock *sk, struct sk_buff *skb) 30int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
34{ 31{
@@ -368,7 +365,7 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
368 365
369 /* AUD: Audit candidate if current->cap_effective is set */ 366 /* AUD: Audit candidate if current->cap_effective is set */
370 367
371 current->keep_capabilities = 0; 368 current->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
372} 369}
373 370
374int cap_bprm_secureexec (struct linux_binprm *bprm) 371int cap_bprm_secureexec (struct linux_binprm *bprm)
@@ -448,7 +445,7 @@ static inline void cap_emulate_setxuid (int old_ruid, int old_euid,
448{ 445{
449 if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) && 446 if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
450 (current->uid != 0 && current->euid != 0 && current->suid != 0) && 447 (current->uid != 0 && current->euid != 0 && current->suid != 0) &&
451 !current->keep_capabilities) { 448 !issecure(SECURE_KEEP_CAPS)) {
452 cap_clear (current->cap_permitted); 449 cap_clear (current->cap_permitted);
453 cap_clear (current->cap_effective); 450 cap_clear (current->cap_effective);
454 } 451 }
@@ -547,7 +544,7 @@ int cap_task_setnice (struct task_struct *p, int nice)
547 * this task could get inconsistent info. There can be no 544 * this task could get inconsistent info. There can be no
548 * racing writer bc a task can only change its own caps. 545 * racing writer bc a task can only change its own caps.
549 */ 546 */
550long cap_prctl_drop(unsigned long cap) 547static long cap_prctl_drop(unsigned long cap)
551{ 548{
552 if (!capable(CAP_SETPCAP)) 549 if (!capable(CAP_SETPCAP))
553 return -EPERM; 550 return -EPERM;
@@ -556,6 +553,7 @@ long cap_prctl_drop(unsigned long cap)
556 cap_lower(current->cap_bset, cap); 553 cap_lower(current->cap_bset, cap);
557 return 0; 554 return 0;
558} 555}
556
559#else 557#else
560int cap_task_setscheduler (struct task_struct *p, int policy, 558int cap_task_setscheduler (struct task_struct *p, int policy,
561 struct sched_param *lp) 559 struct sched_param *lp)
@@ -572,12 +570,99 @@ int cap_task_setnice (struct task_struct *p, int nice)
572} 570}
573#endif 571#endif
574 572
573int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
574 unsigned long arg4, unsigned long arg5, long *rc_p)
575{
576 long error = 0;
577
578 switch (option) {
579 case PR_CAPBSET_READ:
580 if (!cap_valid(arg2))
581 error = -EINVAL;
582 else
583 error = !!cap_raised(current->cap_bset, arg2);
584 break;
585#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
586 case PR_CAPBSET_DROP:
587 error = cap_prctl_drop(arg2);
588 break;
589
590 /*
591 * The next four prctl's remain to assist with transitioning a
592 * system from legacy UID=0 based privilege (when filesystem
593 * capabilities are not in use) to a system using filesystem
594 * capabilities only - as the POSIX.1e draft intended.
595 *
596 * Note:
597 *
598 * PR_SET_SECUREBITS =
599 * issecure_mask(SECURE_KEEP_CAPS_LOCKED)
600 * | issecure_mask(SECURE_NOROOT)
601 * | issecure_mask(SECURE_NOROOT_LOCKED)
602 * | issecure_mask(SECURE_NO_SETUID_FIXUP)
603 * | issecure_mask(SECURE_NO_SETUID_FIXUP_LOCKED)
604 *
605 * will ensure that the current process and all of its
606 * children will be locked into a pure
607 * capability-based-privilege environment.
608 */
609 case PR_SET_SECUREBITS:
610 if ((((current->securebits & SECURE_ALL_LOCKS) >> 1)
611 & (current->securebits ^ arg2)) /*[1]*/
612 || ((current->securebits & SECURE_ALL_LOCKS
613 & ~arg2)) /*[2]*/
614 || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
615 || (cap_capable(current, CAP_SETPCAP) != 0)) { /*[4]*/
616 /*
617 * [1] no changing of bits that are locked
618 * [2] no unlocking of locks
619 * [3] no setting of unsupported bits
620 * [4] doing anything requires privilege (go read about
621 * the "sendmail capabilities bug")
622 */
623 error = -EPERM; /* cannot change a locked bit */
624 } else {
625 current->securebits = arg2;
626 }
627 break;
628 case PR_GET_SECUREBITS:
629 error = current->securebits;
630 break;
631
632#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */
633
634 case PR_GET_KEEPCAPS:
635 if (issecure(SECURE_KEEP_CAPS))
636 error = 1;
637 break;
638 case PR_SET_KEEPCAPS:
639 if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */
640 error = -EINVAL;
641 else if (issecure(SECURE_KEEP_CAPS_LOCKED))
642 error = -EPERM;
643 else if (arg2)
644 current->securebits |= issecure_mask(SECURE_KEEP_CAPS);
645 else
646 current->securebits &=
647 ~issecure_mask(SECURE_KEEP_CAPS);
648 break;
649
650 default:
651 /* No functionality available - continue with default */
652 return 0;
653 }
654
655 /* Functionality provided */
656 *rc_p = error;
657 return 1;
658}
659
575void cap_task_reparent_to_init (struct task_struct *p) 660void cap_task_reparent_to_init (struct task_struct *p)
576{ 661{
577 cap_set_init_eff(p->cap_effective); 662 cap_set_init_eff(p->cap_effective);
578 cap_clear(p->cap_inheritable); 663 cap_clear(p->cap_inheritable);
579 cap_set_full(p->cap_permitted); 664 cap_set_full(p->cap_permitted);
580 p->keep_capabilities = 0; 665 p->securebits = SECUREBITS_DEFAULT;
581 return; 666 return;
582} 667}
583 668