diff options
Diffstat (limited to 'security')
38 files changed, 361 insertions, 205 deletions
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index d0594446ae3f..17a601c67b62 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -758,7 +758,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) file_inode(bprm->file)->i_mode }; - if (bprm->cred_prepared) + if (bprm->called_set_creds) return 0; ctx = cred_ctx(bprm->cred); @@ -807,7 +807,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) aa_label_printk(new, GFP_ATOMIC); dbg_printk("\n"); } - bprm->unsafe |= AA_SECURE_X_NEEDED; + bprm->secureexec = 1; } if (label->proxy != new->proxy) { @@ -843,23 +843,6 @@ audit: goto done; } -/** - * apparmor_bprm_secureexec - determine if secureexec is needed - * @bprm: binprm for exec (NOT NULL) - * - * Returns: %1 if secureexec is needed else %0 - */ -int apparmor_bprm_secureexec(struct linux_binprm *bprm) -{ - /* the decision to use secure exec is computed in set_creds - * and stored in bprm->unsafe. - */ - if (bprm->unsafe & AA_SECURE_X_NEEDED) - return 1; - - return 0; -} - /* * Functions for self directed profile change */ diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h index bab5810b6e9a..24c5976d6143 100644 --- a/security/apparmor/include/domain.h +++ b/security/apparmor/include/domain.h @@ -30,7 +30,6 @@ struct aa_domain { #define AA_CHANGE_STACK 8 int apparmor_bprm_set_creds(struct linux_binprm *bprm); -int apparmor_bprm_secureexec(struct linux_binprm *bprm); void aa_free_domain_entries(struct aa_domain *domain); int aa_change_hat(const char *hats[], int count, u64 token, int flags); diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h index 001e40073ff9..4c2c8ac8842f 100644 --- a/security/apparmor/include/file.h +++ b/security/apparmor/include/file.h @@ -101,9 +101,6 @@ static inline struct aa_label *aa_get_file_label(struct aa_file_ctx *ctx) #define AA_X_INHERIT 0x4000 #define AA_X_UNCONFINED 0x8000 -/* AA_SECURE_X_NEEDED - is passed in the bprm->unsafe field */ -#define AA_SECURE_X_NEEDED 0x8000 - /* need to make conditional which ones are being set */ struct path_cond { kuid_t uid; diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 867bcd154c7e..7a82c0f61452 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -694,7 +694,6 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(bprm_set_creds, apparmor_bprm_set_creds), LSM_HOOK_INIT(bprm_committing_creds, apparmor_bprm_committing_creds), LSM_HOOK_INIT(bprm_committed_creds, apparmor_bprm_committed_creds), - LSM_HOOK_INIT(bprm_secureexec, apparmor_bprm_secureexec), LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit), }; diff --git a/security/commoncap.c b/security/commoncap.c index 7abebd782d5e..6bf72b175b49 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -82,8 +82,11 @@ int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, if (ns == cred->user_ns) return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM; - /* Have we tried all of the parent namespaces? */ - if (ns == &init_user_ns) + /* + * If we're already at a lower level than we're looking for, + * we're done searching. + */ + if (ns->level <= cred->user_ns->level) return -EPERM; /* @@ -285,15 +288,6 @@ int cap_capset(struct cred *new, return 0; } -/* - * Clear proposed capability sets for execve(). - */ -static inline void bprm_clear_caps(struct linux_binprm *bprm) -{ - cap_clear(bprm->cred->cap_permitted); - bprm->cap_effective = false; -} - /** * cap_inode_need_killpriv - Determine if inode change affects privileges * @dentry: The inode/dentry in being changed with change marked ATTR_KILL_PRIV @@ -332,6 +326,209 @@ int cap_inode_killpriv(struct dentry *dentry) return error; } +static bool rootid_owns_currentns(kuid_t kroot) +{ + struct user_namespace *ns; + + if (!uid_valid(kroot)) + return false; + + for (ns = current_user_ns(); ; ns = ns->parent) { + if (from_kuid(ns, kroot) == 0) + return true; + if (ns == &init_user_ns) + break; + } + + return false; +} + +static __u32 sansflags(__u32 m) +{ + return m & ~VFS_CAP_FLAGS_EFFECTIVE; +} + +static bool is_v2header(size_t size, __le32 magic) +{ + __u32 m = le32_to_cpu(magic); + if (size != XATTR_CAPS_SZ_2) + return false; + return sansflags(m) == VFS_CAP_REVISION_2; +} + +static bool is_v3header(size_t size, __le32 magic) +{ + __u32 m = le32_to_cpu(magic); + + if (size != XATTR_CAPS_SZ_3) + return false; + return sansflags(m) == VFS_CAP_REVISION_3; +} + +/* + * getsecurity: We are called for security.* before any attempt to read the + * xattr from the inode itself. + * + * This gives us a chance to read the on-disk value and convert it. If we + * return -EOPNOTSUPP, then vfs_getxattr() will call the i_op handler. + * + * Note we are not called by vfs_getxattr_alloc(), but that is only called + * by the integrity subsystem, which really wants the unconverted values - + * so that's good. + */ +int cap_inode_getsecurity(struct inode *inode, const char *name, void **buffer, + bool alloc) +{ + int size, ret; + kuid_t kroot; + uid_t root, mappedroot; + char *tmpbuf = NULL; + struct vfs_cap_data *cap; + struct vfs_ns_cap_data *nscap; + struct dentry *dentry; + struct user_namespace *fs_ns; + + if (strcmp(name, "capability") != 0) + return -EOPNOTSUPP; + + dentry = d_find_alias(inode); + if (!dentry) + return -EINVAL; + + size = sizeof(struct vfs_ns_cap_data); + ret = (int) vfs_getxattr_alloc(dentry, XATTR_NAME_CAPS, + &tmpbuf, size, GFP_NOFS); + dput(dentry); + + if (ret < 0) + return ret; + + fs_ns = inode->i_sb->s_user_ns; + cap = (struct vfs_cap_data *) tmpbuf; + if (is_v2header((size_t) ret, cap->magic_etc)) { + /* If this is sizeof(vfs_cap_data) then we're ok with the + * on-disk value, so return that. */ + if (alloc) + *buffer = tmpbuf; + else + kfree(tmpbuf); + return ret; + } else if (!is_v3header((size_t) ret, cap->magic_etc)) { + kfree(tmpbuf); + return -EINVAL; + } + + nscap = (struct vfs_ns_cap_data *) tmpbuf; + root = le32_to_cpu(nscap->rootid); + kroot = make_kuid(fs_ns, root); + + /* If the root kuid maps to a valid uid in current ns, then return + * this as a nscap. */ + mappedroot = from_kuid(current_user_ns(), kroot); + if (mappedroot != (uid_t)-1 && mappedroot != (uid_t)0) { + if (alloc) { + *buffer = tmpbuf; + nscap->rootid = cpu_to_le32(mappedroot); + } else + kfree(tmpbuf); + return size; + } + + if (!rootid_owns_currentns(kroot)) { + kfree(tmpbuf); + return -EOPNOTSUPP; + } + + /* This comes from a parent namespace. Return as a v2 capability */ + size = sizeof(struct vfs_cap_data); + if (alloc) { + *buffer = kmalloc(size, GFP_ATOMIC); + if (*buffer) { + struct vfs_cap_data *cap = *buffer; + __le32 nsmagic, magic; + magic = VFS_CAP_REVISION_2; + nsmagic = le32_to_cpu(nscap->magic_etc); + if (nsmagic & VFS_CAP_FLAGS_EFFECTIVE) + magic |= VFS_CAP_FLAGS_EFFECTIVE; + memcpy(&cap->data, &nscap->data, sizeof(__le32) * 2 * VFS_CAP_U32); + cap->magic_etc = cpu_to_le32(magic); + } + } + kfree(tmpbuf); + return size; +} + +static kuid_t rootid_from_xattr(const void *value, size_t size, + struct user_namespace *task_ns) +{ + const struct vfs_ns_cap_data *nscap = value; + uid_t rootid = 0; + + if (size == XATTR_CAPS_SZ_3) + rootid = le32_to_cpu(nscap->rootid); + + return make_kuid(task_ns, rootid); +} + +static bool validheader(size_t size, __le32 magic) +{ + return is_v2header(size, magic) || is_v3header(size, magic); +} + +/* + * User requested a write of security.capability. If needed, update the + * xattr to change from v2 to v3, or to fixup the v3 rootid. + * + * If all is ok, we return the new size, on error return < 0. + */ +int cap_convert_nscap(struct dentry *dentry, void **ivalue, size_t size) +{ + struct vfs_ns_cap_data *nscap; + uid_t nsrootid; + const struct vfs_cap_data *cap = *ivalue; + __u32 magic, nsmagic; + struct inode *inode = d_backing_inode(dentry); + struct user_namespace *task_ns = current_user_ns(), + *fs_ns = inode->i_sb->s_user_ns; + kuid_t rootid; + size_t newsize; + + if (!*ivalue) + return -EINVAL; + if (!validheader(size, cap->magic_etc)) + return -EINVAL; + if (!capable_wrt_inode_uidgid(inode, CAP_SETFCAP)) + return -EPERM; + if (size == XATTR_CAPS_SZ_2) + if (ns_capable(inode->i_sb->s_user_ns, CAP_SETFCAP)) + /* user is privileged, just write the v2 */ + return size; + + rootid = rootid_from_xattr(*ivalue, size, task_ns); + if (!uid_valid(rootid)) + return -EINVAL; + + nsrootid = from_kuid(fs_ns, rootid); + if (nsrootid == -1) + return -EINVAL; + + newsize = sizeof(struct vfs_ns_cap_data); + nscap = kmalloc(newsize, GFP_ATOMIC); + if (!nscap) + return -ENOMEM; + nscap->rootid = cpu_to_le32(nsrootid); + nsmagic = VFS_CAP_REVISION_3; + magic = le32_to_cpu(cap->magic_etc); + if (magic & VFS_CAP_FLAGS_EFFECTIVE) + nsmagic |= VFS_CAP_FLAGS_EFFECTIVE; + nscap->magic_etc = cpu_to_le32(nsmagic); + memcpy(&nscap->data, &cap->data, sizeof(__le32) * 2 * VFS_CAP_U32); + + kvfree(*ivalue); + *ivalue = nscap; + return newsize; +} + /* * Calculate the new process capability sets from the capability sets attached * to a file. @@ -385,7 +582,10 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data __u32 magic_etc; unsigned tocopy, i; int size; - struct vfs_cap_data caps; + struct vfs_ns_cap_data data, *nscaps = &data; + struct vfs_cap_data *caps = (struct vfs_cap_data *) &data; + kuid_t rootkuid; + struct user_namespace *fs_ns = inode->i_sb->s_user_ns; memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data)); @@ -393,18 +593,20 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data return -ENODATA; size = __vfs_getxattr((struct dentry *)dentry, inode, - XATTR_NAME_CAPS, &caps, XATTR_CAPS_SZ); + XATTR_NAME_CAPS, &data, XATTR_CAPS_SZ); if (size == -ENODATA || size == -EOPNOTSUPP) /* no data, that's ok */ return -ENODATA; + if (size < 0) return size; if (size < sizeof(magic_etc)) return -EINVAL; - cpu_caps->magic_etc = magic_etc = le32_to_cpu(caps.magic_etc); + cpu_caps->magic_etc = magic_etc = le32_to_cpu(caps->magic_etc); + rootkuid = make_kuid(fs_ns, 0); switch (magic_etc & VFS_CAP_REVISION_MASK) { case VFS_CAP_REVISION_1: if (size != XATTR_CAPS_SZ_1) @@ -416,15 +618,27 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data return -EINVAL; tocopy = VFS_CAP_U32_2; break; + case VFS_CAP_REVISION_3: + if (size != XATTR_CAPS_SZ_3) + return -EINVAL; + tocopy = VFS_CAP_U32_3; + rootkuid = make_kuid(fs_ns, le32_to_cpu(nscaps->rootid)); + break; + default: return -EINVAL; } + /* Limit the caps to the mounter of the filesystem + * or the more limited uid specified in the xattr. + */ + if (!rootid_owns_currentns(rootkuid)) + return -ENODATA; CAP_FOR_EACH_U32(i) { if (i >= tocopy) break; - cpu_caps->permitted.cap[i] = le32_to_cpu(caps.data[i].permitted); - cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable); + cpu_caps->permitted.cap[i] = le32_to_cpu(caps->data[i].permitted); + cpu_caps->inheritable.cap[i] = le32_to_cpu(caps->data[i].inheritable); } cpu_caps->permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; @@ -443,7 +657,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c int rc = 0; struct cpu_vfs_cap_data vcaps; - bprm_clear_caps(bprm); + cap_clear(bprm->cred->cap_permitted); if (!file_caps_enabled) return 0; @@ -462,8 +676,8 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c rc = get_vfs_caps_from_disk(bprm->file->f_path.dentry, &vcaps); if (rc < 0) { if (rc == -EINVAL) - printk(KERN_NOTICE "%s: get_vfs_caps_from_disk returned %d for %s\n", - __func__, rc, bprm->filename); + printk(KERN_NOTICE "Invalid argument reading file caps for %s\n", + bprm->filename); else if (rc == -ENODATA) rc = 0; goto out; @@ -476,7 +690,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c out: if (rc) - bprm_clear_caps(bprm); + cap_clear(bprm->cred->cap_permitted); return rc; } @@ -585,8 +799,6 @@ skip: if (WARN_ON(!cap_ambient_invariant_ok(new))) return -EPERM; - bprm->cap_effective = effective; - /* * Audit candidate if current->cap_effective is set * @@ -614,33 +826,17 @@ skip: if (WARN_ON(!cap_ambient_invariant_ok(new))) return -EPERM; - return 0; -} - -/** - * cap_bprm_secureexec - Determine whether a secure execution is required - * @bprm: The execution parameters - * - * Determine whether a secure execution is required, return 1 if it is, and 0 - * if it is not. - * - * The credentials have been committed by this point, and so are no longer - * available through @bprm->cred. - */ -int cap_bprm_secureexec(struct linux_binprm *bprm) -{ - const struct cred *cred = current_cred(); - kuid_t root_uid = make_kuid(cred->user_ns, 0); - - if (!uid_eq(cred->uid, root_uid)) { - if (bprm->cap_effective) - return 1; - if (!cap_issubset(cred->cap_permitted, cred->cap_ambient)) - return 1; + /* Check for privilege-elevated exec. */ + bprm->cap_elevated = 0; + if (is_setid) { + bprm->cap_elevated = 1; + } else if (!uid_eq(new->uid, root_uid)) { + if (effective || + !cap_issubset(new->cap_permitted, new->cap_ambient)) + bprm->cap_elevated = 1; } - return (!uid_eq(cred->euid, cred->uid) || - !gid_eq(cred->egid, cred->gid)); + return 0; } /** @@ -660,15 +856,19 @@ int cap_bprm_secureexec(struct linux_binprm *bprm) int cap_inode_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - if (!strcmp(name, XATTR_NAME_CAPS)) { - if (!capable(CAP_SETFCAP)) - return -EPERM; + /* Ignore non-security xattrs */ + if (strncmp(name, XATTR_SECURITY_PREFIX, + sizeof(XATTR_SECURITY_PREFIX) - 1) != 0) return 0; - } - if (!strncmp(name, XATTR_SECURITY_PREFIX, - sizeof(XATTR_SECURITY_PREFIX) - 1) && - !capable(CAP_SYS_ADMIN)) + /* + * For XATTR_NAME_CAPS the check will be done in + * cap_convert_nscap(), called by setxattr() + */ + if (strcmp(name, XATTR_NAME_CAPS) == 0) + return 0; + + if (!capable(CAP_SYS_ADMIN)) return -EPERM; return 0; } @@ -686,15 +886,22 @@ int cap_inode_setxattr(struct dentry *dentry, const char *name, */ int cap_inode_removexattr(struct dentry *dentry, const char *name) { - if (!strcmp(name, XATTR_NAME_CAPS)) { - if (!capable(CAP_SETFCAP)) + /* Ignore non-security xattrs */ + if (strncmp(name, XATTR_SECURITY_PREFIX, + sizeof(XATTR_SECURITY_PREFIX) - 1) != 0) + return 0; + + if (strcmp(name, XATTR_NAME_CAPS) == 0) { + /* security.capability gets namespaced */ + struct inode *inode = d_backing_inode(dentry); + if (!inode) + return -EINVAL; + if (!capable_wrt_inode_uidgid(inode, CAP_SETFCAP)) return -EPERM; return 0; } - if (!strncmp(name, XATTR_SECURITY_PREFIX, - sizeof(XATTR_SECURITY_PREFIX) - 1) && - !capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; return 0; } @@ -1079,9 +1286,9 @@ struct security_hook_list capability_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(capget, cap_capget), LSM_HOOK_INIT(capset, cap_capset), LSM_HOOK_INIT(bprm_set_creds, cap_bprm_set_creds), - LSM_HOOK_INIT(bprm_secureexec, cap_bprm_secureexec), LSM_HOOK_INIT(inode_need_killpriv, cap_inode_need_killpriv), LSM_HOOK_INIT(inode_killpriv, cap_inode_killpriv), + LSM_HOOK_INIT(inode_getsecurity, cap_inode_getsecurity), LSM_HOOK_INIT(mmap_addr, cap_mmap_addr), LSM_HOOK_INIT(mmap_file, cap_mmap_file), LSM_HOOK_INIT(task_fix_setuid, cap_task_fix_setuid), diff --git a/security/keys/internal.h b/security/keys/internal.h index 91bc6214ae57..1c02c6547038 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -198,7 +198,7 @@ struct request_key_auth { void *callout_info; size_t callout_len; pid_t pid; -}; +} __randomize_layout; extern struct key_type key_type_request_key_auth; extern struct key *request_key_auth_new(struct key *target, diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 28d4c3a528ab..67703dbe29ea 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -2,7 +2,7 @@ * common LSM auditing functions * * Based on code written for SELinux by : - * Stephen Smalley, <sds@epoch.ncsc.mil> + * Stephen Smalley, <sds@tycho.nsa.gov> * James Morris <jmorris@redhat.com> * Author : Etienne Basset, <etienne.basset@ensta.org> * diff --git a/security/security.c b/security/security.c index 30132378d103..4bf0f571b4ef 100644 --- a/security/security.c +++ b/security/security.c @@ -351,11 +351,6 @@ void security_bprm_committed_creds(struct linux_binprm *bprm) call_void_hook(bprm_committed_creds, bprm); } -int security_bprm_secureexec(struct linux_binprm *bprm) -{ - return call_int_hook(bprm_secureexec, 0, bprm); -} - int security_sb_alloc(struct super_block *sb) { return call_int_hook(sb_alloc_security, 0, sb); @@ -979,11 +974,6 @@ int security_file_open(struct file *file, const struct cred *cred) return fsnotify_perm(file, MAY_OPEN); } -int security_task_create(unsigned long clone_flags) -{ - return call_int_hook(task_create, 0, clone_flags); -} - int security_task_alloc(struct task_struct *task, unsigned long clone_flags) { return call_int_hook(task_alloc, 0, task, clone_flags); diff --git a/security/selinux/avc.c b/security/selinux/avc.c index e60c79de13e1..2380b8d72cec 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -1,7 +1,7 @@ /* * Implementation of the kernel access vector cache (AVC). * - * Authors: Stephen Smalley, <sds@epoch.ncsc.mil> + * Authors: Stephen Smalley, <sds@tycho.nsa.gov> * James Morris <jmorris@redhat.com> * * Update: KaiGai, Kohei <kaigai@ak.jp.nec.com> @@ -197,8 +197,6 @@ void __init avc_init(void) avc_xperms_data_cachep = kmem_cache_create("avc_xperms_data", sizeof(struct extended_perms_data), 0, SLAB_PANIC, NULL); - - audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED\n"); } int avc_get_hash_stats(char *page) @@ -348,27 +346,26 @@ static struct avc_xperms_decision_node struct avc_xperms_decision_node *xpd_node; struct extended_perms_decision *xpd; - xpd_node = kmem_cache_zalloc(avc_xperms_decision_cachep, - GFP_ATOMIC | __GFP_NOMEMALLOC); + xpd_node = kmem_cache_zalloc(avc_xperms_decision_cachep, GFP_NOWAIT); if (!xpd_node) return NULL; xpd = &xpd_node->xpd; if (which & XPERMS_ALLOWED) { xpd->allowed = kmem_cache_zalloc(avc_xperms_data_cachep, - GFP_ATOMIC | __GFP_NOMEMALLOC); + GFP_NOWAIT); if (!xpd->allowed) goto error; } if (which & XPERMS_AUDITALLOW) { xpd->auditallow = kmem_cache_zalloc(avc_xperms_data_cachep, - GFP_ATOMIC | __GFP_NOMEMALLOC); + GFP_NOWAIT); if (!xpd->auditallow) goto error; } if (which & XPERMS_DONTAUDIT) { xpd->dontaudit = kmem_cache_zalloc(avc_xperms_data_cachep, - GFP_ATOMIC | __GFP_NOMEMALLOC); + GFP_NOWAIT); if (!xpd->dontaudit) goto error; } @@ -396,8 +393,7 @@ static struct avc_xperms_node *avc_xperms_alloc(void) { struct avc_xperms_node *xp_node; - xp_node = kmem_cache_zalloc(avc_xperms_cachep, - GFP_ATOMIC|__GFP_NOMEMALLOC); + xp_node = kmem_cache_zalloc(avc_xperms_cachep, GFP_NOWAIT); if (!xp_node) return xp_node; INIT_LIST_HEAD(&xp_node->xpd_head); @@ -550,7 +546,7 @@ static struct avc_node *avc_alloc_node(void) { struct avc_node *node; - node = kmem_cache_zalloc(avc_node_cachep, GFP_ATOMIC|__GFP_NOMEMALLOC); + node = kmem_cache_zalloc(avc_node_cachep, GFP_NOWAIT); if (!node) goto out; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 33fd061305c4..f5d304736852 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3,7 +3,7 @@ * * This file contains the SELinux hook function implementations. * - * Authors: Stephen Smalley, <sds@epoch.ncsc.mil> + * Authors: Stephen Smalley, <sds@tycho.nsa.gov> * Chris Vance, <cvance@nai.com> * Wayne Salamon, <wsalamon@nai.com> * James Morris <jmorris@redhat.com> @@ -815,7 +815,9 @@ static int selinux_set_mnt_opts(struct super_block *sb, if (!strcmp(sb->s_type->name, "debugfs") || !strcmp(sb->s_type->name, "tracefs") || !strcmp(sb->s_type->name, "sysfs") || - !strcmp(sb->s_type->name, "pstore")) + !strcmp(sb->s_type->name, "pstore") || + !strcmp(sb->s_type->name, "cgroup") || + !strcmp(sb->s_type->name, "cgroup2")) sbsec->flags |= SE_SBGENFS; if (!sbsec->behavior) { @@ -1303,6 +1305,7 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc case SOCK_SEQPACKET: return SECCLASS_UNIX_STREAM_SOCKET; case SOCK_DGRAM: + case SOCK_RAW: return SECCLASS_UNIX_DGRAM_SOCKET; } break; @@ -2317,6 +2320,7 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm, int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS); int nosuid = !mnt_may_suid(bprm->file->f_path.mnt); int rc; + u32 av; if (!nnp && !nosuid) return 0; /* neither NNP nor nosuid */ @@ -2325,24 +2329,40 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm, return 0; /* No change in credentials */ /* - * The only transitions we permit under NNP or nosuid - * are transitions to bounded SIDs, i.e. SIDs that are - * guaranteed to only be allowed a subset of the permissions - * of the current SID. + * If the policy enables the nnp_nosuid_transition policy capability, + * then we permit transitions under NNP or nosuid if the + * policy allows the corresponding permission between + * the old and new contexts. */ - rc = security_bounded_transition(old_tsec->sid, new_tsec->sid); - if (rc) { - /* - * On failure, preserve the errno values for NNP vs nosuid. - * NNP: Operation not permitted for caller. - * nosuid: Permission denied to file. - */ + if (selinux_policycap_nnp_nosuid_transition) { + av = 0; if (nnp) - return -EPERM; - else - return -EACCES; + av |= PROCESS2__NNP_TRANSITION; + if (nosuid) + av |= PROCESS2__NOSUID_TRANSITION; + rc = avc_has_perm(old_tsec->sid, new_tsec->sid, + SECCLASS_PROCESS2, av, NULL); + if (!rc) + return 0; } - return 0; + + /* + * We also permit NNP or nosuid transitions to bounded SIDs, + * i.e. SIDs that are guaranteed to only be allowed a subset + * of the permissions of the current SID. + */ + rc = security_bounded_transition(old_tsec->sid, new_tsec->sid); + if (!rc) + return 0; + + /* + * On failure, preserve the errno values for NNP vs nosuid. + * NNP: Operation not permitted for caller. + * nosuid: Permission denied to file. + */ + if (nnp) + return -EPERM; + return -EACCES; } static int selinux_bprm_set_creds(struct linux_binprm *bprm) @@ -2356,7 +2376,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) /* SELinux context only depends on initial program or script and not * the script interpreter */ - if (bprm->cred_prepared) + if (bprm->called_set_creds) return 0; old_tsec = current_security(); @@ -2442,30 +2462,17 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) /* Clear any possibly unsafe personality bits on exec: */ bprm->per_clear |= PER_CLEAR_ON_SETID; - } - - return 0; -} -static int selinux_bprm_secureexec(struct linux_binprm *bprm) -{ - const struct task_security_struct *tsec = current_security(); - u32 sid, osid; - int atsecure = 0; - - sid = tsec->sid; - osid = tsec->osid; - - if (osid != sid) { /* Enable secure mode for SIDs transitions unless the noatsecure permission is granted between the two SIDs, i.e. ahp returns 0. */ - atsecure = avc_has_perm(osid, sid, - SECCLASS_PROCESS, - PROCESS__NOATSECURE, NULL); + rc = avc_has_perm(old_tsec->sid, new_tsec->sid, + SECCLASS_PROCESS, PROCESS__NOATSECURE, + NULL); + bprm->secureexec |= !!rc; } - return !!atsecure; + return 0; } static int match_file(const void *p, struct file *file, unsigned fd) @@ -6266,7 +6273,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(bprm_set_creds, selinux_bprm_set_creds), LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds), LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds), - LSM_HOOK_INIT(bprm_secureexec, selinux_bprm_secureexec), LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security), LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security), @@ -6530,7 +6536,7 @@ security_initcall(selinux_init); #if defined(CONFIG_NETFILTER) -static struct nf_hook_ops selinux_nf_ops[] = { +static const struct nf_hook_ops selinux_nf_ops[] = { { .hook = selinux_ipv4_postroute, .pf = NFPROTO_IPV4, diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 0999df03af8b..a5004e9de11a 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -1,7 +1,7 @@ /* * Access vector cache interface for object managers. * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> */ #ifndef _SELINUX_AVC_H_ #define _SELINUX_AVC_H_ diff --git a/security/selinux/include/avc_ss.h b/security/selinux/include/avc_ss.h index d5c328452df0..37d57dadd476 100644 --- a/security/selinux/include/avc_ss.h +++ b/security/selinux/include/avc_ss.h @@ -1,7 +1,7 @@ /* * Access vector cache interface for the security server. * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> */ #ifndef _SELINUX_AVC_SS_H_ #define _SELINUX_AVC_SS_H_ diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index b9fe3434b036..35ffb29a69cb 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -48,6 +48,8 @@ struct security_class_mapping secclass_map[] = { "setrlimit", "rlimitinh", "dyntransition", "setcurrent", "execmem", "execstack", "execheap", "setkeycreate", "setsockcreate", "getrlimit", NULL } }, + { "process2", + { "nnp_transition", "nosuid_transition", NULL } }, { "system", { "ipc_info", "syslog_read", "syslog_mod", "syslog_console", "module_request", "module_load", NULL } }, diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 6ebc61e370ff..1649cd18eb0b 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -3,7 +3,7 @@ * * This file contains the SELinux security data structures for kernel objects. * - * Author(s): Stephen Smalley, <sds@epoch.ncsc.mil> + * Author(s): Stephen Smalley, <sds@tycho.nsa.gov> * Chris Vance, <cvance@nai.com> * Wayne Salamon, <wsalamon@nai.com> * James Morris <jmorris@redhat.com> diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index e91f08c16c0b..28dfb2f93e4d 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -1,7 +1,7 @@ /* * Security server interface. * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> * */ @@ -73,6 +73,7 @@ enum { POLICYDB_CAPABILITY_EXTSOCKCLASS, POLICYDB_CAPABILITY_ALWAYSNETWORK, POLICYDB_CAPABILITY_CGROUPSECLABEL, + POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION, __POLICYDB_CAPABILITY_MAX }; #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1) @@ -84,6 +85,7 @@ extern int selinux_policycap_openperm; extern int selinux_policycap_extsockclass; extern int selinux_policycap_alwaysnetwork; extern int selinux_policycap_cgroupseclabel; +extern int selinux_policycap_nnp_nosuid_transition; /* * type_datum properties diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 1450f85b946d..36a7ce9e11ff 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h @@ -47,10 +47,8 @@ static inline void selinux_xfrm_notify_policyload(void) struct net *net; rtnl_lock(); - for_each_net(net) { - atomic_inc(&net->xfrm.flow_cache_genid); + for_each_net(net) rt_genid_bump_all(net); - } rtnl_unlock(); } #else diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 3628d3a868b6..2c3c7d010d8a 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -1,7 +1,7 @@ /* * Implementation of the access vector table type. * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> */ /* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h index d946c9dc3c9c..725853cadc42 100644 --- a/security/selinux/ss/avtab.h +++ b/security/selinux/ss/avtab.h @@ -5,7 +5,7 @@ * table is used to represent the type enforcement * tables. * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> */ /* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> diff --git a/security/selinux/ss/constraint.h b/security/selinux/ss/constraint.h index 96fd947c494b..33ae2aec4f36 100644 --- a/security/selinux/ss/constraint.h +++ b/security/selinux/ss/constraint.h @@ -10,7 +10,7 @@ * process from labeling an object with a different user * identity. * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> */ #ifndef _SS_CONSTRAINT_H_ #define _SS_CONSTRAINT_H_ diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h index 212e3479a0d9..a2c0f37c42ae 100644 --- a/security/selinux/ss/context.h +++ b/security/selinux/ss/context.h @@ -10,7 +10,7 @@ * security server and can be changed without affecting * clients of the security server. * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> */ #ifndef _SS_CONTEXT_H_ #define _SS_CONTEXT_H_ diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index ad38299164c3..fc28149a4f2e 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c @@ -1,7 +1,7 @@ /* * Implementation of the extensible bitmap type. * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> */ /* * Updated: Hewlett-Packard <paul@paul-moore.com> diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h index 6d5a9ac4251f..da1325dda550 100644 --- a/security/selinux/ss/ebitmap.h +++ b/security/selinux/ss/ebitmap.h @@ -9,7 +9,7 @@ * an explicitly specified starting bit position within * the total bitmap. * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> */ #ifndef _SS_EBITMAP_H_ #define _SS_EBITMAP_H_ diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c index 3858706a29fb..686c3917064c 100644 --- a/security/selinux/ss/hashtab.c +++ b/security/selinux/ss/hashtab.c @@ -1,7 +1,7 @@ /* * Implementation of the hash table type. * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> */ #include <linux/kernel.h> #include <linux/slab.h> diff --git a/security/selinux/ss/hashtab.h b/security/selinux/ss/hashtab.h index 953872cd84ab..009fb5e06172 100644 --- a/security/selinux/ss/hashtab.h +++ b/security/selinux/ss/hashtab.h @@ -5,7 +5,7 @@ * functions for hash computation and key comparison are * provided by the creator of the table. * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> */ #ifndef _SS_HASHTAB_H_ #define _SS_HASHTAB_H_ diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index e1088842232c..d9dc34f4fade 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -1,7 +1,7 @@ /* * Implementation of the multi-level security (MLS) policy. * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> */ /* * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h index e4369e3e6366..0f0a1d65b2ce 100644 --- a/security/selinux/ss/mls.h +++ b/security/selinux/ss/mls.h @@ -1,7 +1,7 @@ /* * Multi-level security (MLS) policy operations. * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> */ /* * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> diff --git a/security/selinux/ss/mls_types.h b/security/selinux/ss/mls_types.h index e93648774137..47f3702cd596 100644 --- a/security/selinux/ss/mls_types.h +++ b/security/selinux/ss/mls_types.h @@ -1,7 +1,7 @@ /* * Type definitions for the multi-level security (MLS) policy. * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> */ /* * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index aa6500abb178..6e8c8056d7ad 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -1,7 +1,7 @@ /* * Implementation of the policy database. * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> */ /* diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 5d23eed35fa7..215f8f30ac5a 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -2,7 +2,7 @@ * A policy database (policydb) specifies the * configuration data for the security policy. * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> */ /* diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 2f02fa67ec2e..e4a1c0dc561a 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -1,7 +1,7 @@ /* * Implementation of the security services. * - * Authors : Stephen Smalley, <sds@epoch.ncsc.mil> + * Authors : Stephen Smalley, <sds@tycho.nsa.gov> * James Morris <jmorris@redhat.com> * * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> @@ -76,7 +76,8 @@ char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = { "open_perms", "extended_socket_class", "always_check_network", - "cgroup_seclabel" + "cgroup_seclabel", + "nnp_nosuid_transition" }; int selinux_policycap_netpeer; @@ -84,6 +85,7 @@ int selinux_policycap_openperm; int selinux_policycap_extsockclass; int selinux_policycap_alwaysnetwork; int selinux_policycap_cgroupseclabel; +int selinux_policycap_nnp_nosuid_transition; static DEFINE_RWLOCK(policy_rwlock); @@ -2009,6 +2011,9 @@ static void security_load_policycaps(void) selinux_policycap_cgroupseclabel = ebitmap_get_bit(&policydb.policycaps, POLICYDB_CAPABILITY_CGROUPSECLABEL); + selinux_policycap_nnp_nosuid_transition = + ebitmap_get_bit(&policydb.policycaps, + POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION); for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++) pr_info("SELinux: policy capability %s=%d\n", diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h index 6abcd8729ec3..3d9fa9556b4f 100644 --- a/security/selinux/ss/services.h +++ b/security/selinux/ss/services.h @@ -1,7 +1,7 @@ /* * Implementation of the security services. * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> */ #ifndef _SS_SERVICES_H_ #define _SS_SERVICES_H_ diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c index c5f436b15d19..6ae08efc5ae7 100644 --- a/security/selinux/ss/sidtab.c +++ b/security/selinux/ss/sidtab.c @@ -1,7 +1,7 @@ /* * Implementation of the SID table type. * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> */ #include <linux/kernel.h> #include <linux/slab.h> diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h index 84dc154d9389..de5d0ea583d2 100644 --- a/security/selinux/ss/sidtab.h +++ b/security/selinux/ss/sidtab.h @@ -2,7 +2,7 @@ * A security identifier table (sidtab) is a hash table * of security context structures indexed by SID value. * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> */ #ifndef _SS_SIDTAB_H_ #define _SS_SIDTAB_H_ diff --git a/security/selinux/ss/symtab.c b/security/selinux/ss/symtab.c index 160326ee99e5..d1a6745849a7 100644 --- a/security/selinux/ss/symtab.c +++ b/security/selinux/ss/symtab.c @@ -1,7 +1,7 @@ /* * Implementation of the symbol table type. * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> */ #include <linux/kernel.h> #include <linux/string.h> diff --git a/security/selinux/ss/symtab.h b/security/selinux/ss/symtab.h index ca422b42fbc0..0bc12d587d3a 100644 --- a/security/selinux/ss/symtab.h +++ b/security/selinux/ss/symtab.h @@ -4,7 +4,7 @@ * is arbitrary. The symbol table type is implemented * using the hash table type (hashtab). * - * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + * Author : Stephen Smalley, <sds@tycho.nsa.gov> */ #ifndef _SS_SYMTAB_H_ #define _SS_SYMTAB_H_ diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 463af86812c7..319add31b4a4 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -917,7 +917,7 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm) struct superblock_smack *sbsp; int rc; - if (bprm->cred_prepared) + if (bprm->called_set_creds) return 0; isp = inode->i_security; @@ -950,35 +950,9 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm) bsp->smk_task = isp->smk_task; bprm->per_clear |= PER_CLEAR_ON_SETID; - return 0; -} - -/** - * smack_bprm_committing_creds - Prepare to install the new credentials - * from bprm. - * - * @bprm: binprm for exec - */ -static void smack_bprm_committing_creds(struct linux_binprm *bprm) -{ - struct task_smack *bsp = bprm->cred->security; - + /* Decide if this is a secure exec. */ if (bsp->smk_task != bsp->smk_forked) - current->pdeath_signal = 0; -} - -/** - * smack_bprm_secureexec - Return the decision to use secureexec. - * @bprm: binprm for exec - * - * Returns 0 on success. - */ -static int smack_bprm_secureexec(struct linux_binprm *bprm) -{ - struct task_smack *tsp = current_security(); - - if (tsp->smk_task != tsp->smk_forked) - return 1; + bprm->secureexec = 1; return 0; } @@ -4645,8 +4619,6 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(sb_parse_opts_str, smack_parse_opts_str), LSM_HOOK_INIT(bprm_set_creds, smack_bprm_set_creds), - LSM_HOOK_INIT(bprm_committing_creds, smack_bprm_committing_creds), - LSM_HOOK_INIT(bprm_secureexec, smack_bprm_secureexec), LSM_HOOK_INIT(inode_alloc_security, smack_inode_alloc_security), LSM_HOOK_INIT(inode_free_security, smack_inode_free_security), diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c index cdeb0f3243dd..e36d17835d4f 100644 --- a/security/smack/smack_netfilter.c +++ b/security/smack/smack_netfilter.c @@ -58,7 +58,7 @@ static unsigned int smack_ipv4_output(void *priv, return NF_ACCEPT; } -static struct nf_hook_ops smack_nf_ops[] = { +static const struct nf_hook_ops smack_nf_ops[] = { { .hook = smack_ipv4_output, .pf = NFPROTO_IPV4, diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 130b4fa4f65f..d25b705360e0 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -76,7 +76,7 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) * Do only if this function is called for the first time of an execve * operation. */ - if (bprm->cred_prepared) + if (bprm->called_set_creds) return 0; #ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER /* |