diff options
Diffstat (limited to 'security/commoncap.c')
| -rw-r--r-- | security/commoncap.c | 68 |
1 files changed, 41 insertions, 27 deletions
diff --git a/security/commoncap.c b/security/commoncap.c index 71a166a05975..e771cb1b2d79 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
| @@ -77,12 +77,12 @@ int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, | |||
| 77 | int cap, int audit) | 77 | int cap, int audit) |
| 78 | { | 78 | { |
| 79 | for (;;) { | 79 | for (;;) { |
| 80 | /* The creator of the user namespace has all caps. */ | 80 | /* The owner of the user namespace has all caps. */ |
| 81 | if (targ_ns != &init_user_ns && targ_ns->creator == cred->user) | 81 | if (targ_ns != &init_user_ns && uid_eq(targ_ns->owner, cred->euid)) |
| 82 | return 0; | 82 | return 0; |
| 83 | 83 | ||
| 84 | /* Do we have the necessary capabilities? */ | 84 | /* Do we have the necessary capabilities? */ |
| 85 | if (targ_ns == cred->user->user_ns) | 85 | if (targ_ns == cred->user_ns) |
| 86 | return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM; | 86 | return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM; |
| 87 | 87 | ||
| 88 | /* Have we tried all of the parent namespaces? */ | 88 | /* Have we tried all of the parent namespaces? */ |
| @@ -93,7 +93,7 @@ int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, | |||
| 93 | *If you have a capability in a parent user ns, then you have | 93 | *If you have a capability in a parent user ns, then you have |
| 94 | * it over all children user namespaces as well. | 94 | * it over all children user namespaces as well. |
| 95 | */ | 95 | */ |
| 96 | targ_ns = targ_ns->creator->user_ns; | 96 | targ_ns = targ_ns->parent; |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | /* We never get here */ | 99 | /* We never get here */ |
| @@ -137,10 +137,10 @@ int cap_ptrace_access_check(struct task_struct *child, unsigned int mode) | |||
| 137 | rcu_read_lock(); | 137 | rcu_read_lock(); |
| 138 | cred = current_cred(); | 138 | cred = current_cred(); |
| 139 | child_cred = __task_cred(child); | 139 | child_cred = __task_cred(child); |
| 140 | if (cred->user->user_ns == child_cred->user->user_ns && | 140 | if (cred->user_ns == child_cred->user_ns && |
| 141 | cap_issubset(child_cred->cap_permitted, cred->cap_permitted)) | 141 | cap_issubset(child_cred->cap_permitted, cred->cap_permitted)) |
| 142 | goto out; | 142 | goto out; |
| 143 | if (ns_capable(child_cred->user->user_ns, CAP_SYS_PTRACE)) | 143 | if (ns_capable(child_cred->user_ns, CAP_SYS_PTRACE)) |
| 144 | goto out; | 144 | goto out; |
| 145 | ret = -EPERM; | 145 | ret = -EPERM; |
| 146 | out: | 146 | out: |
| @@ -169,10 +169,10 @@ int cap_ptrace_traceme(struct task_struct *parent) | |||
| 169 | rcu_read_lock(); | 169 | rcu_read_lock(); |
| 170 | cred = __task_cred(parent); | 170 | cred = __task_cred(parent); |
| 171 | child_cred = current_cred(); | 171 | child_cred = current_cred(); |
| 172 | if (cred->user->user_ns == child_cred->user->user_ns && | 172 | if (cred->user_ns == child_cred->user_ns && |
| 173 | cap_issubset(child_cred->cap_permitted, cred->cap_permitted)) | 173 | cap_issubset(child_cred->cap_permitted, cred->cap_permitted)) |
| 174 | goto out; | 174 | goto out; |
| 175 | if (has_ns_capability(parent, child_cred->user->user_ns, CAP_SYS_PTRACE)) | 175 | if (has_ns_capability(parent, child_cred->user_ns, CAP_SYS_PTRACE)) |
| 176 | goto out; | 176 | goto out; |
| 177 | ret = -EPERM; | 177 | ret = -EPERM; |
| 178 | out: | 178 | out: |
| @@ -215,7 +215,7 @@ static inline int cap_inh_is_capped(void) | |||
| 215 | /* they are so limited unless the current task has the CAP_SETPCAP | 215 | /* they are so limited unless the current task has the CAP_SETPCAP |
| 216 | * capability | 216 | * capability |
| 217 | */ | 217 | */ |
| 218 | if (cap_capable(current_cred(), current_cred()->user->user_ns, | 218 | if (cap_capable(current_cred(), current_cred()->user_ns, |
| 219 | CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0) | 219 | CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0) |
| 220 | return 0; | 220 | return 0; |
| 221 | return 1; | 221 | return 1; |
| @@ -473,19 +473,22 @@ int cap_bprm_set_creds(struct linux_binprm *bprm) | |||
| 473 | struct cred *new = bprm->cred; | 473 | struct cred *new = bprm->cred; |
| 474 | bool effective, has_cap = false; | 474 | bool effective, has_cap = false; |
| 475 | int ret; | 475 | int ret; |
| 476 | kuid_t root_uid; | ||
| 476 | 477 | ||
| 477 | effective = false; | 478 | effective = false; |
| 478 | ret = get_file_caps(bprm, &effective, &has_cap); | 479 | ret = get_file_caps(bprm, &effective, &has_cap); |
| 479 | if (ret < 0) | 480 | if (ret < 0) |
| 480 | return ret; | 481 | return ret; |
| 481 | 482 | ||
| 483 | root_uid = make_kuid(new->user_ns, 0); | ||
| 484 | |||
| 482 | if (!issecure(SECURE_NOROOT)) { | 485 | if (!issecure(SECURE_NOROOT)) { |
| 483 | /* | 486 | /* |
| 484 | * If the legacy file capability is set, then don't set privs | 487 | * If the legacy file capability is set, then don't set privs |
| 485 | * for a setuid root binary run by a non-root user. Do set it | 488 | * for a setuid root binary run by a non-root user. Do set it |
| 486 | * for a root user just to cause least surprise to an admin. | 489 | * for a root user just to cause least surprise to an admin. |
| 487 | */ | 490 | */ |
| 488 | if (has_cap && new->uid != 0 && new->euid == 0) { | 491 | if (has_cap && !uid_eq(new->uid, root_uid) && uid_eq(new->euid, root_uid)) { |
| 489 | warn_setuid_and_fcaps_mixed(bprm->filename); | 492 | warn_setuid_and_fcaps_mixed(bprm->filename); |
| 490 | goto skip; | 493 | goto skip; |
| 491 | } | 494 | } |
| @@ -496,12 +499,12 @@ int cap_bprm_set_creds(struct linux_binprm *bprm) | |||
| 496 | * | 499 | * |
| 497 | * If only the real uid is 0, we do not set the effective bit. | 500 | * If only the real uid is 0, we do not set the effective bit. |
| 498 | */ | 501 | */ |
| 499 | if (new->euid == 0 || new->uid == 0) { | 502 | if (uid_eq(new->euid, root_uid) || uid_eq(new->uid, root_uid)) { |
| 500 | /* pP' = (cap_bset & ~0) | (pI & ~0) */ | 503 | /* pP' = (cap_bset & ~0) | (pI & ~0) */ |
| 501 | new->cap_permitted = cap_combine(old->cap_bset, | 504 | new->cap_permitted = cap_combine(old->cap_bset, |
| 502 | old->cap_inheritable); | 505 | old->cap_inheritable); |
| 503 | } | 506 | } |
| 504 | if (new->euid == 0) | 507 | if (uid_eq(new->euid, root_uid)) |
| 505 | effective = true; | 508 | effective = true; |
| 506 | } | 509 | } |
| 507 | skip: | 510 | skip: |
| @@ -512,14 +515,17 @@ skip: | |||
| 512 | 515 | ||
| 513 | 516 | ||
| 514 | /* Don't let someone trace a set[ug]id/setpcap binary with the revised | 517 | /* Don't let someone trace a set[ug]id/setpcap binary with the revised |
| 515 | * credentials unless they have the appropriate permit | 518 | * credentials unless they have the appropriate permit. |
| 519 | * | ||
| 520 | * In addition, if NO_NEW_PRIVS, then ensure we get no new privs. | ||
| 516 | */ | 521 | */ |
| 517 | if ((new->euid != old->uid || | 522 | if ((!uid_eq(new->euid, old->uid) || |
| 518 | new->egid != old->gid || | 523 | !gid_eq(new->egid, old->gid) || |
| 519 | !cap_issubset(new->cap_permitted, old->cap_permitted)) && | 524 | !cap_issubset(new->cap_permitted, old->cap_permitted)) && |
| 520 | bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) { | 525 | bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) { |
| 521 | /* downgrade; they get no more than they had, and maybe less */ | 526 | /* downgrade; they get no more than they had, and maybe less */ |
| 522 | if (!capable(CAP_SETUID)) { | 527 | if (!capable(CAP_SETUID) || |
| 528 | (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)) { | ||
| 523 | new->euid = new->uid; | 529 | new->euid = new->uid; |
| 524 | new->egid = new->gid; | 530 | new->egid = new->gid; |
| 525 | } | 531 | } |
| @@ -550,7 +556,7 @@ skip: | |||
| 550 | */ | 556 | */ |
| 551 | if (!cap_isclear(new->cap_effective)) { | 557 | if (!cap_isclear(new->cap_effective)) { |
| 552 | if (!cap_issubset(CAP_FULL_SET, new->cap_effective) || | 558 | if (!cap_issubset(CAP_FULL_SET, new->cap_effective) || |
| 553 | new->euid != 0 || new->uid != 0 || | 559 | !uid_eq(new->euid, root_uid) || !uid_eq(new->uid, root_uid) || |
| 554 | issecure(SECURE_NOROOT)) { | 560 | issecure(SECURE_NOROOT)) { |
| 555 | ret = audit_log_bprm_fcaps(bprm, new, old); | 561 | ret = audit_log_bprm_fcaps(bprm, new, old); |
| 556 | if (ret < 0) | 562 | if (ret < 0) |
| @@ -575,16 +581,17 @@ skip: | |||
| 575 | int cap_bprm_secureexec(struct linux_binprm *bprm) | 581 | int cap_bprm_secureexec(struct linux_binprm *bprm) |
| 576 | { | 582 | { |
| 577 | const struct cred *cred = current_cred(); | 583 | const struct cred *cred = current_cred(); |
| 584 | kuid_t root_uid = make_kuid(cred->user_ns, 0); | ||
| 578 | 585 | ||
| 579 | if (cred->uid != 0) { | 586 | if (!uid_eq(cred->uid, root_uid)) { |
| 580 | if (bprm->cap_effective) | 587 | if (bprm->cap_effective) |
| 581 | return 1; | 588 | return 1; |
| 582 | if (!cap_isclear(cred->cap_permitted)) | 589 | if (!cap_isclear(cred->cap_permitted)) |
| 583 | return 1; | 590 | return 1; |
| 584 | } | 591 | } |
| 585 | 592 | ||
| 586 | return (cred->euid != cred->uid || | 593 | return (!uid_eq(cred->euid, cred->uid) || |
| 587 | cred->egid != cred->gid); | 594 | !gid_eq(cred->egid, cred->gid)); |
| 588 | } | 595 | } |
| 589 | 596 | ||
| 590 | /** | 597 | /** |
| @@ -674,15 +681,21 @@ int cap_inode_removexattr(struct dentry *dentry, const char *name) | |||
| 674 | */ | 681 | */ |
| 675 | static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old) | 682 | static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old) |
| 676 | { | 683 | { |
| 677 | if ((old->uid == 0 || old->euid == 0 || old->suid == 0) && | 684 | kuid_t root_uid = make_kuid(old->user_ns, 0); |
| 678 | (new->uid != 0 && new->euid != 0 && new->suid != 0) && | 685 | |
| 686 | if ((uid_eq(old->uid, root_uid) || | ||
| 687 | uid_eq(old->euid, root_uid) || | ||
| 688 | uid_eq(old->suid, root_uid)) && | ||
| 689 | (!uid_eq(new->uid, root_uid) && | ||
| 690 | !uid_eq(new->euid, root_uid) && | ||
| 691 | !uid_eq(new->suid, root_uid)) && | ||
| 679 | !issecure(SECURE_KEEP_CAPS)) { | 692 | !issecure(SECURE_KEEP_CAPS)) { |
| 680 | cap_clear(new->cap_permitted); | 693 | cap_clear(new->cap_permitted); |
| 681 | cap_clear(new->cap_effective); | 694 | cap_clear(new->cap_effective); |
| 682 | } | 695 | } |
| 683 | if (old->euid == 0 && new->euid != 0) | 696 | if (uid_eq(old->euid, root_uid) && !uid_eq(new->euid, root_uid)) |
| 684 | cap_clear(new->cap_effective); | 697 | cap_clear(new->cap_effective); |
| 685 | if (old->euid != 0 && new->euid == 0) | 698 | if (!uid_eq(old->euid, root_uid) && uid_eq(new->euid, root_uid)) |
| 686 | new->cap_effective = new->cap_permitted; | 699 | new->cap_effective = new->cap_permitted; |
| 687 | } | 700 | } |
| 688 | 701 | ||
| @@ -715,11 +728,12 @@ int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags) | |||
| 715 | * if not, we might be a bit too harsh here. | 728 | * if not, we might be a bit too harsh here. |
| 716 | */ | 729 | */ |
| 717 | if (!issecure(SECURE_NO_SETUID_FIXUP)) { | 730 | if (!issecure(SECURE_NO_SETUID_FIXUP)) { |
| 718 | if (old->fsuid == 0 && new->fsuid != 0) | 731 | kuid_t root_uid = make_kuid(old->user_ns, 0); |
| 732 | if (uid_eq(old->fsuid, root_uid) && !uid_eq(new->fsuid, root_uid)) | ||
| 719 | new->cap_effective = | 733 | new->cap_effective = |
| 720 | cap_drop_fs_set(new->cap_effective); | 734 | cap_drop_fs_set(new->cap_effective); |
| 721 | 735 | ||
| 722 | if (old->fsuid != 0 && new->fsuid == 0) | 736 | if (!uid_eq(old->fsuid, root_uid) && uid_eq(new->fsuid, root_uid)) |
| 723 | new->cap_effective = | 737 | new->cap_effective = |
| 724 | cap_raise_fs_set(new->cap_effective, | 738 | cap_raise_fs_set(new->cap_effective, |
| 725 | new->cap_permitted); | 739 | new->cap_permitted); |
| @@ -872,7 +886,7 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
| 872 | || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ | 886 | || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ |
| 873 | || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ | 887 | || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ |
| 874 | || (cap_capable(current_cred(), | 888 | || (cap_capable(current_cred(), |
| 875 | current_cred()->user->user_ns, CAP_SETPCAP, | 889 | current_cred()->user_ns, CAP_SETPCAP, |
| 876 | SECURITY_CAP_AUDIT) != 0) /*[4]*/ | 890 | SECURITY_CAP_AUDIT) != 0) /*[4]*/ |
| 877 | /* | 891 | /* |
| 878 | * [1] no changing of bits that are locked | 892 | * [1] no changing of bits that are locked |
