diff options
| author | James Morris <james.l.morris@oracle.com> | 2012-06-10 08:52:10 -0400 |
|---|---|---|
| committer | James Morris <james.l.morris@oracle.com> | 2012-06-10 08:52:10 -0400 |
| commit | 66dd07b88a1c9d446f32253da606b87324fa620e (patch) | |
| tree | 4e0971bdd543585c7ab46716ae808a7fd82f9c35 /security | |
| parent | f52c44cd27b4a0be37ef97f0466e4095ebebef3f (diff) | |
| parent | cfaf025112d3856637ff34a767ef785ef5cf2ca9 (diff) | |
Merge commit 'v3.5-rc2' into next
Diffstat (limited to 'security')
| -rw-r--r-- | security/apparmor/lsm.c | 15 | ||||
| -rw-r--r-- | security/capability.c | 3 | ||||
| -rw-r--r-- | security/commoncap.c | 78 | ||||
| -rw-r--r-- | security/device_cgroup.c | 10 | ||||
| -rw-r--r-- | security/keys/compat.c | 2 | ||||
| -rw-r--r-- | security/keys/internal.h | 2 | ||||
| -rw-r--r-- | security/keys/key.c | 2 | ||||
| -rw-r--r-- | security/keys/keyctl.c | 77 | ||||
| -rw-r--r-- | security/keys/permission.c | 5 | ||||
| -rw-r--r-- | security/keys/process_keys.c | 22 | ||||
| -rw-r--r-- | security/keys/request_key.c | 13 | ||||
| -rw-r--r-- | security/security.c | 51 | ||||
| -rw-r--r-- | security/selinux/hooks.c | 15 | ||||
| -rw-r--r-- | security/selinux/nlmsgtab.c | 13 | ||||
| -rw-r--r-- | security/selinux/selinuxfs.c | 36 | ||||
| -rw-r--r-- | security/smack/smack_lsm.c | 15 |
16 files changed, 173 insertions, 186 deletions
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 032daab449b0..8ea39aabe948 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c | |||
| @@ -490,17 +490,9 @@ static int common_mmap(int op, struct file *file, unsigned long prot, | |||
| 490 | return common_file_perm(op, file, mask); | 490 | return common_file_perm(op, file, mask); |
| 491 | } | 491 | } |
| 492 | 492 | ||
| 493 | static int apparmor_file_mmap(struct file *file, unsigned long reqprot, | 493 | static int apparmor_mmap_file(struct file *file, unsigned long reqprot, |
| 494 | unsigned long prot, unsigned long flags, | 494 | unsigned long prot, unsigned long flags) |
| 495 | unsigned long addr, unsigned long addr_only) | ||
| 496 | { | 495 | { |
| 497 | int rc = 0; | ||
| 498 | |||
| 499 | /* do DAC check */ | ||
| 500 | rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only); | ||
| 501 | if (rc || addr_only) | ||
| 502 | return rc; | ||
| 503 | |||
| 504 | return common_mmap(OP_FMMAP, file, prot, flags); | 496 | return common_mmap(OP_FMMAP, file, prot, flags); |
| 505 | } | 497 | } |
| 506 | 498 | ||
| @@ -646,7 +638,8 @@ static struct security_operations apparmor_ops = { | |||
| 646 | .file_permission = apparmor_file_permission, | 638 | .file_permission = apparmor_file_permission, |
| 647 | .file_alloc_security = apparmor_file_alloc_security, | 639 | .file_alloc_security = apparmor_file_alloc_security, |
| 648 | .file_free_security = apparmor_file_free_security, | 640 | .file_free_security = apparmor_file_free_security, |
| 649 | .file_mmap = apparmor_file_mmap, | 641 | .mmap_file = apparmor_mmap_file, |
| 642 | .mmap_addr = cap_mmap_addr, | ||
| 650 | .file_mprotect = apparmor_file_mprotect, | 643 | .file_mprotect = apparmor_file_mprotect, |
| 651 | .file_lock = apparmor_file_lock, | 644 | .file_lock = apparmor_file_lock, |
| 652 | 645 | ||
diff --git a/security/capability.c b/security/capability.c index fca889676c5e..61095df8b89a 100644 --- a/security/capability.c +++ b/security/capability.c | |||
| @@ -949,7 +949,8 @@ void __init security_fixup_ops(struct security_operations *ops) | |||
| 949 | set_to_cap_if_null(ops, file_alloc_security); | 949 | set_to_cap_if_null(ops, file_alloc_security); |
| 950 | set_to_cap_if_null(ops, file_free_security); | 950 | set_to_cap_if_null(ops, file_free_security); |
| 951 | set_to_cap_if_null(ops, file_ioctl); | 951 | set_to_cap_if_null(ops, file_ioctl); |
| 952 | set_to_cap_if_null(ops, file_mmap); | 952 | set_to_cap_if_null(ops, mmap_addr); |
| 953 | set_to_cap_if_null(ops, mmap_file); | ||
| 953 | set_to_cap_if_null(ops, file_mprotect); | 954 | set_to_cap_if_null(ops, file_mprotect); |
| 954 | set_to_cap_if_null(ops, file_lock); | 955 | set_to_cap_if_null(ops, file_lock); |
| 955 | set_to_cap_if_null(ops, file_fcntl); | 956 | set_to_cap_if_null(ops, file_fcntl); |
diff --git a/security/commoncap.c b/security/commoncap.c index f80d11609391..6dbae4650abe 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: |
| @@ -516,8 +519,8 @@ skip: | |||
| 516 | * | 519 | * |
| 517 | * In addition, if NO_NEW_PRIVS, then ensure we get no new privs. | 520 | * In addition, if NO_NEW_PRIVS, then ensure we get no new privs. |
| 518 | */ | 521 | */ |
| 519 | if ((new->euid != old->uid || | 522 | if ((!uid_eq(new->euid, old->uid) || |
| 520 | new->egid != old->gid || | 523 | !gid_eq(new->egid, old->gid) || |
| 521 | !cap_issubset(new->cap_permitted, old->cap_permitted)) && | 524 | !cap_issubset(new->cap_permitted, old->cap_permitted)) && |
| 522 | bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) { | 525 | bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) { |
| 523 | /* downgrade; they get no more than they had, and maybe less */ | 526 | /* downgrade; they get no more than they had, and maybe less */ |
| @@ -553,7 +556,7 @@ skip: | |||
| 553 | */ | 556 | */ |
| 554 | if (!cap_isclear(new->cap_effective)) { | 557 | if (!cap_isclear(new->cap_effective)) { |
| 555 | if (!cap_issubset(CAP_FULL_SET, new->cap_effective) || | 558 | if (!cap_issubset(CAP_FULL_SET, new->cap_effective) || |
| 556 | new->euid != 0 || new->uid != 0 || | 559 | !uid_eq(new->euid, root_uid) || !uid_eq(new->uid, root_uid) || |
| 557 | issecure(SECURE_NOROOT)) { | 560 | issecure(SECURE_NOROOT)) { |
| 558 | ret = audit_log_bprm_fcaps(bprm, new, old); | 561 | ret = audit_log_bprm_fcaps(bprm, new, old); |
| 559 | if (ret < 0) | 562 | if (ret < 0) |
| @@ -578,16 +581,17 @@ skip: | |||
| 578 | int cap_bprm_secureexec(struct linux_binprm *bprm) | 581 | int cap_bprm_secureexec(struct linux_binprm *bprm) |
| 579 | { | 582 | { |
| 580 | const struct cred *cred = current_cred(); | 583 | const struct cred *cred = current_cred(); |
| 584 | kuid_t root_uid = make_kuid(cred->user_ns, 0); | ||
| 581 | 585 | ||
| 582 | if (cred->uid != 0) { | 586 | if (!uid_eq(cred->uid, root_uid)) { |
| 583 | if (bprm->cap_effective) | 587 | if (bprm->cap_effective) |
| 584 | return 1; | 588 | return 1; |
| 585 | if (!cap_isclear(cred->cap_permitted)) | 589 | if (!cap_isclear(cred->cap_permitted)) |
| 586 | return 1; | 590 | return 1; |
| 587 | } | 591 | } |
| 588 | 592 | ||
| 589 | return (cred->euid != cred->uid || | 593 | return (!uid_eq(cred->euid, cred->uid) || |
| 590 | cred->egid != cred->gid); | 594 | !gid_eq(cred->egid, cred->gid)); |
| 591 | } | 595 | } |
| 592 | 596 | ||
| 593 | /** | 597 | /** |
| @@ -677,15 +681,21 @@ int cap_inode_removexattr(struct dentry *dentry, const char *name) | |||
| 677 | */ | 681 | */ |
| 678 | 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) |
| 679 | { | 683 | { |
| 680 | if ((old->uid == 0 || old->euid == 0 || old->suid == 0) && | 684 | kuid_t root_uid = make_kuid(old->user_ns, 0); |
| 681 | (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)) && | ||
| 682 | !issecure(SECURE_KEEP_CAPS)) { | 692 | !issecure(SECURE_KEEP_CAPS)) { |
| 683 | cap_clear(new->cap_permitted); | 693 | cap_clear(new->cap_permitted); |
| 684 | cap_clear(new->cap_effective); | 694 | cap_clear(new->cap_effective); |
| 685 | } | 695 | } |
| 686 | if (old->euid == 0 && new->euid != 0) | 696 | if (uid_eq(old->euid, root_uid) && !uid_eq(new->euid, root_uid)) |
| 687 | cap_clear(new->cap_effective); | 697 | cap_clear(new->cap_effective); |
| 688 | if (old->euid != 0 && new->euid == 0) | 698 | if (!uid_eq(old->euid, root_uid) && uid_eq(new->euid, root_uid)) |
| 689 | new->cap_effective = new->cap_permitted; | 699 | new->cap_effective = new->cap_permitted; |
| 690 | } | 700 | } |
| 691 | 701 | ||
| @@ -718,11 +728,12 @@ int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags) | |||
| 718 | * if not, we might be a bit too harsh here. | 728 | * if not, we might be a bit too harsh here. |
| 719 | */ | 729 | */ |
| 720 | if (!issecure(SECURE_NO_SETUID_FIXUP)) { | 730 | if (!issecure(SECURE_NO_SETUID_FIXUP)) { |
| 721 | 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)) | ||
| 722 | new->cap_effective = | 733 | new->cap_effective = |
| 723 | cap_drop_fs_set(new->cap_effective); | 734 | cap_drop_fs_set(new->cap_effective); |
| 724 | 735 | ||
| 725 | if (old->fsuid != 0 && new->fsuid == 0) | 736 | if (!uid_eq(old->fsuid, root_uid) && uid_eq(new->fsuid, root_uid)) |
| 726 | new->cap_effective = | 737 | new->cap_effective = |
| 727 | cap_raise_fs_set(new->cap_effective, | 738 | cap_raise_fs_set(new->cap_effective, |
| 728 | new->cap_permitted); | 739 | new->cap_permitted); |
| @@ -875,7 +886,7 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
| 875 | || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ | 886 | || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ |
| 876 | || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ | 887 | || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ |
| 877 | || (cap_capable(current_cred(), | 888 | || (cap_capable(current_cred(), |
| 878 | current_cred()->user->user_ns, CAP_SETPCAP, | 889 | current_cred()->user_ns, CAP_SETPCAP, |
| 879 | SECURITY_CAP_AUDIT) != 0) /*[4]*/ | 890 | SECURITY_CAP_AUDIT) != 0) /*[4]*/ |
| 880 | /* | 891 | /* |
| 881 | * [1] no changing of bits that are locked | 892 | * [1] no changing of bits that are locked |
| @@ -947,22 +958,15 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages) | |||
| 947 | } | 958 | } |
| 948 | 959 | ||
| 949 | /* | 960 | /* |
| 950 | * cap_file_mmap - check if able to map given addr | 961 | * cap_mmap_addr - check if able to map given addr |
| 951 | * @file: unused | ||
| 952 | * @reqprot: unused | ||
| 953 | * @prot: unused | ||
| 954 | * @flags: unused | ||
| 955 | * @addr: address attempting to be mapped | 962 | * @addr: address attempting to be mapped |
| 956 | * @addr_only: unused | ||
| 957 | * | 963 | * |
| 958 | * If the process is attempting to map memory below dac_mmap_min_addr they need | 964 | * If the process is attempting to map memory below dac_mmap_min_addr they need |
| 959 | * CAP_SYS_RAWIO. The other parameters to this function are unused by the | 965 | * CAP_SYS_RAWIO. The other parameters to this function are unused by the |
| 960 | * capability security module. Returns 0 if this mapping should be allowed | 966 | * capability security module. Returns 0 if this mapping should be allowed |
| 961 | * -EPERM if not. | 967 | * -EPERM if not. |
| 962 | */ | 968 | */ |
| 963 | int cap_file_mmap(struct file *file, unsigned long reqprot, | 969 | int cap_mmap_addr(unsigned long addr) |
| 964 | unsigned long prot, unsigned long flags, | ||
| 965 | unsigned long addr, unsigned long addr_only) | ||
| 966 | { | 970 | { |
| 967 | int ret = 0; | 971 | int ret = 0; |
| 968 | 972 | ||
| @@ -975,3 +979,9 @@ int cap_file_mmap(struct file *file, unsigned long reqprot, | |||
| 975 | } | 979 | } |
| 976 | return ret; | 980 | return ret; |
| 977 | } | 981 | } |
| 982 | |||
| 983 | int cap_mmap_file(struct file *file, unsigned long reqprot, | ||
| 984 | unsigned long prot, unsigned long flags) | ||
| 985 | { | ||
| 986 | return 0; | ||
| 987 | } | ||
diff --git a/security/device_cgroup.c b/security/device_cgroup.c index c43a3323feea..442204cc22d9 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c | |||
| @@ -447,22 +447,16 @@ static struct cftype dev_cgroup_files[] = { | |||
| 447 | .read_seq_string = devcgroup_seq_read, | 447 | .read_seq_string = devcgroup_seq_read, |
| 448 | .private = DEVCG_LIST, | 448 | .private = DEVCG_LIST, |
| 449 | }, | 449 | }, |
| 450 | { } /* terminate */ | ||
| 450 | }; | 451 | }; |
| 451 | 452 | ||
| 452 | static int devcgroup_populate(struct cgroup_subsys *ss, | ||
| 453 | struct cgroup *cgroup) | ||
| 454 | { | ||
| 455 | return cgroup_add_files(cgroup, ss, dev_cgroup_files, | ||
| 456 | ARRAY_SIZE(dev_cgroup_files)); | ||
| 457 | } | ||
| 458 | |||
| 459 | struct cgroup_subsys devices_subsys = { | 453 | struct cgroup_subsys devices_subsys = { |
| 460 | .name = "devices", | 454 | .name = "devices", |
| 461 | .can_attach = devcgroup_can_attach, | 455 | .can_attach = devcgroup_can_attach, |
| 462 | .create = devcgroup_create, | 456 | .create = devcgroup_create, |
| 463 | .destroy = devcgroup_destroy, | 457 | .destroy = devcgroup_destroy, |
| 464 | .populate = devcgroup_populate, | ||
| 465 | .subsys_id = devices_subsys_id, | 458 | .subsys_id = devices_subsys_id, |
| 459 | .base_cftypes = dev_cgroup_files, | ||
| 466 | }; | 460 | }; |
| 467 | 461 | ||
| 468 | int __devcgroup_inode_permission(struct inode *inode, int mask) | 462 | int __devcgroup_inode_permission(struct inode *inode, int mask) |
diff --git a/security/keys/compat.c b/security/keys/compat.c index e35ae1d208a8..1c261763f479 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c | |||
| @@ -38,7 +38,7 @@ static long compat_keyctl_instantiate_key_iov( | |||
| 38 | 38 | ||
| 39 | ret = compat_rw_copy_check_uvector(WRITE, _payload_iov, ioc, | 39 | ret = compat_rw_copy_check_uvector(WRITE, _payload_iov, ioc, |
| 40 | ARRAY_SIZE(iovstack), | 40 | ARRAY_SIZE(iovstack), |
| 41 | iovstack, &iov, 1); | 41 | iovstack, &iov); |
| 42 | if (ret < 0) | 42 | if (ret < 0) |
| 43 | return ret; | 43 | return ret; |
| 44 | if (ret == 0) | 44 | if (ret == 0) |
diff --git a/security/keys/internal.h b/security/keys/internal.h index f173be2ce3ea..c990b8c8ef1d 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | 14 | ||
| 15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
| 16 | #include <linux/key-type.h> | 16 | #include <linux/key-type.h> |
| 17 | #include <linux/task_work.h> | ||
| 17 | 18 | ||
| 18 | #ifdef __KDEBUG | 19 | #ifdef __KDEBUG |
| 19 | #define kenter(FMT, ...) \ | 20 | #define kenter(FMT, ...) \ |
| @@ -148,6 +149,7 @@ extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags, | |||
| 148 | #define KEY_LOOKUP_FOR_UNLINK 0x04 | 149 | #define KEY_LOOKUP_FOR_UNLINK 0x04 |
| 149 | 150 | ||
| 150 | extern long join_session_keyring(const char *name); | 151 | extern long join_session_keyring(const char *name); |
| 152 | extern void key_change_session_keyring(struct task_work *twork); | ||
| 151 | 153 | ||
| 152 | extern struct work_struct key_gc_work; | 154 | extern struct work_struct key_gc_work; |
| 153 | extern unsigned key_gc_delay; | 155 | extern unsigned key_gc_delay; |
diff --git a/security/keys/key.c b/security/keys/key.c index c9bf66ac36e0..50d96d4e06f2 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
| @@ -253,7 +253,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, | |||
| 253 | quotalen = desclen + type->def_datalen; | 253 | quotalen = desclen + type->def_datalen; |
| 254 | 254 | ||
| 255 | /* get hold of the key tracking for this user */ | 255 | /* get hold of the key tracking for this user */ |
| 256 | user = key_user_lookup(uid, cred->user->user_ns); | 256 | user = key_user_lookup(uid, cred->user_ns); |
| 257 | if (!user) | 257 | if (!user) |
| 258 | goto no_memory_1; | 258 | goto no_memory_1; |
| 259 | 259 | ||
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index b61c063888b9..3bdc419b272f 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
| @@ -84,7 +84,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, | |||
| 84 | vm = false; | 84 | vm = false; |
| 85 | if (_payload) { | 85 | if (_payload) { |
| 86 | ret = -ENOMEM; | 86 | ret = -ENOMEM; |
| 87 | payload = kmalloc(plen, GFP_KERNEL); | 87 | payload = kmalloc(plen, GFP_KERNEL | __GFP_NOWARN); |
| 88 | if (!payload) { | 88 | if (!payload) { |
| 89 | if (plen <= PAGE_SIZE) | 89 | if (plen <= PAGE_SIZE) |
| 90 | goto error2; | 90 | goto error2; |
| @@ -1110,7 +1110,7 @@ long keyctl_instantiate_key_iov(key_serial_t id, | |||
| 1110 | goto no_payload; | 1110 | goto no_payload; |
| 1111 | 1111 | ||
| 1112 | ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc, | 1112 | ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc, |
| 1113 | ARRAY_SIZE(iovstack), iovstack, &iov, 1); | 1113 | ARRAY_SIZE(iovstack), iovstack, &iov); |
| 1114 | if (ret < 0) | 1114 | if (ret < 0) |
| 1115 | return ret; | 1115 | return ret; |
| 1116 | if (ret == 0) | 1116 | if (ret == 0) |
| @@ -1454,50 +1454,57 @@ long keyctl_get_security(key_serial_t keyid, | |||
| 1454 | */ | 1454 | */ |
| 1455 | long keyctl_session_to_parent(void) | 1455 | long keyctl_session_to_parent(void) |
| 1456 | { | 1456 | { |
| 1457 | #ifdef TIF_NOTIFY_RESUME | ||
| 1458 | struct task_struct *me, *parent; | 1457 | struct task_struct *me, *parent; |
| 1459 | const struct cred *mycred, *pcred; | 1458 | const struct cred *mycred, *pcred; |
| 1460 | struct cred *cred, *oldcred; | 1459 | struct task_work *newwork, *oldwork; |
| 1461 | key_ref_t keyring_r; | 1460 | key_ref_t keyring_r; |
| 1461 | struct cred *cred; | ||
| 1462 | int ret; | 1462 | int ret; |
| 1463 | 1463 | ||
| 1464 | keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK); | 1464 | keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK); |
| 1465 | if (IS_ERR(keyring_r)) | 1465 | if (IS_ERR(keyring_r)) |
| 1466 | return PTR_ERR(keyring_r); | 1466 | return PTR_ERR(keyring_r); |
| 1467 | 1467 | ||
| 1468 | ret = -ENOMEM; | ||
| 1469 | newwork = kmalloc(sizeof(struct task_work), GFP_KERNEL); | ||
| 1470 | if (!newwork) | ||
| 1471 | goto error_keyring; | ||
| 1472 | |||
| 1468 | /* our parent is going to need a new cred struct, a new tgcred struct | 1473 | /* our parent is going to need a new cred struct, a new tgcred struct |
| 1469 | * and new security data, so we allocate them here to prevent ENOMEM in | 1474 | * and new security data, so we allocate them here to prevent ENOMEM in |
| 1470 | * our parent */ | 1475 | * our parent */ |
| 1471 | ret = -ENOMEM; | ||
| 1472 | cred = cred_alloc_blank(); | 1476 | cred = cred_alloc_blank(); |
| 1473 | if (!cred) | 1477 | if (!cred) |
| 1474 | goto error_keyring; | 1478 | goto error_newwork; |
| 1475 | 1479 | ||
| 1476 | cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); | 1480 | cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); |
| 1477 | keyring_r = NULL; | 1481 | init_task_work(newwork, key_change_session_keyring, cred); |
| 1478 | 1482 | ||
| 1479 | me = current; | 1483 | me = current; |
| 1480 | rcu_read_lock(); | 1484 | rcu_read_lock(); |
| 1481 | write_lock_irq(&tasklist_lock); | 1485 | write_lock_irq(&tasklist_lock); |
| 1482 | 1486 | ||
| 1483 | parent = me->real_parent; | ||
| 1484 | ret = -EPERM; | 1487 | ret = -EPERM; |
| 1488 | oldwork = NULL; | ||
| 1489 | parent = me->real_parent; | ||
| 1485 | 1490 | ||
| 1486 | /* the parent mustn't be init and mustn't be a kernel thread */ | 1491 | /* the parent mustn't be init and mustn't be a kernel thread */ |
| 1487 | if (parent->pid <= 1 || !parent->mm) | 1492 | if (parent->pid <= 1 || !parent->mm) |
| 1488 | goto not_permitted; | 1493 | goto unlock; |
| 1489 | 1494 | ||
| 1490 | /* the parent must be single threaded */ | 1495 | /* the parent must be single threaded */ |
| 1491 | if (!thread_group_empty(parent)) | 1496 | if (!thread_group_empty(parent)) |
| 1492 | goto not_permitted; | 1497 | goto unlock; |
| 1493 | 1498 | ||
| 1494 | /* the parent and the child must have different session keyrings or | 1499 | /* the parent and the child must have different session keyrings or |
| 1495 | * there's no point */ | 1500 | * there's no point */ |
| 1496 | mycred = current_cred(); | 1501 | mycred = current_cred(); |
| 1497 | pcred = __task_cred(parent); | 1502 | pcred = __task_cred(parent); |
| 1498 | if (mycred == pcred || | 1503 | if (mycred == pcred || |
| 1499 | mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) | 1504 | mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) { |
| 1500 | goto already_same; | 1505 | ret = 0; |
| 1506 | goto unlock; | ||
| 1507 | } | ||
| 1501 | 1508 | ||
| 1502 | /* the parent must have the same effective ownership and mustn't be | 1509 | /* the parent must have the same effective ownership and mustn't be |
| 1503 | * SUID/SGID */ | 1510 | * SUID/SGID */ |
| @@ -1507,50 +1514,40 @@ long keyctl_session_to_parent(void) | |||
| 1507 | pcred->gid != mycred->egid || | 1514 | pcred->gid != mycred->egid || |
| 1508 | pcred->egid != mycred->egid || | 1515 | pcred->egid != mycred->egid || |
| 1509 | pcred->sgid != mycred->egid) | 1516 | pcred->sgid != mycred->egid) |
| 1510 | goto not_permitted; | 1517 | goto unlock; |
| 1511 | 1518 | ||
| 1512 | /* the keyrings must have the same UID */ | 1519 | /* the keyrings must have the same UID */ |
| 1513 | if ((pcred->tgcred->session_keyring && | 1520 | if ((pcred->tgcred->session_keyring && |
| 1514 | pcred->tgcred->session_keyring->uid != mycred->euid) || | 1521 | pcred->tgcred->session_keyring->uid != mycred->euid) || |
| 1515 | mycred->tgcred->session_keyring->uid != mycred->euid) | 1522 | mycred->tgcred->session_keyring->uid != mycred->euid) |
| 1516 | goto not_permitted; | 1523 | goto unlock; |
| 1517 | 1524 | ||
| 1518 | /* if there's an already pending keyring replacement, then we replace | 1525 | /* cancel an already pending keyring replacement */ |
| 1519 | * that */ | 1526 | oldwork = task_work_cancel(parent, key_change_session_keyring); |
| 1520 | oldcred = parent->replacement_session_keyring; | ||
| 1521 | 1527 | ||
| 1522 | /* the replacement session keyring is applied just prior to userspace | 1528 | /* the replacement session keyring is applied just prior to userspace |
| 1523 | * restarting */ | 1529 | * restarting */ |
| 1524 | parent->replacement_session_keyring = cred; | 1530 | ret = task_work_add(parent, newwork, true); |
| 1525 | cred = NULL; | 1531 | if (!ret) |
| 1526 | set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME); | 1532 | newwork = NULL; |
| 1527 | 1533 | unlock: | |
| 1528 | write_unlock_irq(&tasklist_lock); | ||
| 1529 | rcu_read_unlock(); | ||
| 1530 | if (oldcred) | ||
| 1531 | put_cred(oldcred); | ||
| 1532 | return 0; | ||
| 1533 | |||
| 1534 | already_same: | ||
| 1535 | ret = 0; | ||
| 1536 | not_permitted: | ||
| 1537 | write_unlock_irq(&tasklist_lock); | 1534 | write_unlock_irq(&tasklist_lock); |
| 1538 | rcu_read_unlock(); | 1535 | rcu_read_unlock(); |
| 1539 | put_cred(cred); | 1536 | if (oldwork) { |
| 1537 | put_cred(oldwork->data); | ||
| 1538 | kfree(oldwork); | ||
| 1539 | } | ||
| 1540 | if (newwork) { | ||
| 1541 | put_cred(newwork->data); | ||
| 1542 | kfree(newwork); | ||
| 1543 | } | ||
| 1540 | return ret; | 1544 | return ret; |
| 1541 | 1545 | ||
| 1546 | error_newwork: | ||
| 1547 | kfree(newwork); | ||
| 1542 | error_keyring: | 1548 | error_keyring: |
| 1543 | key_ref_put(keyring_r); | 1549 | key_ref_put(keyring_r); |
| 1544 | return ret; | 1550 | return ret; |
| 1545 | |||
| 1546 | #else /* !TIF_NOTIFY_RESUME */ | ||
| 1547 | /* | ||
| 1548 | * To be removed when TIF_NOTIFY_RESUME has been implemented on | ||
| 1549 | * m68k/xtensa | ||
| 1550 | */ | ||
| 1551 | #warning TIF_NOTIFY_RESUME not implemented | ||
| 1552 | return -EOPNOTSUPP; | ||
| 1553 | #endif /* !TIF_NOTIFY_RESUME */ | ||
| 1554 | } | 1551 | } |
| 1555 | 1552 | ||
| 1556 | /* | 1553 | /* |
diff --git a/security/keys/permission.c b/security/keys/permission.c index 57d96363d7f1..0b4d019e027d 100644 --- a/security/keys/permission.c +++ b/security/keys/permission.c | |||
| @@ -36,7 +36,7 @@ int key_task_permission(const key_ref_t key_ref, const struct cred *cred, | |||
| 36 | 36 | ||
| 37 | key = key_ref_to_ptr(key_ref); | 37 | key = key_ref_to_ptr(key_ref); |
| 38 | 38 | ||
| 39 | if (key->user->user_ns != cred->user->user_ns) | 39 | if (key->user->user_ns != cred->user_ns) |
| 40 | goto use_other_perms; | 40 | goto use_other_perms; |
| 41 | 41 | ||
| 42 | /* use the second 8-bits of permissions for keys the caller owns */ | 42 | /* use the second 8-bits of permissions for keys the caller owns */ |
| @@ -53,7 +53,8 @@ int key_task_permission(const key_ref_t key_ref, const struct cred *cred, | |||
| 53 | goto use_these_perms; | 53 | goto use_these_perms; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | ret = groups_search(cred->group_info, key->gid); | 56 | ret = groups_search(cred->group_info, |
| 57 | make_kgid(current_user_ns(), key->gid)); | ||
| 57 | if (ret) { | 58 | if (ret) { |
| 58 | kperm = key->perm >> 8; | 59 | kperm = key->perm >> 8; |
| 59 | goto use_these_perms; | 60 | goto use_these_perms; |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index e137fcd7042c..4ad54eea1ea4 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
| @@ -834,23 +834,17 @@ error: | |||
| 834 | * Replace a process's session keyring on behalf of one of its children when | 834 | * Replace a process's session keyring on behalf of one of its children when |
| 835 | * the target process is about to resume userspace execution. | 835 | * the target process is about to resume userspace execution. |
| 836 | */ | 836 | */ |
| 837 | void key_replace_session_keyring(void) | 837 | void key_change_session_keyring(struct task_work *twork) |
| 838 | { | 838 | { |
| 839 | const struct cred *old; | 839 | const struct cred *old = current_cred(); |
| 840 | struct cred *new; | 840 | struct cred *new = twork->data; |
| 841 | |||
| 842 | if (!current->replacement_session_keyring) | ||
| 843 | return; | ||
| 844 | 841 | ||
| 845 | write_lock_irq(&tasklist_lock); | 842 | kfree(twork); |
| 846 | new = current->replacement_session_keyring; | 843 | if (unlikely(current->flags & PF_EXITING)) { |
| 847 | current->replacement_session_keyring = NULL; | 844 | put_cred(new); |
| 848 | write_unlock_irq(&tasklist_lock); | ||
| 849 | |||
| 850 | if (!new) | ||
| 851 | return; | 845 | return; |
| 846 | } | ||
| 852 | 847 | ||
| 853 | old = current_cred(); | ||
| 854 | new-> uid = old-> uid; | 848 | new-> uid = old-> uid; |
| 855 | new-> euid = old-> euid; | 849 | new-> euid = old-> euid; |
| 856 | new-> suid = old-> suid; | 850 | new-> suid = old-> suid; |
| @@ -860,7 +854,7 @@ void key_replace_session_keyring(void) | |||
| 860 | new-> sgid = old-> sgid; | 854 | new-> sgid = old-> sgid; |
| 861 | new->fsgid = old->fsgid; | 855 | new->fsgid = old->fsgid; |
| 862 | new->user = get_uid(old->user); | 856 | new->user = get_uid(old->user); |
| 863 | new->user_ns = new->user->user_ns; | 857 | new->user_ns = get_user_ns(new->user_ns); |
| 864 | new->group_info = get_group_info(old->group_info); | 858 | new->group_info = get_group_info(old->group_info); |
| 865 | 859 | ||
| 866 | new->securebits = old->securebits; | 860 | new->securebits = old->securebits; |
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index cc3790315d2f..000e75017520 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
| @@ -93,16 +93,9 @@ static void umh_keys_cleanup(struct subprocess_info *info) | |||
| 93 | static int call_usermodehelper_keys(char *path, char **argv, char **envp, | 93 | static int call_usermodehelper_keys(char *path, char **argv, char **envp, |
| 94 | struct key *session_keyring, int wait) | 94 | struct key *session_keyring, int wait) |
| 95 | { | 95 | { |
| 96 | gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL; | 96 | return call_usermodehelper_fns(path, argv, envp, wait, |
| 97 | struct subprocess_info *info = | 97 | umh_keys_init, umh_keys_cleanup, |
| 98 | call_usermodehelper_setup(path, argv, envp, gfp_mask); | 98 | key_get(session_keyring)); |
| 99 | |||
| 100 | if (!info) | ||
| 101 | return -ENOMEM; | ||
| 102 | |||
| 103 | call_usermodehelper_setfns(info, umh_keys_init, umh_keys_cleanup, | ||
| 104 | key_get(session_keyring)); | ||
| 105 | return call_usermodehelper_exec(info, wait); | ||
| 106 | } | 99 | } |
| 107 | 100 | ||
| 108 | /* | 101 | /* |
diff --git a/security/security.c b/security/security.c index 5497a57fba01..3efc9b12aef4 100644 --- a/security/security.c +++ b/security/security.c | |||
| @@ -20,6 +20,9 @@ | |||
| 20 | #include <linux/ima.h> | 20 | #include <linux/ima.h> |
| 21 | #include <linux/evm.h> | 21 | #include <linux/evm.h> |
| 22 | #include <linux/fsnotify.h> | 22 | #include <linux/fsnotify.h> |
| 23 | #include <linux/mman.h> | ||
| 24 | #include <linux/mount.h> | ||
| 25 | #include <linux/personality.h> | ||
| 23 | #include <net/flow.h> | 26 | #include <net/flow.h> |
| 24 | 27 | ||
| 25 | #define MAX_LSM_EVM_XATTR 2 | 28 | #define MAX_LSM_EVM_XATTR 2 |
| @@ -657,18 +660,56 @@ int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
| 657 | return security_ops->file_ioctl(file, cmd, arg); | 660 | return security_ops->file_ioctl(file, cmd, arg); |
| 658 | } | 661 | } |
| 659 | 662 | ||
| 660 | int security_file_mmap(struct file *file, unsigned long reqprot, | 663 | static inline unsigned long mmap_prot(struct file *file, unsigned long prot) |
| 661 | unsigned long prot, unsigned long flags, | ||
| 662 | unsigned long addr, unsigned long addr_only) | ||
| 663 | { | 664 | { |
| 664 | int ret; | 665 | /* |
| 666 | * Does we have PROT_READ and does the application expect | ||
| 667 | * it to imply PROT_EXEC? If not, nothing to talk about... | ||
| 668 | */ | ||
| 669 | if ((prot & (PROT_READ | PROT_EXEC)) != PROT_READ) | ||
| 670 | return prot; | ||
| 671 | if (!(current->personality & READ_IMPLIES_EXEC)) | ||
| 672 | return prot; | ||
| 673 | /* | ||
| 674 | * if that's an anonymous mapping, let it. | ||
| 675 | */ | ||
| 676 | if (!file) | ||
| 677 | return prot | PROT_EXEC; | ||
| 678 | /* | ||
| 679 | * ditto if it's not on noexec mount, except that on !MMU we need | ||
| 680 | * BDI_CAP_EXEC_MMAP (== VM_MAYEXEC) in this case | ||
| 681 | */ | ||
| 682 | if (!(file->f_path.mnt->mnt_flags & MNT_NOEXEC)) { | ||
| 683 | #ifndef CONFIG_MMU | ||
| 684 | unsigned long caps = 0; | ||
| 685 | struct address_space *mapping = file->f_mapping; | ||
| 686 | if (mapping && mapping->backing_dev_info) | ||
| 687 | caps = mapping->backing_dev_info->capabilities; | ||
| 688 | if (!(caps & BDI_CAP_EXEC_MAP)) | ||
| 689 | return prot; | ||
| 690 | #endif | ||
| 691 | return prot | PROT_EXEC; | ||
| 692 | } | ||
| 693 | /* anything on noexec mount won't get PROT_EXEC */ | ||
| 694 | return prot; | ||
| 695 | } | ||
| 665 | 696 | ||
| 666 | ret = security_ops->file_mmap(file, reqprot, prot, flags, addr, addr_only); | 697 | int security_mmap_file(struct file *file, unsigned long prot, |
| 698 | unsigned long flags) | ||
| 699 | { | ||
| 700 | int ret; | ||
| 701 | ret = security_ops->mmap_file(file, prot, | ||
| 702 | mmap_prot(file, prot), flags); | ||
| 667 | if (ret) | 703 | if (ret) |
| 668 | return ret; | 704 | return ret; |
| 669 | return ima_file_mmap(file, prot); | 705 | return ima_file_mmap(file, prot); |
| 670 | } | 706 | } |
| 671 | 707 | ||
| 708 | int security_mmap_addr(unsigned long addr) | ||
| 709 | { | ||
| 710 | return security_ops->mmap_addr(addr); | ||
| 711 | } | ||
| 712 | |||
| 672 | int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, | 713 | int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, |
| 673 | unsigned long prot) | 714 | unsigned long prot) |
| 674 | { | 715 | { |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index fa2341b68331..372ec6502aa8 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -3083,9 +3083,7 @@ error: | |||
| 3083 | return rc; | 3083 | return rc; |
| 3084 | } | 3084 | } |
| 3085 | 3085 | ||
| 3086 | static int selinux_file_mmap(struct file *file, unsigned long reqprot, | 3086 | static int selinux_mmap_addr(unsigned long addr) |
| 3087 | unsigned long prot, unsigned long flags, | ||
| 3088 | unsigned long addr, unsigned long addr_only) | ||
| 3089 | { | 3087 | { |
| 3090 | int rc = 0; | 3088 | int rc = 0; |
| 3091 | u32 sid = current_sid(); | 3089 | u32 sid = current_sid(); |
| @@ -3104,10 +3102,12 @@ static int selinux_file_mmap(struct file *file, unsigned long reqprot, | |||
| 3104 | } | 3102 | } |
| 3105 | 3103 | ||
| 3106 | /* do DAC check on address space usage */ | 3104 | /* do DAC check on address space usage */ |
| 3107 | rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only); | 3105 | return cap_mmap_addr(addr); |
| 3108 | if (rc || addr_only) | 3106 | } |
| 3109 | return rc; | ||
| 3110 | 3107 | ||
| 3108 | static int selinux_mmap_file(struct file *file, unsigned long reqprot, | ||
| 3109 | unsigned long prot, unsigned long flags) | ||
| 3110 | { | ||
| 3111 | if (selinux_checkreqprot) | 3111 | if (selinux_checkreqprot) |
| 3112 | prot = reqprot; | 3112 | prot = reqprot; |
| 3113 | 3113 | ||
| @@ -5570,7 +5570,8 @@ static struct security_operations selinux_ops = { | |||
| 5570 | .file_alloc_security = selinux_file_alloc_security, | 5570 | .file_alloc_security = selinux_file_alloc_security, |
| 5571 | .file_free_security = selinux_file_free_security, | 5571 | .file_free_security = selinux_file_free_security, |
| 5572 | .file_ioctl = selinux_file_ioctl, | 5572 | .file_ioctl = selinux_file_ioctl, |
| 5573 | .file_mmap = selinux_file_mmap, | 5573 | .mmap_file = selinux_mmap_file, |
| 5574 | .mmap_addr = selinux_mmap_addr, | ||
| 5574 | .file_mprotect = selinux_file_mprotect, | 5575 | .file_mprotect = selinux_file_mprotect, |
| 5575 | .file_lock = selinux_file_lock, | 5576 | .file_lock = selinux_file_lock, |
| 5576 | .file_fcntl = selinux_file_fcntl, | 5577 | .file_fcntl = selinux_file_fcntl, |
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 0920ea3bf599..d309e7f472d8 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c | |||
| @@ -14,7 +14,6 @@ | |||
| 14 | #include <linux/netlink.h> | 14 | #include <linux/netlink.h> |
| 15 | #include <linux/rtnetlink.h> | 15 | #include <linux/rtnetlink.h> |
| 16 | #include <linux/if.h> | 16 | #include <linux/if.h> |
| 17 | #include <linux/netfilter_ipv4/ip_queue.h> | ||
| 18 | #include <linux/inet_diag.h> | 17 | #include <linux/inet_diag.h> |
| 19 | #include <linux/xfrm.h> | 18 | #include <linux/xfrm.h> |
| 20 | #include <linux/audit.h> | 19 | #include <linux/audit.h> |
| @@ -70,12 +69,6 @@ static struct nlmsg_perm nlmsg_route_perms[] = | |||
| 70 | { RTM_SETDCB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, | 69 | { RTM_SETDCB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, |
| 71 | }; | 70 | }; |
| 72 | 71 | ||
| 73 | static struct nlmsg_perm nlmsg_firewall_perms[] = | ||
| 74 | { | ||
| 75 | { IPQM_MODE, NETLINK_FIREWALL_SOCKET__NLMSG_WRITE }, | ||
| 76 | { IPQM_VERDICT, NETLINK_FIREWALL_SOCKET__NLMSG_WRITE }, | ||
| 77 | }; | ||
| 78 | |||
| 79 | static struct nlmsg_perm nlmsg_tcpdiag_perms[] = | 72 | static struct nlmsg_perm nlmsg_tcpdiag_perms[] = |
| 80 | { | 73 | { |
| 81 | { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, | 74 | { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, |
| @@ -145,12 +138,6 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm) | |||
| 145 | sizeof(nlmsg_route_perms)); | 138 | sizeof(nlmsg_route_perms)); |
| 146 | break; | 139 | break; |
| 147 | 140 | ||
| 148 | case SECCLASS_NETLINK_FIREWALL_SOCKET: | ||
| 149 | case SECCLASS_NETLINK_IP6FW_SOCKET: | ||
| 150 | err = nlmsg_perm(nlmsg_type, perm, nlmsg_firewall_perms, | ||
| 151 | sizeof(nlmsg_firewall_perms)); | ||
| 152 | break; | ||
| 153 | |||
| 154 | case SECCLASS_NETLINK_TCPDIAG_SOCKET: | 141 | case SECCLASS_NETLINK_TCPDIAG_SOCKET: |
| 155 | err = nlmsg_perm(nlmsg_type, perm, nlmsg_tcpdiag_perms, | 142 | err = nlmsg_perm(nlmsg_type, perm, nlmsg_tcpdiag_perms, |
| 156 | sizeof(nlmsg_tcpdiag_perms)); | 143 | sizeof(nlmsg_tcpdiag_perms)); |
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 4e93f9ef970b..3ad290251288 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
| @@ -1259,12 +1259,8 @@ static int sel_make_bools(void) | |||
| 1259 | if (!inode) | 1259 | if (!inode) |
| 1260 | goto out; | 1260 | goto out; |
| 1261 | 1261 | ||
| 1262 | ret = -EINVAL; | ||
| 1263 | len = snprintf(page, PAGE_SIZE, "/%s/%s", BOOL_DIR_NAME, names[i]); | ||
| 1264 | if (len < 0) | ||
| 1265 | goto out; | ||
| 1266 | |||
| 1267 | ret = -ENAMETOOLONG; | 1262 | ret = -ENAMETOOLONG; |
| 1263 | len = snprintf(page, PAGE_SIZE, "/%s/%s", BOOL_DIR_NAME, names[i]); | ||
| 1268 | if (len >= PAGE_SIZE) | 1264 | if (len >= PAGE_SIZE) |
| 1269 | goto out; | 1265 | goto out; |
| 1270 | 1266 | ||
| @@ -1557,19 +1553,10 @@ static inline u32 sel_ino_to_perm(unsigned long ino) | |||
| 1557 | static ssize_t sel_read_class(struct file *file, char __user *buf, | 1553 | static ssize_t sel_read_class(struct file *file, char __user *buf, |
| 1558 | size_t count, loff_t *ppos) | 1554 | size_t count, loff_t *ppos) |
| 1559 | { | 1555 | { |
| 1560 | ssize_t rc, len; | ||
| 1561 | char *page; | ||
| 1562 | unsigned long ino = file->f_path.dentry->d_inode->i_ino; | 1556 | unsigned long ino = file->f_path.dentry->d_inode->i_ino; |
| 1563 | 1557 | char res[TMPBUFLEN]; | |
| 1564 | page = (char *)__get_free_page(GFP_KERNEL); | 1558 | ssize_t len = snprintf(res, sizeof(res), "%d", sel_ino_to_class(ino)); |
| 1565 | if (!page) | 1559 | return simple_read_from_buffer(buf, count, ppos, res, len); |
| 1566 | return -ENOMEM; | ||
| 1567 | |||
| 1568 | len = snprintf(page, PAGE_SIZE, "%d", sel_ino_to_class(ino)); | ||
| 1569 | rc = simple_read_from_buffer(buf, count, ppos, page, len); | ||
| 1570 | free_page((unsigned long)page); | ||
| 1571 | |||
| 1572 | return rc; | ||
| 1573 | } | 1560 | } |
| 1574 | 1561 | ||
| 1575 | static const struct file_operations sel_class_ops = { | 1562 | static const struct file_operations sel_class_ops = { |
| @@ -1580,19 +1567,10 @@ static const struct file_operations sel_class_ops = { | |||
| 1580 | static ssize_t sel_read_perm(struct file *file, char __user *buf, | 1567 | static ssize_t sel_read_perm(struct file *file, char __user *buf, |
| 1581 | size_t count, loff_t *ppos) | 1568 | size_t count, loff_t *ppos) |
| 1582 | { | 1569 | { |
| 1583 | ssize_t rc, len; | ||
| 1584 | char *page; | ||
| 1585 | unsigned long ino = file->f_path.dentry->d_inode->i_ino; | 1570 | unsigned long ino = file->f_path.dentry->d_inode->i_ino; |
| 1586 | 1571 | char res[TMPBUFLEN]; | |
| 1587 | page = (char *)__get_free_page(GFP_KERNEL); | 1572 | ssize_t len = snprintf(res, sizeof(res), "%d", sel_ino_to_perm(ino)); |
| 1588 | if (!page) | 1573 | return simple_read_from_buffer(buf, count, ppos, res, len); |
| 1589 | return -ENOMEM; | ||
| 1590 | |||
| 1591 | len = snprintf(page, PAGE_SIZE, "%d", sel_ino_to_perm(ino)); | ||
| 1592 | rc = simple_read_from_buffer(buf, count, ppos, page, len); | ||
| 1593 | free_page((unsigned long)page); | ||
| 1594 | |||
| 1595 | return rc; | ||
| 1596 | } | 1574 | } |
| 1597 | 1575 | ||
| 1598 | static const struct file_operations sel_perm_ops = { | 1576 | static const struct file_operations sel_perm_ops = { |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index d583c0545808..ee0bb5735f35 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
| @@ -1171,7 +1171,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd, | |||
| 1171 | } | 1171 | } |
| 1172 | 1172 | ||
| 1173 | /** | 1173 | /** |
| 1174 | * smack_file_mmap : | 1174 | * smack_mmap_file : |
| 1175 | * Check permissions for a mmap operation. The @file may be NULL, e.g. | 1175 | * Check permissions for a mmap operation. The @file may be NULL, e.g. |
| 1176 | * if mapping anonymous memory. | 1176 | * if mapping anonymous memory. |
| 1177 | * @file contains the file structure for file to map (may be NULL). | 1177 | * @file contains the file structure for file to map (may be NULL). |
| @@ -1180,10 +1180,9 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd, | |||
| 1180 | * @flags contains the operational flags. | 1180 | * @flags contains the operational flags. |
| 1181 | * Return 0 if permission is granted. | 1181 | * Return 0 if permission is granted. |
| 1182 | */ | 1182 | */ |
| 1183 | static int smack_file_mmap(struct file *file, | 1183 | static int smack_mmap_file(struct file *file, |
| 1184 | unsigned long reqprot, unsigned long prot, | 1184 | unsigned long reqprot, unsigned long prot, |
| 1185 | unsigned long flags, unsigned long addr, | 1185 | unsigned long flags) |
| 1186 | unsigned long addr_only) | ||
| 1187 | { | 1186 | { |
| 1188 | struct smack_known *skp; | 1187 | struct smack_known *skp; |
| 1189 | struct smack_rule *srp; | 1188 | struct smack_rule *srp; |
| @@ -1198,11 +1197,6 @@ static int smack_file_mmap(struct file *file, | |||
| 1198 | int tmay; | 1197 | int tmay; |
| 1199 | int rc; | 1198 | int rc; |
| 1200 | 1199 | ||
| 1201 | /* do DAC check on address space usage */ | ||
| 1202 | rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only); | ||
| 1203 | if (rc || addr_only) | ||
| 1204 | return rc; | ||
| 1205 | |||
| 1206 | if (file == NULL || file->f_dentry == NULL) | 1200 | if (file == NULL || file->f_dentry == NULL) |
| 1207 | return 0; | 1201 | return 0; |
| 1208 | 1202 | ||
| @@ -3482,7 +3476,8 @@ struct security_operations smack_ops = { | |||
| 3482 | .file_ioctl = smack_file_ioctl, | 3476 | .file_ioctl = smack_file_ioctl, |
| 3483 | .file_lock = smack_file_lock, | 3477 | .file_lock = smack_file_lock, |
| 3484 | .file_fcntl = smack_file_fcntl, | 3478 | .file_fcntl = smack_file_fcntl, |
| 3485 | .file_mmap = smack_file_mmap, | 3479 | .mmap_file = smack_mmap_file, |
| 3480 | .mmap_addr = cap_mmap_addr, | ||
| 3486 | .file_set_fowner = smack_file_set_fowner, | 3481 | .file_set_fowner = smack_file_set_fowner, |
| 3487 | .file_send_sigiotask = smack_file_send_sigiotask, | 3482 | .file_send_sigiotask = smack_file_send_sigiotask, |
| 3488 | .file_receive = smack_file_receive, | 3483 | .file_receive = smack_file_receive, |
