diff --git a/fs/compat.c b/fs/compat.c index 15078ce4c04a3b385de62b3a4d4a2ce498ca07b0..5216c3fd751771ab4349753f68395b6daba74063 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -1104,10 +1104,6 @@ static ssize_t compat_do_readv_writev(int type, struct file *file, if (ret < 0) goto out; - ret = security_file_permission(file, type == READ ? MAY_READ:MAY_WRITE); - if (ret) - goto out; - fnv = NULL; if (type == READ) { fn = file->f_op->read; diff --git a/fs/read_write.c b/fs/read_write.c index ea1f94cc722e0c942111b9849cedf8b1aef1d86a..c4d3d17923f155004fec85fd04f836a06aa585f3 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -197,25 +197,27 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count { struct inode *inode; loff_t pos; + int retval = -EINVAL; inode = file->f_path.dentry->d_inode; if (unlikely((ssize_t) count < 0)) - goto Einval; + return retval; pos = *ppos; if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) - goto Einval; + return retval; if (unlikely(inode->i_flock && mandatory_lock(inode))) { - int retval = locks_mandatory_area( + retval = locks_mandatory_area( read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, inode, file, pos, count); if (retval < 0) return retval; } + retval = security_file_permission(file, + read_write == READ ? MAY_READ : MAY_WRITE); + if (retval) + return retval; return count > MAX_RW_COUNT ? MAX_RW_COUNT : count; - -Einval: - return -EINVAL; } static void wait_on_retry_sync_kiocb(struct kiocb *iocb) @@ -267,18 +269,15 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) ret = rw_verify_area(READ, file, pos, count); if (ret >= 0) { count = ret; - ret = security_file_permission (file, MAY_READ); - if (!ret) { - if (file->f_op->read) - ret = file->f_op->read(file, buf, count, pos); - else - ret = do_sync_read(file, buf, count, pos); - if (ret > 0) { - fsnotify_access(file->f_path.dentry); - add_rchar(current, ret); - } - inc_syscr(current); + if (file->f_op->read) + ret = file->f_op->read(file, buf, count, pos); + else + ret = do_sync_read(file, buf, count, pos); + if (ret > 0) { + fsnotify_access(file->f_path.dentry); + add_rchar(current, ret); } + inc_syscr(current); } return ret; @@ -325,18 +324,15 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ ret = rw_verify_area(WRITE, file, pos, count); if (ret >= 0) { count = ret; - ret = security_file_permission (file, MAY_WRITE); - if (!ret) { - if (file->f_op->write) - ret = file->f_op->write(file, buf, count, pos); - else - ret = do_sync_write(file, buf, count, pos); - if (ret > 0) { - fsnotify_modify(file->f_path.dentry); - add_wchar(current, ret); - } - inc_syscw(current); + if (file->f_op->write) + ret = file->f_op->write(file, buf, count, pos); + else + ret = do_sync_write(file, buf, count, pos); + if (ret > 0) { + fsnotify_modify(file->f_path.dentry); + add_wchar(current, ret); } + inc_syscw(current); } return ret; @@ -603,9 +599,6 @@ static ssize_t do_readv_writev(int type, struct file *file, ret = rw_verify_area(type, file, pos, tot_len); if (ret < 0) goto out; - ret = security_file_permission(file, type == READ ? MAY_READ : MAY_WRITE); - if (ret) - goto out; fnv = NULL; if (type == READ) { @@ -737,10 +730,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, goto fput_in; count = retval; - retval = security_file_permission (in_file, MAY_READ); - if (retval) - goto fput_in; - /* * Get output file, and verify that it is ok.. */ @@ -759,10 +748,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, goto fput_out; count = retval; - retval = security_file_permission (out_file, MAY_WRITE); - if (retval) - goto fput_out; - if (!max) max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes); diff --git a/fs/splice.c b/fs/splice.c index 6bdcb6107bc3c55b58199537e2eb5537133cd460..56b802bfbfa4879021cc2af03f175e69cec621d8 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -908,10 +908,6 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, if (unlikely(ret < 0)) return ret; - ret = security_file_permission(out, MAY_WRITE); - if (unlikely(ret < 0)) - return ret; - return out->f_op->splice_write(pipe, out, ppos, len, flags); } @@ -934,10 +930,6 @@ static long do_splice_to(struct file *in, loff_t *ppos, if (unlikely(ret < 0)) return ret; - ret = security_file_permission(in, MAY_READ); - if (unlikely(ret < 0)) - return ret; - return in->f_op->splice_read(in, ppos, pipe, len, flags); } diff --git a/include/linux/mm.h b/include/linux/mm.h index 1b7b95c67acaf5df2fd9cb860599931119ddc029..1897ca223eca99c402523994c04e64287b769cbd 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -12,7 +12,6 @@ #include #include #include -#include struct mempolicy; struct anon_vma; @@ -34,6 +33,8 @@ extern int sysctl_legacy_va_layout; #define sysctl_legacy_va_layout 0 #endif +extern unsigned long mmap_min_addr; + #include #include #include diff --git a/include/linux/security.h b/include/linux/security.h index ac050830a873b044ba1d23144c88fb99a975c934..d24974262dc62a9376e6c6ffd1a4e7f42ca0196a 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -34,6 +34,12 @@ #include #include +/* only a char in selinux superblock security struct flags */ +#define FSCONTEXT_MNT 0x01 +#define CONTEXT_MNT 0x02 +#define ROOTCONTEXT_MNT 0x04 +#define DEFCONTEXT_MNT 0x08 + /* * Bounding set */ @@ -243,9 +249,6 @@ struct request_sock; * @mnt contains the mounted file system. * @flags contains the new filesystem flags. * @data contains the filesystem-specific data. - * @sb_post_mountroot: - * Update the security module's state when the root filesystem is mounted. - * This hook is only called if the mount was successful. * @sb_post_addmount: * Update the security module's state when a filesystem is mounted. * This hook is called any time a mount is successfully grafetd to @@ -261,6 +264,22 @@ struct request_sock; * Update module state after a successful pivot. * @old_nd contains the nameidata structure for the old root. * @new_nd contains the nameidata structure for the new root. + * @sb_get_mnt_opts: + * Get the security relevant mount options used for a superblock + * @sb the superblock to get security mount options from + * @mount_options array for pointers to mount options + * @mount_flags array of ints specifying what each mount options is + * @num_opts number of options in the arrays + * @sb_set_mnt_opts: + * Set the security relevant mount options used for a superblock + * @sb the superblock to set security mount options for + * @mount_options array for pointers to mount options + * @mount_flags array of ints specifying what each mount options is + * @num_opts number of options in the arrays + * @sb_clone_mnt_opts: + * Copy all security options from a given superblock to another + * @oldsb old superblock which contain information to clone + * @newsb new superblock which needs filled in * * Security hooks for inode operations. * @@ -1183,6 +1202,10 @@ struct request_sock; * Convert secid to security context. * @secid contains the security ID. * @secdata contains the pointer that stores the converted security context. + * @secctx_to_secid: + * Convert security context to secid. + * @secid contains the pointer to the generated security ID. + * @secdata contains the security context. * * @release_secctx: * Release the security context. @@ -1235,13 +1258,19 @@ struct security_operations { void (*sb_umount_busy) (struct vfsmount * mnt); void (*sb_post_remount) (struct vfsmount * mnt, unsigned long flags, void *data); - void (*sb_post_mountroot) (void); void (*sb_post_addmount) (struct vfsmount * mnt, struct nameidata * mountpoint_nd); int (*sb_pivotroot) (struct nameidata * old_nd, struct nameidata * new_nd); void (*sb_post_pivotroot) (struct nameidata * old_nd, struct nameidata * new_nd); + int (*sb_get_mnt_opts) (const struct super_block *sb, + char ***mount_options, int **flags, + int *num_opts); + int (*sb_set_mnt_opts) (struct super_block *sb, char **mount_options, + int *flags, int num_opts); + void (*sb_clone_mnt_opts) (const struct super_block *oldsb, + struct super_block *newsb); int (*inode_alloc_security) (struct inode *inode); void (*inode_free_security) (struct inode *inode); @@ -1371,6 +1400,7 @@ struct security_operations { int (*getprocattr)(struct task_struct *p, char *name, char **value); int (*setprocattr)(struct task_struct *p, char *name, void *value, size_t size); int (*secid_to_secctx)(u32 secid, char **secdata, u32 *seclen); + int (*secctx_to_secid)(char *secdata, u32 seclen, u32 *secid); void (*release_secctx)(char *secdata, u32 seclen); #ifdef CONFIG_SECURITY_NETWORK @@ -1495,10 +1525,16 @@ int security_sb_umount(struct vfsmount *mnt, int flags); void security_sb_umount_close(struct vfsmount *mnt); void security_sb_umount_busy(struct vfsmount *mnt); void security_sb_post_remount(struct vfsmount *mnt, unsigned long flags, void *data); -void security_sb_post_mountroot(void); void security_sb_post_addmount(struct vfsmount *mnt, struct nameidata *mountpoint_nd); int security_sb_pivotroot(struct nameidata *old_nd, struct nameidata *new_nd); void security_sb_post_pivotroot(struct nameidata *old_nd, struct nameidata *new_nd); +int security_sb_get_mnt_opts(const struct super_block *sb, char ***mount_options, + int **flags, int *num_opts); +int security_sb_set_mnt_opts(struct super_block *sb, char **mount_options, + int *flags, int num_opts); +void security_sb_clone_mnt_opts(const struct super_block *oldsb, + struct super_block *newsb); + int security_inode_alloc(struct inode *inode); void security_inode_free(struct inode *inode); int security_inode_init_security(struct inode *inode, struct inode *dir, @@ -1603,6 +1639,7 @@ int security_setprocattr(struct task_struct *p, char *name, void *value, size_t int security_netlink_send(struct sock *sk, struct sk_buff *skb); int security_netlink_recv(struct sk_buff *skb, int cap); int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); +int security_secctx_to_secid(char *secdata, u32 seclen, u32 *secid); void security_release_secctx(char *secdata, u32 seclen); #else /* CONFIG_SECURITY */ @@ -1777,9 +1814,6 @@ static inline void security_sb_post_remount (struct vfsmount *mnt, unsigned long flags, void *data) { } -static inline void security_sb_post_mountroot (void) -{ } - static inline void security_sb_post_addmount (struct vfsmount *mnt, struct nameidata *mountpoint_nd) { } @@ -2266,7 +2300,7 @@ static inline struct dentry *securityfs_create_file(const char *name, mode_t mode, struct dentry *parent, void *data, - struct file_operations *fops) + const struct file_operations *fops) { return ERR_PTR(-ENODEV); } @@ -2280,6 +2314,13 @@ static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *secle return -EOPNOTSUPP; } +static inline int security_secctx_to_secid(char *secdata, + u32 seclen, + u32 *secid) +{ + return -EOPNOTSUPP; +} + static inline void security_release_secctx(char *secdata, u32 seclen) { } diff --git a/init/do_mounts.c b/init/do_mounts.c index 2ae5b84623992719c511256445876f15ce73f76b..1161dfd7b0d3d23a4f9968c973a5f578b42c341d 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -378,6 +378,5 @@ void __init prepare_namespace(void) out: sys_mount(".", "/", NULL, MS_MOVE, NULL); sys_chroot("."); - security_sb_post_mountroot(); } diff --git a/mm/mmap.c b/mm/mmap.c index 15678aa6ec73a4389d1c523fe542144cd3050836..bfa389fc6ded6a2a5892eec57ed6cd90bbd34d1e 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1620,7 +1620,7 @@ static inline int expand_downwards(struct vm_area_struct *vma, return -ENOMEM; address &= PAGE_MASK; - error = security_file_mmap(0, 0, 0, 0, address, 1); + error = security_file_mmap(NULL, 0, 0, 0, address, 1); if (error) return error; @@ -1941,7 +1941,7 @@ unsigned long do_brk(unsigned long addr, unsigned long len) if (is_hugepage_only_range(mm, addr, len)) return -EINVAL; - error = security_file_mmap(0, 0, 0, 0, addr, 1); + error = security_file_mmap(NULL, 0, 0, 0, addr, 1); if (error) return error; diff --git a/security/dummy.c b/security/dummy.c index 3ccfbbe973b6d3014ea9b8cf77015b206688bf6f..48d4b0a52737b2e28a8fb2e32d589af2db2463f9 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -225,22 +225,40 @@ static void dummy_sb_post_remount (struct vfsmount *mnt, unsigned long flags, } -static void dummy_sb_post_mountroot (void) +static void dummy_sb_post_addmount (struct vfsmount *mnt, struct nameidata *nd) { return; } -static void dummy_sb_post_addmount (struct vfsmount *mnt, struct nameidata *nd) +static int dummy_sb_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd) +{ + return 0; +} + +static void dummy_sb_post_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd) { return; } -static int dummy_sb_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd) +static int dummy_sb_get_mnt_opts(const struct super_block *sb, char ***mount_options, + int **flags, int *num_opts) { + *mount_options = NULL; + *flags = NULL; + *num_opts = 0; return 0; } -static void dummy_sb_post_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd) +static int dummy_sb_set_mnt_opts(struct super_block *sb, char **mount_options, + int *flags, int num_opts) +{ + if (unlikely(num_opts)) + return -EOPNOTSUPP; + return 0; +} + +static void dummy_sb_clone_mnt_opts(const struct super_block *oldsb, + struct super_block *newsb) { return; } @@ -928,6 +946,11 @@ static int dummy_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) return -EOPNOTSUPP; } +static int dummy_secctx_to_secid(char *secdata, u32 seclen, u32 *secid) +{ + return -EOPNOTSUPP; +} + static void dummy_release_secctx(char *secdata, u32 seclen) { } @@ -994,10 +1017,12 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, sb_umount_close); set_to_dummy_if_null(ops, sb_umount_busy); set_to_dummy_if_null(ops, sb_post_remount); - set_to_dummy_if_null(ops, sb_post_mountroot); set_to_dummy_if_null(ops, sb_post_addmount); set_to_dummy_if_null(ops, sb_pivotroot); set_to_dummy_if_null(ops, sb_post_pivotroot); + set_to_dummy_if_null(ops, sb_get_mnt_opts); + set_to_dummy_if_null(ops, sb_set_mnt_opts); + set_to_dummy_if_null(ops, sb_clone_mnt_opts); set_to_dummy_if_null(ops, inode_alloc_security); set_to_dummy_if_null(ops, inode_free_security); set_to_dummy_if_null(ops, inode_init_security); @@ -1086,6 +1111,7 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, getprocattr); set_to_dummy_if_null(ops, setprocattr); set_to_dummy_if_null(ops, secid_to_secctx); + set_to_dummy_if_null(ops, secctx_to_secid); set_to_dummy_if_null(ops, release_secctx); #ifdef CONFIG_SECURITY_NETWORK set_to_dummy_if_null(ops, unix_stream_connect); diff --git a/security/keys/proc.c b/security/keys/proc.c index 3e0d0a6e224f5e36204c05526175d9382f6af6c6..694126003ed3bcfaacc980e3210540de38cda107 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c @@ -26,7 +26,7 @@ static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos); static void proc_keys_stop(struct seq_file *p, void *v); static int proc_keys_show(struct seq_file *m, void *v); -static struct seq_operations proc_keys_ops = { +static const struct seq_operations proc_keys_ops = { .start = proc_keys_start, .next = proc_keys_next, .stop = proc_keys_stop, @@ -47,7 +47,7 @@ static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos); static void proc_key_users_stop(struct seq_file *p, void *v); static int proc_key_users_show(struct seq_file *m, void *v); -static struct seq_operations proc_key_users_ops = { +static const struct seq_operations proc_key_users_ops = { .start = proc_key_users_start, .next = proc_key_users_next, .stop = proc_key_users_stop, diff --git a/security/security.c b/security/security.c index 0e1f1f124368b03aa31df48552030ed17bf7946e..ca475ca206e4b3afe51ad7bdee1c30fe8398c892 100644 --- a/security/security.c +++ b/security/security.c @@ -288,11 +288,6 @@ void security_sb_post_remount(struct vfsmount *mnt, unsigned long flags, void *d security_ops->sb_post_remount(mnt, flags, data); } -void security_sb_post_mountroot(void) -{ - security_ops->sb_post_mountroot(); -} - void security_sb_post_addmount(struct vfsmount *mnt, struct nameidata *mountpoint_nd) { security_ops->sb_post_addmount(mnt, mountpoint_nd); @@ -308,6 +303,26 @@ void security_sb_post_pivotroot(struct nameidata *old_nd, struct nameidata *new_ security_ops->sb_post_pivotroot(old_nd, new_nd); } +int security_sb_get_mnt_opts(const struct super_block *sb, + char ***mount_options, + int **flags, int *num_opts) +{ + return security_ops->sb_get_mnt_opts(sb, mount_options, flags, num_opts); +} + +int security_sb_set_mnt_opts(struct super_block *sb, + char **mount_options, + int *flags, int num_opts) +{ + return security_ops->sb_set_mnt_opts(sb, mount_options, flags, num_opts); +} + +void security_sb_clone_mnt_opts(const struct super_block *oldsb, + struct super_block *newsb) +{ + security_ops->sb_clone_mnt_opts(oldsb, newsb); +} + int security_inode_alloc(struct inode *inode) { inode->i_security = NULL; @@ -816,6 +831,12 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) } EXPORT_SYMBOL(security_secid_to_secctx); +int security_secctx_to_secid(char *secdata, u32 seclen, u32 *secid) +{ + return security_ops->secctx_to_secid(secdata, seclen, secid); +} +EXPORT_SYMBOL(security_secctx_to_secid); + void security_release_secctx(char *secdata, u32 seclen) { return security_ops->release_secctx(secdata, seclen); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 9f3124b08867536aca7cc580046d844e341ac6d5..0396354fff9521b7146ff1aff96e3f9c384a6857 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -82,6 +82,8 @@ #define XATTR_SELINUX_SUFFIX "selinux" #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX +#define NUM_SEL_MNT_OPTS 4 + extern unsigned int policydb_loaded_version; extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); extern int selinux_compat_net; @@ -321,8 +323,8 @@ enum { Opt_error = -1, Opt_context = 1, Opt_fscontext = 2, - Opt_defcontext = 4, - Opt_rootcontext = 8, + Opt_defcontext = 3, + Opt_rootcontext = 4, }; static match_table_t tokens = { @@ -366,150 +368,317 @@ static int may_context_mount_inode_relabel(u32 sid, return rc; } -static int try_context_mount(struct super_block *sb, void *data) +static int sb_finish_set_opts(struct super_block *sb) { - char *context = NULL, *defcontext = NULL; - char *fscontext = NULL, *rootcontext = NULL; - const char *name; - u32 sid; - int alloc = 0, rc = 0, seen = 0; - struct task_security_struct *tsec = current->security; struct superblock_security_struct *sbsec = sb->s_security; + struct dentry *root = sb->s_root; + struct inode *root_inode = root->d_inode; + int rc = 0; - if (!data) - goto out; + if (sbsec->behavior == SECURITY_FS_USE_XATTR) { + /* Make sure that the xattr handler exists and that no + error other than -ENODATA is returned by getxattr on + the root directory. -ENODATA is ok, as this may be + the first boot of the SELinux kernel before we have + assigned xattr values to the filesystem. */ + if (!root_inode->i_op->getxattr) { + printk(KERN_WARNING "SELinux: (dev %s, type %s) has no " + "xattr support\n", sb->s_id, sb->s_type->name); + rc = -EOPNOTSUPP; + goto out; + } + rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0); + if (rc < 0 && rc != -ENODATA) { + if (rc == -EOPNOTSUPP) + printk(KERN_WARNING "SELinux: (dev %s, type " + "%s) has no security xattr handler\n", + sb->s_id, sb->s_type->name); + else + printk(KERN_WARNING "SELinux: (dev %s, type " + "%s) getxattr errno %d\n", sb->s_id, + sb->s_type->name, -rc); + goto out; + } + } - name = sb->s_type->name; + sbsec->initialized = 1; - if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) { + if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) + printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n", + sb->s_id, sb->s_type->name); + else + printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n", + sb->s_id, sb->s_type->name, + labeling_behaviors[sbsec->behavior-1]); - /* NFS we understand. */ - if (!strcmp(name, "nfs")) { - struct nfs_mount_data *d = data; + /* Initialize the root inode. */ + rc = inode_doinit_with_dentry(root_inode, root); - if (d->version < NFS_MOUNT_VERSION) - goto out; + /* Initialize any other inodes associated with the superblock, e.g. + inodes created prior to initial policy load or inodes created + during get_sb by a pseudo filesystem that directly + populates itself. */ + spin_lock(&sbsec->isec_lock); +next_inode: + if (!list_empty(&sbsec->isec_head)) { + struct inode_security_struct *isec = + list_entry(sbsec->isec_head.next, + struct inode_security_struct, list); + struct inode *inode = isec->inode; + spin_unlock(&sbsec->isec_lock); + inode = igrab(inode); + if (inode) { + if (!IS_PRIVATE(inode)) + inode_doinit(inode); + iput(inode); + } + spin_lock(&sbsec->isec_lock); + list_del_init(&isec->list); + goto next_inode; + } + spin_unlock(&sbsec->isec_lock); +out: + return rc; +} - if (d->context[0]) { - context = d->context; - seen |= Opt_context; - } - } else - goto out; +/* + * This function should allow an FS to ask what it's mount security + * options were so it can use those later for submounts, displaying + * mount options, or whatever. + */ +static int selinux_get_mnt_opts(const struct super_block *sb, + char ***mount_options, int **mnt_opts_flags, + int *num_opts) +{ + int rc = 0, i; + struct superblock_security_struct *sbsec = sb->s_security; + char *context = NULL; + u32 len; + char tmp; - } else { - /* Standard string-based options. */ - char *p, *options = data; + *num_opts = 0; + *mount_options = NULL; + *mnt_opts_flags = NULL; - while ((p = strsep(&options, "|")) != NULL) { - int token; - substring_t args[MAX_OPT_ARGS]; + if (!sbsec->initialized) + return -EINVAL; - if (!*p) - continue; + if (!ss_initialized) + return -EINVAL; - token = match_token(p, tokens, args); + /* + * if we ever use sbsec flags for anything other than tracking mount + * settings this is going to need a mask + */ + tmp = sbsec->flags; + /* count the number of mount options for this sb */ + for (i = 0; i < 8; i++) { + if (tmp & 0x01) + (*num_opts)++; + tmp >>= 1; + } - switch (token) { - case Opt_context: - if (seen & (Opt_context|Opt_defcontext)) { - rc = -EINVAL; - printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); - goto out_free; - } - context = match_strdup(&args[0]); - if (!context) { - rc = -ENOMEM; - goto out_free; - } - if (!alloc) - alloc = 1; - seen |= Opt_context; - break; + *mount_options = kcalloc(*num_opts, sizeof(char *), GFP_ATOMIC); + if (!*mount_options) { + rc = -ENOMEM; + goto out_free; + } - case Opt_fscontext: - if (seen & Opt_fscontext) { - rc = -EINVAL; - printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); - goto out_free; - } - fscontext = match_strdup(&args[0]); - if (!fscontext) { - rc = -ENOMEM; - goto out_free; - } - if (!alloc) - alloc = 1; - seen |= Opt_fscontext; - break; + *mnt_opts_flags = kcalloc(*num_opts, sizeof(int), GFP_ATOMIC); + if (!*mnt_opts_flags) { + rc = -ENOMEM; + goto out_free; + } - case Opt_rootcontext: - if (seen & Opt_rootcontext) { - rc = -EINVAL; - printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); - goto out_free; - } - rootcontext = match_strdup(&args[0]); - if (!rootcontext) { - rc = -ENOMEM; - goto out_free; - } - if (!alloc) - alloc = 1; - seen |= Opt_rootcontext; - break; + i = 0; + if (sbsec->flags & FSCONTEXT_MNT) { + rc = security_sid_to_context(sbsec->sid, &context, &len); + if (rc) + goto out_free; + (*mount_options)[i] = context; + (*mnt_opts_flags)[i++] = FSCONTEXT_MNT; + } + if (sbsec->flags & CONTEXT_MNT) { + rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len); + if (rc) + goto out_free; + (*mount_options)[i] = context; + (*mnt_opts_flags)[i++] = CONTEXT_MNT; + } + if (sbsec->flags & DEFCONTEXT_MNT) { + rc = security_sid_to_context(sbsec->def_sid, &context, &len); + if (rc) + goto out_free; + (*mount_options)[i] = context; + (*mnt_opts_flags)[i++] = DEFCONTEXT_MNT; + } + if (sbsec->flags & ROOTCONTEXT_MNT) { + struct inode *root = sbsec->sb->s_root->d_inode; + struct inode_security_struct *isec = root->i_security; - case Opt_defcontext: - if (sbsec->behavior != SECURITY_FS_USE_XATTR) { - rc = -EINVAL; - printk(KERN_WARNING "SELinux: " - "defcontext option is invalid " - "for this filesystem type\n"); - goto out_free; - } - if (seen & (Opt_context|Opt_defcontext)) { - rc = -EINVAL; - printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); - goto out_free; - } - defcontext = match_strdup(&args[0]); - if (!defcontext) { - rc = -ENOMEM; - goto out_free; - } - if (!alloc) - alloc = 1; - seen |= Opt_defcontext; - break; + rc = security_sid_to_context(isec->sid, &context, &len); + if (rc) + goto out_free; + (*mount_options)[i] = context; + (*mnt_opts_flags)[i++] = ROOTCONTEXT_MNT; + } - default: - rc = -EINVAL; - printk(KERN_WARNING "SELinux: unknown mount " - "option\n"); - goto out_free; + BUG_ON(i != *num_opts); - } - } - } + return 0; + +out_free: + /* don't leak context string if security_sid_to_context had an error */ + if (*mount_options && i) + for (; i > 0; i--) + kfree((*mount_options)[i-1]); + kfree(*mount_options); + *mount_options = NULL; + kfree(*mnt_opts_flags); + *mnt_opts_flags = NULL; + *num_opts = 0; + return rc; +} + +static int bad_option(struct superblock_security_struct *sbsec, char flag, + u32 old_sid, u32 new_sid) +{ + /* check if the old mount command had the same options */ + if (sbsec->initialized) + if (!(sbsec->flags & flag) || + (old_sid != new_sid)) + return 1; + + /* check if we were passed the same options twice, + * aka someone passed context=a,context=b + */ + if (!sbsec->initialized) + if (sbsec->flags & flag) + return 1; + return 0; +} +/* + * Allow filesystems with binary mount data to explicitly set mount point + * labeling information. + */ +int selinux_set_mnt_opts(struct super_block *sb, char **mount_options, + int *flags, int num_opts) +{ + int rc = 0, i; + struct task_security_struct *tsec = current->security; + struct superblock_security_struct *sbsec = sb->s_security; + const char *name = sb->s_type->name; + struct inode *inode = sbsec->sb->s_root->d_inode; + struct inode_security_struct *root_isec = inode->i_security; + u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0; + u32 defcontext_sid = 0; - if (!seen) + mutex_lock(&sbsec->lock); + + if (!ss_initialized) { + if (!num_opts) { + /* Defer initialization until selinux_complete_init, + after the initial policy is loaded and the security + server is ready to handle calls. */ + spin_lock(&sb_security_lock); + if (list_empty(&sbsec->list)) + list_add(&sbsec->list, &superblock_security_head); + spin_unlock(&sb_security_lock); + goto out; + } + rc = -EINVAL; + printk(KERN_WARNING "Unable to set superblock options before " + "the security server is initialized\n"); goto out; + } - /* sets the context of the superblock for the fs being mounted. */ - if (fscontext) { - rc = security_context_to_sid(fscontext, strlen(fscontext), &sid); + /* + * parse the mount options, check if they are valid sids. + * also check if someone is trying to mount the same sb more + * than once with different security options. + */ + for (i = 0; i < num_opts; i++) { + u32 sid; + rc = security_context_to_sid(mount_options[i], + strlen(mount_options[i]), &sid); if (rc) { printk(KERN_WARNING "SELinux: security_context_to_sid" "(%s) failed for (dev %s, type %s) errno=%d\n", - fscontext, sb->s_id, name, rc); - goto out_free; + mount_options[i], sb->s_id, name, rc); + goto out; } + switch (flags[i]) { + case FSCONTEXT_MNT: + fscontext_sid = sid; + + if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, + fscontext_sid)) + goto out_double_mount; + + sbsec->flags |= FSCONTEXT_MNT; + break; + case CONTEXT_MNT: + context_sid = sid; + + if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, + context_sid)) + goto out_double_mount; + + sbsec->flags |= CONTEXT_MNT; + break; + case ROOTCONTEXT_MNT: + rootcontext_sid = sid; + + if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, + rootcontext_sid)) + goto out_double_mount; + + sbsec->flags |= ROOTCONTEXT_MNT; + + break; + case DEFCONTEXT_MNT: + defcontext_sid = sid; + + if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, + defcontext_sid)) + goto out_double_mount; + + sbsec->flags |= DEFCONTEXT_MNT; + + break; + default: + rc = -EINVAL; + goto out; + } + } + + if (sbsec->initialized) { + /* previously mounted with options, but not on this attempt? */ + if (sbsec->flags && !num_opts) + goto out_double_mount; + rc = 0; + goto out; + } + + if (strcmp(sb->s_type->name, "proc") == 0) + sbsec->proc = 1; + + /* Determine the labeling behavior to use for this filesystem type. */ + rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid); + if (rc) { + printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n", + __FUNCTION__, sb->s_type->name, rc); + goto out; + } + + /* sets the context of the superblock for the fs being mounted. */ + if (fscontext_sid) { - rc = may_context_mount_sb_relabel(sid, sbsec, tsec); + rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, tsec); if (rc) - goto out_free; + goto out; - sbsec->sid = sid; + sbsec->sid = fscontext_sid; } /* @@ -517,182 +686,250 @@ static int try_context_mount(struct super_block *sb, void *data) * sets the label used on all file below the mountpoint, and will set * the superblock context if not already set. */ - if (context) { - rc = security_context_to_sid(context, strlen(context), &sid); - if (rc) { - printk(KERN_WARNING "SELinux: security_context_to_sid" - "(%s) failed for (dev %s, type %s) errno=%d\n", - context, sb->s_id, name, rc); - goto out_free; - } - - if (!fscontext) { - rc = may_context_mount_sb_relabel(sid, sbsec, tsec); + if (context_sid) { + if (!fscontext_sid) { + rc = may_context_mount_sb_relabel(context_sid, sbsec, tsec); if (rc) - goto out_free; - sbsec->sid = sid; + goto out; + sbsec->sid = context_sid; } else { - rc = may_context_mount_inode_relabel(sid, sbsec, tsec); + rc = may_context_mount_inode_relabel(context_sid, sbsec, tsec); if (rc) - goto out_free; + goto out; } - sbsec->mntpoint_sid = sid; + if (!rootcontext_sid) + rootcontext_sid = context_sid; + sbsec->mntpoint_sid = context_sid; sbsec->behavior = SECURITY_FS_USE_MNTPOINT; } - if (rootcontext) { - struct inode *inode = sb->s_root->d_inode; - struct inode_security_struct *isec = inode->i_security; - rc = security_context_to_sid(rootcontext, strlen(rootcontext), &sid); - if (rc) { - printk(KERN_WARNING "SELinux: security_context_to_sid" - "(%s) failed for (dev %s, type %s) errno=%d\n", - rootcontext, sb->s_id, name, rc); - goto out_free; - } - - rc = may_context_mount_inode_relabel(sid, sbsec, tsec); + if (rootcontext_sid) { + rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec, tsec); if (rc) - goto out_free; + goto out; - isec->sid = sid; - isec->initialized = 1; + root_isec->sid = rootcontext_sid; + root_isec->initialized = 1; } - if (defcontext) { - rc = security_context_to_sid(defcontext, strlen(defcontext), &sid); - if (rc) { - printk(KERN_WARNING "SELinux: security_context_to_sid" - "(%s) failed for (dev %s, type %s) errno=%d\n", - defcontext, sb->s_id, name, rc); - goto out_free; + if (defcontext_sid) { + if (sbsec->behavior != SECURITY_FS_USE_XATTR) { + rc = -EINVAL; + printk(KERN_WARNING "SELinux: defcontext option is " + "invalid for this filesystem type\n"); + goto out; } - if (sid == sbsec->def_sid) - goto out_free; - - rc = may_context_mount_inode_relabel(sid, sbsec, tsec); - if (rc) - goto out_free; + if (defcontext_sid != sbsec->def_sid) { + rc = may_context_mount_inode_relabel(defcontext_sid, + sbsec, tsec); + if (rc) + goto out; + } - sbsec->def_sid = sid; + sbsec->def_sid = defcontext_sid; } -out_free: - if (alloc) { - kfree(context); - kfree(defcontext); - kfree(fscontext); - kfree(rootcontext); - } + rc = sb_finish_set_opts(sb); out: + mutex_unlock(&sbsec->lock); return rc; +out_double_mount: + rc = -EINVAL; + printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different " + "security settings for (dev %s, type %s)\n", sb->s_id, name); + goto out; } -static int superblock_doinit(struct super_block *sb, void *data) +static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb, + struct super_block *newsb) { - struct superblock_security_struct *sbsec = sb->s_security; - struct dentry *root = sb->s_root; - struct inode *inode = root->d_inode; - int rc = 0; + const struct superblock_security_struct *oldsbsec = oldsb->s_security; + struct superblock_security_struct *newsbsec = newsb->s_security; - mutex_lock(&sbsec->lock); - if (sbsec->initialized) - goto out; + int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT); + int set_context = (oldsbsec->flags & CONTEXT_MNT); + int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT); - if (!ss_initialized) { - /* Defer initialization until selinux_complete_init, - after the initial policy is loaded and the security - server is ready to handle calls. */ - spin_lock(&sb_security_lock); - if (list_empty(&sbsec->list)) - list_add(&sbsec->list, &superblock_security_head); - spin_unlock(&sb_security_lock); - goto out; + /* we can't error, we can't save the info, this shouldn't get called + * this early in the boot process. */ + BUG_ON(!ss_initialized); + + /* this might go away sometime down the line if there is a new user + * of clone, but for now, nfs better not get here... */ + BUG_ON(newsbsec->initialized); + + /* how can we clone if the old one wasn't set up?? */ + BUG_ON(!oldsbsec->initialized); + + mutex_lock(&newsbsec->lock); + + newsbsec->flags = oldsbsec->flags; + + newsbsec->sid = oldsbsec->sid; + newsbsec->def_sid = oldsbsec->def_sid; + newsbsec->behavior = oldsbsec->behavior; + + if (set_context) { + u32 sid = oldsbsec->mntpoint_sid; + + if (!set_fscontext) + newsbsec->sid = sid; + if (!set_rootcontext) { + struct inode *newinode = newsb->s_root->d_inode; + struct inode_security_struct *newisec = newinode->i_security; + newisec->sid = sid; + } + newsbsec->mntpoint_sid = sid; } + if (set_rootcontext) { + const struct inode *oldinode = oldsb->s_root->d_inode; + const struct inode_security_struct *oldisec = oldinode->i_security; + struct inode *newinode = newsb->s_root->d_inode; + struct inode_security_struct *newisec = newinode->i_security; - /* Determine the labeling behavior to use for this filesystem type. */ - rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid); - if (rc) { - printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n", - __FUNCTION__, sb->s_type->name, rc); - goto out; + newisec->sid = oldisec->sid; } - rc = try_context_mount(sb, data); - if (rc) + sb_finish_set_opts(newsb); + mutex_unlock(&newsbsec->lock); +} + +/* + * string mount options parsing and call set the sbsec + */ +static int superblock_doinit(struct super_block *sb, void *data) +{ + char *context = NULL, *defcontext = NULL; + char *fscontext = NULL, *rootcontext = NULL; + int rc = 0; + char *p, *options = data; + /* selinux only know about a fixed number of mount options */ + char *mnt_opts[NUM_SEL_MNT_OPTS]; + int mnt_opts_flags[NUM_SEL_MNT_OPTS], num_mnt_opts = 0; + + if (!data) goto out; - if (sbsec->behavior == SECURITY_FS_USE_XATTR) { - /* Make sure that the xattr handler exists and that no - error other than -ENODATA is returned by getxattr on - the root directory. -ENODATA is ok, as this may be - the first boot of the SELinux kernel before we have - assigned xattr values to the filesystem. */ - if (!inode->i_op->getxattr) { - printk(KERN_WARNING "SELinux: (dev %s, type %s) has no " - "xattr support\n", sb->s_id, sb->s_type->name); - rc = -EOPNOTSUPP; - goto out; - } - rc = inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0); - if (rc < 0 && rc != -ENODATA) { - if (rc == -EOPNOTSUPP) - printk(KERN_WARNING "SELinux: (dev %s, type " - "%s) has no security xattr handler\n", - sb->s_id, sb->s_type->name); - else - printk(KERN_WARNING "SELinux: (dev %s, type " - "%s) getxattr errno %d\n", sb->s_id, - sb->s_type->name, -rc); + /* with the nfs patch this will become a goto out; */ + if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) { + const char *name = sb->s_type->name; + /* NFS we understand. */ + if (!strcmp(name, "nfs")) { + struct nfs_mount_data *d = data; + + if (d->version != NFS_MOUNT_VERSION) + goto out; + + if (d->context[0]) { + context = kstrdup(d->context, GFP_KERNEL); + if (!context) { + rc = -ENOMEM; + goto out; + } + } + goto build_flags; + } else goto out; - } } - if (strcmp(sb->s_type->name, "proc") == 0) - sbsec->proc = 1; + /* Standard string-based options. */ + while ((p = strsep(&options, "|")) != NULL) { + int token; + substring_t args[MAX_OPT_ARGS]; - sbsec->initialized = 1; + if (!*p) + continue; - if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) { - printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n", - sb->s_id, sb->s_type->name); - } - else { - printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n", - sb->s_id, sb->s_type->name, - labeling_behaviors[sbsec->behavior-1]); - } + token = match_token(p, tokens, args); - /* Initialize the root inode. */ - rc = inode_doinit_with_dentry(sb->s_root->d_inode, sb->s_root); + switch (token) { + case Opt_context: + if (context || defcontext) { + rc = -EINVAL; + printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); + goto out_err; + } + context = match_strdup(&args[0]); + if (!context) { + rc = -ENOMEM; + goto out_err; + } + break; + + case Opt_fscontext: + if (fscontext) { + rc = -EINVAL; + printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); + goto out_err; + } + fscontext = match_strdup(&args[0]); + if (!fscontext) { + rc = -ENOMEM; + goto out_err; + } + break; + + case Opt_rootcontext: + if (rootcontext) { + rc = -EINVAL; + printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); + goto out_err; + } + rootcontext = match_strdup(&args[0]); + if (!rootcontext) { + rc = -ENOMEM; + goto out_err; + } + break; + + case Opt_defcontext: + if (context || defcontext) { + rc = -EINVAL; + printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); + goto out_err; + } + defcontext = match_strdup(&args[0]); + if (!defcontext) { + rc = -ENOMEM; + goto out_err; + } + break; + + default: + rc = -EINVAL; + printk(KERN_WARNING "SELinux: unknown mount option\n"); + goto out_err; - /* Initialize any other inodes associated with the superblock, e.g. - inodes created prior to initial policy load or inodes created - during get_sb by a pseudo filesystem that directly - populates itself. */ - spin_lock(&sbsec->isec_lock); -next_inode: - if (!list_empty(&sbsec->isec_head)) { - struct inode_security_struct *isec = - list_entry(sbsec->isec_head.next, - struct inode_security_struct, list); - struct inode *inode = isec->inode; - spin_unlock(&sbsec->isec_lock); - inode = igrab(inode); - if (inode) { - if (!IS_PRIVATE (inode)) - inode_doinit(inode); - iput(inode); } - spin_lock(&sbsec->isec_lock); - list_del_init(&isec->list); - goto next_inode; } - spin_unlock(&sbsec->isec_lock); + +build_flags: + if (fscontext) { + mnt_opts[num_mnt_opts] = fscontext; + mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT; + } + if (context) { + mnt_opts[num_mnt_opts] = context; + mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT; + } + if (rootcontext) { + mnt_opts[num_mnt_opts] = rootcontext; + mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT; + } + if (defcontext) { + mnt_opts[num_mnt_opts] = defcontext; + mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT; + } + out: - mutex_unlock(&sbsec->lock); + rc = selinux_set_mnt_opts(sb, mnt_opts, mnt_opts_flags, num_mnt_opts); +out_err: + kfree(context); + kfree(defcontext); + kfree(fscontext); + kfree(rootcontext); return rc; } @@ -4710,6 +4947,11 @@ static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) return security_sid_to_context(secid, secdata, seclen); } +static int selinux_secctx_to_secid(char *secdata, u32 seclen, u32 *secid) +{ + return security_context_to_sid(secdata, seclen, secid); +} + static void selinux_release_secctx(char *secdata, u32 seclen) { kfree(secdata); @@ -4800,6 +5042,9 @@ static struct security_operations selinux_ops = { .sb_statfs = selinux_sb_statfs, .sb_mount = selinux_mount, .sb_umount = selinux_umount, + .sb_get_mnt_opts = selinux_get_mnt_opts, + .sb_set_mnt_opts = selinux_set_mnt_opts, + .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts, .inode_alloc_security = selinux_inode_alloc_security, .inode_free_security = selinux_inode_free_security, @@ -4898,6 +5143,7 @@ static struct security_operations selinux_ops = { .setprocattr = selinux_setprocattr, .secid_to_secctx = selinux_secid_to_secctx, + .secctx_to_secid = selinux_secctx_to_secid, .release_secctx = selinux_release_secctx, .unix_stream_connect = selinux_socket_unix_stream_connect, diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 642a9fd319adea8dccd3ad84d9228f7e71274c4e..4138a80f8e2706061666f5a3b83d731ff9204afb 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -65,6 +65,7 @@ struct superblock_security_struct { u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */ unsigned int behavior; /* labeling behavior */ unsigned char initialized; /* initialization flag */ + unsigned char flags; /* which mount options were specified */ unsigned char proc; /* proc fs */ struct mutex lock; struct list_head isec_head; diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 2fa483f26113c1656d950e11579bda5c7903cf8c..397fd4955fe1fb9dc9e57b95189084435f648294 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -1222,7 +1222,7 @@ static int sel_avc_stats_seq_show(struct seq_file *seq, void *v) static void sel_avc_stats_seq_stop(struct seq_file *seq, void *v) { } -static struct seq_operations sel_avc_cache_stats_seq_ops = { +static const struct seq_operations sel_avc_cache_stats_seq_ops = { .start = sel_avc_stats_seq_start, .next = sel_avc_stats_seq_next, .show = sel_avc_stats_seq_show, diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 9e70a160d7da4e5f90d9c57ad816b4e2ec4d5b16..cd10e27fc9e630002395db667e9fd85f78eadeeb 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -280,7 +280,7 @@ int avtab_alloc(struct avtab *h, u32 nrules) h->nel = 0; h->nslot = nslot; h->mask = mask; - printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated." + printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated. " "Num of rules:%d\n", h->nslot, nrules); return 0; } diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index fb5d70a6628dfe79a31a5209f20e38eccdc00bbc..3bbcb5369af9eb6ae2f230a2b0d0ea5099a55273 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -537,15 +537,8 @@ int mls_compute_sid(struct context *scontext, /* Use the process effective MLS attributes. */ return mls_context_cpy_low(newcontext, scontext); case AVTAB_MEMBER: - /* Only polyinstantiate the MLS attributes if - the type is being polyinstantiated */ - if (newcontext->type != tcontext->type) { - /* Use the process effective MLS attributes. */ - return mls_context_cpy_low(newcontext, scontext); - } else { - /* Use the related object MLS attributes. */ - return mls_context_cpy(newcontext, tcontext); - } + /* Use the process effective MLS attributes. */ + return mls_context_cpy_low(newcontext, scontext); default: return -EINVAL; }