aboutsummaryrefslogtreecommitdiffstats
path: root/security/commoncap.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-11-13 13:30:44 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-11-13 13:30:44 -0500
commit55b3a0cb5aeef0961ee18eac058e488f149a0053 (patch)
treeb8ac5161349f5e5dea8b2a29842fe43ee78f23a2 /security/commoncap.c
parentdee02770cdcd8bc06a48c917ce5df2fb56cf6059 (diff)
parent34d8751fd4ffa34e85ee7e85d34168b3f3f62b42 (diff)
Merge branch 'next-general' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull general security subsystem updates from James Morris: "TPM (from Jarkko): - essential clean up for tpm_crb so that ARM64 and x86 versions do not distract each other as much as before - /dev/tpm0 rejects now too short writes (shorter buffer than specified in the command header - use DMA-safe buffer in tpm_tis_spi - otherwise mostly minor fixes. Smack: - base support for overlafs Capabilities: - BPRM_FCAPS fixes, from Richard Guy Briggs: The audit subsystem is adding a BPRM_FCAPS record when auditing setuid application execution (SYSCALL execve). This is not expected as it was supposed to be limited to when the file system actually had capabilities in an extended attribute. It lists all capabilities making the event really ugly to parse what is happening. The PATH record correctly records the setuid bit and owner. Suppress the BPRM_FCAPS record on set*id. TOMOYO: - Y2038 timestamping fixes" * 'next-general' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (28 commits) MAINTAINERS: update the IMA, EVM, trusted-keys, encrypted-keys entries Smack: Base support for overlayfs MAINTAINERS: remove David Safford as maintainer for encrypted+trusted keys tomoyo: fix timestamping for y2038 capabilities: audit log other surprising conditions capabilities: fix logic for effective root or real root capabilities: invert logic for clarity capabilities: remove a layer of conditional logic capabilities: move audit log decision to function capabilities: use intuitive names for id changes capabilities: use root_priveleged inline to clarify logic capabilities: rename has_cap to has_fcap capabilities: intuitive names for cap gain status capabilities: factor out cap_bprm_set_creds privileged root tpm, tpm_tis: use ARRAY_SIZE() to define TPM_HID_USR_IDX tpm: fix duplicate inline declaration specifier tpm: fix type of a local variables in tpm_tis_spi.c tpm: fix type of a local variable in tpm2_map_command() tpm: fix type of a local variable in tpm2_get_cc_attrs_tbl() tpm-dev-common: Reject too short writes ...
Diffstat (limited to 'security/commoncap.c')
-rw-r--r--security/commoncap.c193
1 files changed, 128 insertions, 65 deletions
diff --git a/security/commoncap.c b/security/commoncap.c
index fc46f5b85251..4f8e09340956 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -536,7 +536,7 @@ int cap_convert_nscap(struct dentry *dentry, void **ivalue, size_t size)
536static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps, 536static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
537 struct linux_binprm *bprm, 537 struct linux_binprm *bprm,
538 bool *effective, 538 bool *effective,
539 bool *has_cap) 539 bool *has_fcap)
540{ 540{
541 struct cred *new = bprm->cred; 541 struct cred *new = bprm->cred;
542 unsigned i; 542 unsigned i;
@@ -546,7 +546,7 @@ static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
546 *effective = true; 546 *effective = true;
547 547
548 if (caps->magic_etc & VFS_CAP_REVISION_MASK) 548 if (caps->magic_etc & VFS_CAP_REVISION_MASK)
549 *has_cap = true; 549 *has_fcap = true;
550 550
551 CAP_FOR_EACH_U32(i) { 551 CAP_FOR_EACH_U32(i) {
552 __u32 permitted = caps->permitted.cap[i]; 552 __u32 permitted = caps->permitted.cap[i];
@@ -653,7 +653,7 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data
653 * its xattrs and, if present, apply them to the proposed credentials being 653 * its xattrs and, if present, apply them to the proposed credentials being
654 * constructed by execve(). 654 * constructed by execve().
655 */ 655 */
656static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_cap) 656static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_fcap)
657{ 657{
658 int rc = 0; 658 int rc = 0;
659 struct cpu_vfs_cap_data vcaps; 659 struct cpu_vfs_cap_data vcaps;
@@ -684,7 +684,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c
684 goto out; 684 goto out;
685 } 685 }
686 686
687 rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective, has_cap); 687 rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective, has_fcap);
688 if (rc == -EINVAL) 688 if (rc == -EINVAL)
689 printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n", 689 printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
690 __func__, rc, bprm->filename); 690 __func__, rc, bprm->filename);
@@ -696,6 +696,115 @@ out:
696 return rc; 696 return rc;
697} 697}
698 698
699static inline bool root_privileged(void) { return !issecure(SECURE_NOROOT); }
700
701static inline bool __is_real(kuid_t uid, struct cred *cred)
702{ return uid_eq(cred->uid, uid); }
703
704static inline bool __is_eff(kuid_t uid, struct cred *cred)
705{ return uid_eq(cred->euid, uid); }
706
707static inline bool __is_suid(kuid_t uid, struct cred *cred)
708{ return !__is_real(uid, cred) && __is_eff(uid, cred); }
709
710/*
711 * handle_privileged_root - Handle case of privileged root
712 * @bprm: The execution parameters, including the proposed creds
713 * @has_fcap: Are any file capabilities set?
714 * @effective: Do we have effective root privilege?
715 * @root_uid: This namespace' root UID WRT initial USER namespace
716 *
717 * Handle the case where root is privileged and hasn't been neutered by
718 * SECURE_NOROOT. If file capabilities are set, they won't be combined with
719 * set UID root and nothing is changed. If we are root, cap_permitted is
720 * updated. If we have become set UID root, the effective bit is set.
721 */
722static void handle_privileged_root(struct linux_binprm *bprm, bool has_fcap,
723 bool *effective, kuid_t root_uid)
724{
725 const struct cred *old = current_cred();
726 struct cred *new = bprm->cred;
727
728 if (!root_privileged())
729 return;
730 /*
731 * If the legacy file capability is set, then don't set privs
732 * for a setuid root binary run by a non-root user. Do set it
733 * for a root user just to cause least surprise to an admin.
734 */
735 if (has_fcap && __is_suid(root_uid, new)) {
736 warn_setuid_and_fcaps_mixed(bprm->filename);
737 return;
738 }
739 /*
740 * To support inheritance of root-permissions and suid-root
741 * executables under compatibility mode, we override the
742 * capability sets for the file.
743 */
744 if (__is_eff(root_uid, new) || __is_real(root_uid, new)) {
745 /* pP' = (cap_bset & ~0) | (pI & ~0) */
746 new->cap_permitted = cap_combine(old->cap_bset,
747 old->cap_inheritable);
748 }
749 /*
750 * If only the real uid is 0, we do not set the effective bit.
751 */
752 if (__is_eff(root_uid, new))
753 *effective = true;
754}
755
756#define __cap_gained(field, target, source) \
757 !cap_issubset(target->cap_##field, source->cap_##field)
758#define __cap_grew(target, source, cred) \
759 !cap_issubset(cred->cap_##target, cred->cap_##source)
760#define __cap_full(field, cred) \
761 cap_issubset(CAP_FULL_SET, cred->cap_##field)
762
763static inline bool __is_setuid(struct cred *new, const struct cred *old)
764{ return !uid_eq(new->euid, old->uid); }
765
766static inline bool __is_setgid(struct cred *new, const struct cred *old)
767{ return !gid_eq(new->egid, old->gid); }
768
769/*
770 * 1) Audit candidate if current->cap_effective is set
771 *
772 * We do not bother to audit if 3 things are true:
773 * 1) cap_effective has all caps
774 * 2) we became root *OR* are were already root
775 * 3) root is supposed to have all caps (SECURE_NOROOT)
776 * Since this is just a normal root execing a process.
777 *
778 * Number 1 above might fail if you don't have a full bset, but I think
779 * that is interesting information to audit.
780 *
781 * A number of other conditions require logging:
782 * 2) something prevented setuid root getting all caps
783 * 3) non-setuid root gets fcaps
784 * 4) non-setuid root gets ambient
785 */
786static inline bool nonroot_raised_pE(struct cred *new, const struct cred *old,
787 kuid_t root, bool has_fcap)
788{
789 bool ret = false;
790
791 if ((__cap_grew(effective, ambient, new) &&
792 !(__cap_full(effective, new) &&
793 (__is_eff(root, new) || __is_real(root, new)) &&
794 root_privileged())) ||
795 (root_privileged() &&
796 __is_suid(root, new) &&
797 !__cap_full(effective, new)) ||
798 (!__is_setuid(new, old) &&
799 ((has_fcap &&
800 __cap_gained(permitted, new, old)) ||
801 __cap_gained(ambient, new, old))))
802
803 ret = true;
804
805 return ret;
806}
807
699/** 808/**
700 * cap_bprm_set_creds - Set up the proposed credentials for execve(). 809 * cap_bprm_set_creds - Set up the proposed credentials for execve().
701 * @bprm: The execution parameters, including the proposed creds 810 * @bprm: The execution parameters, including the proposed creds
@@ -708,61 +817,33 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
708{ 817{
709 const struct cred *old = current_cred(); 818 const struct cred *old = current_cred();
710 struct cred *new = bprm->cred; 819 struct cred *new = bprm->cred;
711 bool effective, has_cap = false, is_setid; 820 bool effective = false, has_fcap = false, is_setid;
712 int ret; 821 int ret;
713 kuid_t root_uid; 822 kuid_t root_uid;
714 823
715 if (WARN_ON(!cap_ambient_invariant_ok(old))) 824 if (WARN_ON(!cap_ambient_invariant_ok(old)))
716 return -EPERM; 825 return -EPERM;
717 826
718 effective = false; 827 ret = get_file_caps(bprm, &effective, &has_fcap);
719 ret = get_file_caps(bprm, &effective, &has_cap);
720 if (ret < 0) 828 if (ret < 0)
721 return ret; 829 return ret;
722 830
723 root_uid = make_kuid(new->user_ns, 0); 831 root_uid = make_kuid(new->user_ns, 0);
724 832
725 if (!issecure(SECURE_NOROOT)) { 833 handle_privileged_root(bprm, has_fcap, &effective, root_uid);
726 /*
727 * If the legacy file capability is set, then don't set privs
728 * for a setuid root binary run by a non-root user. Do set it
729 * for a root user just to cause least surprise to an admin.
730 */
731 if (has_cap && !uid_eq(new->uid, root_uid) && uid_eq(new->euid, root_uid)) {
732 warn_setuid_and_fcaps_mixed(bprm->filename);
733 goto skip;
734 }
735 /*
736 * To support inheritance of root-permissions and suid-root
737 * executables under compatibility mode, we override the
738 * capability sets for the file.
739 *
740 * If only the real uid is 0, we do not set the effective bit.
741 */
742 if (uid_eq(new->euid, root_uid) || uid_eq(new->uid, root_uid)) {
743 /* pP' = (cap_bset & ~0) | (pI & ~0) */
744 new->cap_permitted = cap_combine(old->cap_bset,
745 old->cap_inheritable);
746 }
747 if (uid_eq(new->euid, root_uid))
748 effective = true;
749 }
750skip:
751 834
752 /* if we have fs caps, clear dangerous personality flags */ 835 /* if we have fs caps, clear dangerous personality flags */
753 if (!cap_issubset(new->cap_permitted, old->cap_permitted)) 836 if (__cap_gained(permitted, new, old))
754 bprm->per_clear |= PER_CLEAR_ON_SETID; 837 bprm->per_clear |= PER_CLEAR_ON_SETID;
755 838
756
757 /* Don't let someone trace a set[ug]id/setpcap binary with the revised 839 /* Don't let someone trace a set[ug]id/setpcap binary with the revised
758 * credentials unless they have the appropriate permit. 840 * credentials unless they have the appropriate permit.
759 * 841 *
760 * In addition, if NO_NEW_PRIVS, then ensure we get no new privs. 842 * In addition, if NO_NEW_PRIVS, then ensure we get no new privs.
761 */ 843 */
762 is_setid = !uid_eq(new->euid, old->uid) || !gid_eq(new->egid, old->gid); 844 is_setid = __is_setuid(new, old) || __is_setgid(new, old);
763 845
764 if ((is_setid || 846 if ((is_setid || __cap_gained(permitted, new, old)) &&
765 !cap_issubset(new->cap_permitted, old->cap_permitted)) &&
766 ((bprm->unsafe & ~LSM_UNSAFE_PTRACE) || 847 ((bprm->unsafe & ~LSM_UNSAFE_PTRACE) ||
767 !ptracer_capable(current, new->user_ns))) { 848 !ptracer_capable(current, new->user_ns))) {
768 /* downgrade; they get no more than they had, and maybe less */ 849 /* downgrade; they get no more than they had, and maybe less */
@@ -779,7 +860,7 @@ skip:
779 new->sgid = new->fsgid = new->egid; 860 new->sgid = new->fsgid = new->egid;
780 861
781 /* File caps or setid cancels ambient. */ 862 /* File caps or setid cancels ambient. */
782 if (has_cap || is_setid) 863 if (has_fcap || is_setid)
783 cap_clear(new->cap_ambient); 864 cap_clear(new->cap_ambient);
784 865
785 /* 866 /*
@@ -800,26 +881,10 @@ skip:
800 if (WARN_ON(!cap_ambient_invariant_ok(new))) 881 if (WARN_ON(!cap_ambient_invariant_ok(new)))
801 return -EPERM; 882 return -EPERM;
802 883
803 /* 884 if (nonroot_raised_pE(new, old, root_uid, has_fcap)) {
804 * Audit candidate if current->cap_effective is set 885 ret = audit_log_bprm_fcaps(bprm, new, old);
805 * 886 if (ret < 0)
806 * We do not bother to audit if 3 things are true: 887 return ret;
807 * 1) cap_effective has all caps
808 * 2) we are root
809 * 3) root is supposed to have all caps (SECURE_NOROOT)
810 * Since this is just a normal root execing a process.
811 *
812 * Number 1 above might fail if you don't have a full bset, but I think
813 * that is interesting information to audit.
814 */
815 if (!cap_issubset(new->cap_effective, new->cap_ambient)) {
816 if (!cap_issubset(CAP_FULL_SET, new->cap_effective) ||
817 !uid_eq(new->euid, root_uid) || !uid_eq(new->uid, root_uid) ||
818 issecure(SECURE_NOROOT)) {
819 ret = audit_log_bprm_fcaps(bprm, new, old);
820 if (ret < 0)
821 return ret;
822 }
823 } 888 }
824 889
825 new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); 890 new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
@@ -829,13 +894,11 @@ skip:
829 894
830 /* Check for privilege-elevated exec. */ 895 /* Check for privilege-elevated exec. */
831 bprm->cap_elevated = 0; 896 bprm->cap_elevated = 0;
832 if (is_setid) { 897 if (is_setid ||
898 (!__is_real(root_uid, new) &&
899 (effective ||
900 __cap_grew(permitted, ambient, new))))
833 bprm->cap_elevated = 1; 901 bprm->cap_elevated = 1;
834 } else if (!uid_eq(new->uid, root_uid)) {
835 if (effective ||
836 !cap_issubset(new->cap_permitted, new->cap_ambient))
837 bprm->cap_elevated = 1;
838 }
839 902
840 return 0; 903 return 0;
841} 904}