diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2012-02-07 19:45:47 -0500 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2012-05-03 06:28:40 -0400 |
commit | 18815a18085364d8514c0d0c4c986776cb74272c (patch) | |
tree | a931fb2eee31aee6f8d83ef4493071b9827b1b9f /security | |
parent | 9c806aa06f8e121c6058db8e8073798aa5c4355b (diff) |
userns: Convert capabilities related permsion checks
- Use uid_eq when comparing kuids
Use gid_eq when comparing kgids
- Use make_kuid(user_ns, 0) to talk about the user_namespace root uid
Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Diffstat (limited to 'security')
-rw-r--r-- | security/commoncap.c | 41 |
1 files changed, 26 insertions, 15 deletions
diff --git a/security/commoncap.c b/security/commoncap.c index dbd465a59286..ff9b113bb07c 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -472,19 +472,22 @@ int cap_bprm_set_creds(struct linux_binprm *bprm) | |||
472 | struct cred *new = bprm->cred; | 472 | struct cred *new = bprm->cred; |
473 | bool effective, has_cap = false; | 473 | bool effective, has_cap = false; |
474 | int ret; | 474 | int ret; |
475 | kuid_t root_uid; | ||
475 | 476 | ||
476 | effective = false; | 477 | effective = false; |
477 | ret = get_file_caps(bprm, &effective, &has_cap); | 478 | ret = get_file_caps(bprm, &effective, &has_cap); |
478 | if (ret < 0) | 479 | if (ret < 0) |
479 | return ret; | 480 | return ret; |
480 | 481 | ||
482 | root_uid = make_kuid(new->user_ns, 0); | ||
483 | |||
481 | if (!issecure(SECURE_NOROOT)) { | 484 | if (!issecure(SECURE_NOROOT)) { |
482 | /* | 485 | /* |
483 | * If the legacy file capability is set, then don't set privs | 486 | * If the legacy file capability is set, then don't set privs |
484 | * for a setuid root binary run by a non-root user. Do set it | 487 | * for a setuid root binary run by a non-root user. Do set it |
485 | * for a root user just to cause least surprise to an admin. | 488 | * for a root user just to cause least surprise to an admin. |
486 | */ | 489 | */ |
487 | if (has_cap && new->uid != 0 && new->euid == 0) { | 490 | if (has_cap && !uid_eq(new->uid, root_uid) && uid_eq(new->euid, root_uid)) { |
488 | warn_setuid_and_fcaps_mixed(bprm->filename); | 491 | warn_setuid_and_fcaps_mixed(bprm->filename); |
489 | goto skip; | 492 | goto skip; |
490 | } | 493 | } |
@@ -495,12 +498,12 @@ int cap_bprm_set_creds(struct linux_binprm *bprm) | |||
495 | * | 498 | * |
496 | * If only the real uid is 0, we do not set the effective bit. | 499 | * If only the real uid is 0, we do not set the effective bit. |
497 | */ | 500 | */ |
498 | if (new->euid == 0 || new->uid == 0) { | 501 | if (uid_eq(new->euid, root_uid) || uid_eq(new->uid, root_uid)) { |
499 | /* pP' = (cap_bset & ~0) | (pI & ~0) */ | 502 | /* pP' = (cap_bset & ~0) | (pI & ~0) */ |
500 | new->cap_permitted = cap_combine(old->cap_bset, | 503 | new->cap_permitted = cap_combine(old->cap_bset, |
501 | old->cap_inheritable); | 504 | old->cap_inheritable); |
502 | } | 505 | } |
503 | if (new->euid == 0) | 506 | if (uid_eq(new->euid, root_uid)) |
504 | effective = true; | 507 | effective = true; |
505 | } | 508 | } |
506 | skip: | 509 | skip: |
@@ -508,8 +511,8 @@ skip: | |||
508 | /* Don't let someone trace a set[ug]id/setpcap binary with the revised | 511 | /* Don't let someone trace a set[ug]id/setpcap binary with the revised |
509 | * credentials unless they have the appropriate permit | 512 | * credentials unless they have the appropriate permit |
510 | */ | 513 | */ |
511 | if ((new->euid != old->uid || | 514 | if ((!uid_eq(new->euid, old->uid) || |
512 | new->egid != old->gid || | 515 | !gid_eq(new->egid, old->gid) || |
513 | !cap_issubset(new->cap_permitted, old->cap_permitted)) && | 516 | !cap_issubset(new->cap_permitted, old->cap_permitted)) && |
514 | bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) { | 517 | bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) { |
515 | /* downgrade; they get no more than they had, and maybe less */ | 518 | /* downgrade; they get no more than they had, and maybe less */ |
@@ -544,7 +547,7 @@ skip: | |||
544 | */ | 547 | */ |
545 | if (!cap_isclear(new->cap_effective)) { | 548 | if (!cap_isclear(new->cap_effective)) { |
546 | if (!cap_issubset(CAP_FULL_SET, new->cap_effective) || | 549 | if (!cap_issubset(CAP_FULL_SET, new->cap_effective) || |
547 | new->euid != 0 || new->uid != 0 || | 550 | !uid_eq(new->euid, root_uid) || !uid_eq(new->uid, root_uid) || |
548 | issecure(SECURE_NOROOT)) { | 551 | issecure(SECURE_NOROOT)) { |
549 | ret = audit_log_bprm_fcaps(bprm, new, old); | 552 | ret = audit_log_bprm_fcaps(bprm, new, old); |
550 | if (ret < 0) | 553 | if (ret < 0) |
@@ -569,16 +572,17 @@ skip: | |||
569 | int cap_bprm_secureexec(struct linux_binprm *bprm) | 572 | int cap_bprm_secureexec(struct linux_binprm *bprm) |
570 | { | 573 | { |
571 | const struct cred *cred = current_cred(); | 574 | const struct cred *cred = current_cred(); |
575 | kuid_t root_uid = make_kuid(cred->user_ns, 0); | ||
572 | 576 | ||
573 | if (cred->uid != 0) { | 577 | if (!uid_eq(cred->uid, root_uid)) { |
574 | if (bprm->cap_effective) | 578 | if (bprm->cap_effective) |
575 | return 1; | 579 | return 1; |
576 | if (!cap_isclear(cred->cap_permitted)) | 580 | if (!cap_isclear(cred->cap_permitted)) |
577 | return 1; | 581 | return 1; |
578 | } | 582 | } |
579 | 583 | ||
580 | return (cred->euid != cred->uid || | 584 | return (!uid_eq(cred->euid, cred->uid) || |
581 | cred->egid != cred->gid); | 585 | !gid_eq(cred->egid, cred->gid)); |
582 | } | 586 | } |
583 | 587 | ||
584 | /** | 588 | /** |
@@ -668,15 +672,21 @@ int cap_inode_removexattr(struct dentry *dentry, const char *name) | |||
668 | */ | 672 | */ |
669 | static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old) | 673 | static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old) |
670 | { | 674 | { |
671 | if ((old->uid == 0 || old->euid == 0 || old->suid == 0) && | 675 | kuid_t root_uid = make_kuid(old->user_ns, 0); |
672 | (new->uid != 0 && new->euid != 0 && new->suid != 0) && | 676 | |
677 | if ((uid_eq(old->uid, root_uid) || | ||
678 | uid_eq(old->euid, root_uid) || | ||
679 | uid_eq(old->suid, root_uid)) && | ||
680 | (!uid_eq(new->uid, root_uid) && | ||
681 | !uid_eq(new->euid, root_uid) && | ||
682 | !uid_eq(new->suid, root_uid)) && | ||
673 | !issecure(SECURE_KEEP_CAPS)) { | 683 | !issecure(SECURE_KEEP_CAPS)) { |
674 | cap_clear(new->cap_permitted); | 684 | cap_clear(new->cap_permitted); |
675 | cap_clear(new->cap_effective); | 685 | cap_clear(new->cap_effective); |
676 | } | 686 | } |
677 | if (old->euid == 0 && new->euid != 0) | 687 | if (uid_eq(old->euid, root_uid) && !uid_eq(new->euid, root_uid)) |
678 | cap_clear(new->cap_effective); | 688 | cap_clear(new->cap_effective); |
679 | if (old->euid != 0 && new->euid == 0) | 689 | if (!uid_eq(old->euid, root_uid) && uid_eq(new->euid, root_uid)) |
680 | new->cap_effective = new->cap_permitted; | 690 | new->cap_effective = new->cap_permitted; |
681 | } | 691 | } |
682 | 692 | ||
@@ -709,11 +719,12 @@ int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags) | |||
709 | * if not, we might be a bit too harsh here. | 719 | * if not, we might be a bit too harsh here. |
710 | */ | 720 | */ |
711 | if (!issecure(SECURE_NO_SETUID_FIXUP)) { | 721 | if (!issecure(SECURE_NO_SETUID_FIXUP)) { |
712 | if (old->fsuid == 0 && new->fsuid != 0) | 722 | kuid_t root_uid = make_kuid(old->user_ns, 0); |
723 | if (uid_eq(old->fsuid, root_uid) && !uid_eq(new->fsuid, root_uid)) | ||
713 | new->cap_effective = | 724 | new->cap_effective = |
714 | cap_drop_fs_set(new->cap_effective); | 725 | cap_drop_fs_set(new->cap_effective); |
715 | 726 | ||
716 | if (old->fsuid != 0 && new->fsuid == 0) | 727 | if (!uid_eq(old->fsuid, root_uid) && uid_eq(new->fsuid, root_uid)) |
717 | new->cap_effective = | 728 | new->cap_effective = |
718 | cap_raise_fs_set(new->cap_effective, | 729 | cap_raise_fs_set(new->cap_effective, |
719 | new->cap_permitted); | 730 | new->cap_permitted); |