diff options
Diffstat (limited to 'security/commoncap.c')
-rw-r--r-- | security/commoncap.c | 103 |
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 | |||
30 | unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */ | ||
31 | EXPORT_SYMBOL(securebits); | ||
32 | 29 | ||
33 | int cap_netlink_send(struct sock *sk, struct sk_buff *skb) | 30 | int 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 | ||
374 | int cap_bprm_secureexec (struct linux_binprm *bprm) | 371 | int 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 | */ |
550 | long cap_prctl_drop(unsigned long cap) | 547 | static 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 |
560 | int cap_task_setscheduler (struct task_struct *p, int policy, | 558 | int 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 | ||
573 | int 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 | |||
575 | void cap_task_reparent_to_init (struct task_struct *p) | 660 | void 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 | ||