security: Remove the set_mnt_opts and clone_mnt_opts ops
diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c index ec5f0a1..824600e 100644 --- a/fs/nfs/fs_context.c +++ b/fs/nfs/fs_context.c
@@ -1297,8 +1297,6 @@ static int nfs_get_ordinary_tree(struct fs_context *fc) { struct nfs_fs_context *ctx = nfs_fc2context(fc); - ctx->set_security = nfs_set_sb_security; - return ctx->nfs_mod->rpc_ops->try_get_tree(fc); } @@ -1313,8 +1311,6 @@ static int nfs_get_xdev_tree(struct fs_context *fc) dprintk("--> nfs_xdev_mount()\n"); - ctx->set_security = nfs_clone_sb_security; - /* create a new volume representation */ server = ctx->nfs_mod->rpc_ops->clone_server(NFS_SB(ctx->clone_data.sb), ctx->mntfh, @@ -1367,7 +1363,7 @@ static int nfs_get_tree(struct fs_context *fc) } /* - * Handle duplication of a configuration. The caller copied *src into *sc, but + * Handle duplication of a configuration. The caller copied *src into *fc, but * it can't deal with resource pointers in the filesystem context, so we have * to do that. We need to clear pointers, copy data or get extra refs as * appropriate. @@ -1512,6 +1508,13 @@ static int nfs_init_fs_context(struct fs_context *fc, struct dentry *reference) ret = -EINVAL; if (!reference) goto error_fh; + ret = -ESTALE; + if (d_inode(reference)->i_op != + NFS_SB(reference->d_sb)->nfs_client->rpc_ops->dir_inode_ops) + goto error_fh; + if (NFS_SB(reference->d_sb)->caps & NFS_CAP_SECURITY_LABEL) + fc->lsm_flags |= SECURITY_LSM_NATIVE_LABELS; + /* Fall through */ case FS_CONTEXT_FOR_RECONFIGURE: ret = nfs_mount_init_from_ref(fc, ctx, reference);
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 80784db..82b1fe5 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h
@@ -415,8 +415,6 @@ extern int nfs_wait_atomic_killable(atomic_t *p, unsigned int mode); extern const struct super_operations nfs_sops; bool nfs_auth_info_match(const struct nfs_auth_info *, rpc_authflavor_t); int nfs_try_get_tree(struct fs_context *); -int nfs_set_sb_security(struct super_block *, struct fs_context *); -int nfs_clone_sb_security(struct super_block *, struct fs_context *); int nfs_get_tree_common(struct nfs_server *, struct fs_context *); void nfs_kill_super(struct super_block *);
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c index b17b31e0..ffe3b11 100644 --- a/fs/nfs/nfs4super.c +++ b/fs/nfs/nfs4super.c
@@ -78,8 +78,6 @@ static int nfs4_get_remote_tree(struct fs_context *fc) struct nfs_fs_context *ctx = nfs_fc2context(fc); struct nfs_server *server; - ctx->set_security = nfs_set_sb_security; - /* Get a volume representation */ server = nfs4_create_server(fc); if (IS_ERR(server)) @@ -271,8 +269,6 @@ static int nfs4_get_remote_referral_tree(struct fs_context *fc) dprintk("--> nfs4_get_remote_referral_tree()\n"); - ctx->set_security = nfs_clone_sb_security; - if (!ctx->clone_data.cloned) return -EINVAL;
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index ac77dc6..90b463b 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c
@@ -1169,52 +1169,6 @@ static void nfs_get_cache_cookie(struct super_block *sb, } #endif -int nfs_set_sb_security(struct super_block *sb, struct fs_context *fc) -{ - int error; - unsigned long kflags = 0, kflags_out = 0; - - if (NFS_SB(sb)->caps & NFS_CAP_SECURITY_LABEL) - kflags |= SECURITY_LSM_NATIVE_LABELS; - - error = security_sb_set_mnt_opts(sb, fc->security, kflags, &kflags_out); - if (error) - goto err; - - if (NFS_SB(sb)->caps & NFS_CAP_SECURITY_LABEL && - !(kflags_out & SECURITY_LSM_NATIVE_LABELS)) - NFS_SB(sb)->caps &= ~NFS_CAP_SECURITY_LABEL; -err: - return error; -} -EXPORT_SYMBOL_GPL(nfs_set_sb_security); - -int nfs_clone_sb_security(struct super_block *sb, struct fs_context *fc) -{ - struct nfs_fs_context *ctx = nfs_fc2context(fc); - int error; - unsigned long kflags = 0, kflags_out = 0; - - /* clone any lsm security options from the parent to the new sb */ - if (d_inode(fc->root)->i_op != - NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops) - return -ESTALE; - - if (NFS_SB(sb)->caps & NFS_CAP_SECURITY_LABEL) - kflags |= SECURITY_LSM_NATIVE_LABELS; - - error = security_sb_clone_mnt_opts(ctx->clone_data.sb, sb, kflags, - &kflags_out); - if (error) - return error; - - if (NFS_SB(sb)->caps & NFS_CAP_SECURITY_LABEL && - !(kflags_out & SECURITY_LSM_NATIVE_LABELS)) - NFS_SB(sb)->caps &= ~NFS_CAP_SECURITY_LABEL; - return 0; -} -EXPORT_SYMBOL_GPL(nfs_clone_sb_security); - int nfs_get_tree_common(struct nfs_server *server, struct fs_context *fc) { struct nfs_fs_context *ctx = nfs_fc2context(fc); @@ -1276,9 +1230,8 @@ int nfs_get_tree_common(struct nfs_server *server, struct fs_context *fc) goto error_splat_super; } - error = ctx->set_security(s, fc); - if (error) - goto error_splat_root; + if (!(fc->lsm_flags & SECURITY_LSM_NATIVE_LABELS)) + server->caps &= ~NFS_CAP_SECURITY_LABEL; s->s_flags |= SB_ACTIVE; error = 0;
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 227b46d..15fd4f3 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h
@@ -160,18 +160,6 @@ * current root (put_old). * @new_path contains the path for the new root (new_root). * Return 0 if permission is granted. - * @sb_set_mnt_opts: - * Set the security relevant mount options used for a superblock - * @sb the superblock to set security mount options for - * @opts binary data structure containing all lsm mount data - * @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 - * @sb_parse_opts_str: - * Parse a string of security data filling in the opts structure - * @options string containing all mount options known by the LSM - * @opts binary data structure usable by the LSM * @move_mount: * Check permission before a mount is moved. * @from_path indicates the mount that is going to be moved. @@ -1510,15 +1498,6 @@ union security_list_options { void *data, size_t data_size); int (*sb_umount)(struct vfsmount *mnt, int flags); int (*sb_pivotroot)(const struct path *old_path, const struct path *new_path); - int (*sb_set_mnt_opts)(struct super_block *sb, - struct security_mnt_opts *opts, - unsigned long kern_flags, - unsigned long *set_kern_flags); - int (*sb_clone_mnt_opts)(const struct super_block *oldsb, - struct super_block *newsb, - unsigned long kern_flags, - unsigned long *set_kern_flags); - int (*sb_parse_opts_str)(char *options, struct security_mnt_opts *opts); int (*move_mount)(const struct path *from_path, const struct path *to_path); int (*dentry_init_security)(struct dentry *dentry, int mode, const struct qstr *name, void **ctx, @@ -1854,9 +1833,6 @@ struct security_hook_heads { struct hlist_head sb_mount; struct hlist_head sb_umount; struct hlist_head sb_pivotroot; - struct hlist_head sb_set_mnt_opts; - struct hlist_head sb_clone_mnt_opts; - struct hlist_head sb_parse_opts_str; struct hlist_head move_mount; struct hlist_head dentry_init_security; struct hlist_head dentry_create_files_as;
diff --git a/include/linux/security.h b/include/linux/security.h index 6c1a54e..44368578 100644 --- a/include/linux/security.h +++ b/include/linux/security.h
@@ -185,36 +185,10 @@ static inline const char *kernel_load_data_id_str(enum kernel_load_data_id id) #ifdef CONFIG_SECURITY -struct security_mnt_opts { - char **mnt_opts; - int *mnt_opts_flags; - int num_mnt_opts; -}; - int call_lsm_notifier(enum lsm_event event, void *data); int register_lsm_notifier(struct notifier_block *nb); int unregister_lsm_notifier(struct notifier_block *nb); -static inline void security_init_mnt_opts(struct security_mnt_opts *opts) -{ - opts->mnt_opts = NULL; - opts->mnt_opts_flags = NULL; - opts->num_mnt_opts = 0; -} - -static inline void security_free_mnt_opts(struct security_mnt_opts *opts) -{ - int i; - if (opts->mnt_opts) - for (i = 0; i < opts->num_mnt_opts; i++) - kfree(opts->mnt_opts[i]); - kfree(opts->mnt_opts); - opts->mnt_opts = NULL; - kfree(opts->mnt_opts_flags); - opts->mnt_opts_flags = NULL; - opts->num_mnt_opts = 0; -} - /* prototypes */ extern int security_init(void); @@ -266,15 +240,6 @@ int security_sb_mount(const char *dev_name, const struct path *path, const char *type, unsigned long flags, void *data, size_t data_size); int security_sb_umount(struct vfsmount *mnt, int flags); int security_sb_pivotroot(const struct path *old_path, const struct path *new_path); -int security_sb_set_mnt_opts(struct super_block *sb, - struct security_mnt_opts *opts, - unsigned long kern_flags, - unsigned long *set_kern_flags); -int security_sb_clone_mnt_opts(const struct super_block *oldsb, - struct super_block *newsb, - unsigned long kern_flags, - unsigned long *set_kern_flags); -int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts); int security_move_mount(const struct path *from_path, const struct path *to_path); int security_dentry_init_security(struct dentry *dentry, int mode, const struct qstr *name, void **ctx, @@ -413,8 +378,6 @@ int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen); int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen); int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen); #else /* CONFIG_SECURITY */ -struct security_mnt_opts { -}; static inline int call_lsm_notifier(enum lsm_event event, void *data) { @@ -431,14 +394,6 @@ static inline int unregister_lsm_notifier(struct notifier_block *nb) return 0; } -static inline void security_init_mnt_opts(struct security_mnt_opts *opts) -{ -} - -static inline void security_free_mnt_opts(struct security_mnt_opts *opts) -{ -} - /* * This is the default capabilities functionality. Most of these functions * are just stubbed out, but a few must call the proper capable code. @@ -629,27 +584,6 @@ static inline int security_sb_pivotroot(const struct path *old_path, return 0; } -static inline int security_sb_set_mnt_opts(struct super_block *sb, - struct security_mnt_opts *opts, - unsigned long kern_flags, - unsigned long *set_kern_flags) -{ - return 0; -} - -static inline int security_sb_clone_mnt_opts(const struct super_block *oldsb, - struct super_block *newsb, - unsigned long kern_flags, - unsigned long *set_kern_flags) -{ - return 0; -} - -static inline int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts) -{ - return 0; -} - static inline int security_move_mount(const struct path *from_path, const struct path *to_path) {
diff --git a/security/security.c b/security/security.c index 70625ab..54eac40 100644 --- a/security/security.c +++ b/security/security.c
@@ -453,33 +453,6 @@ int security_sb_pivotroot(const struct path *old_path, const struct path *new_pa return call_int_hook(sb_pivotroot, 0, old_path, new_path); } -int security_sb_set_mnt_opts(struct super_block *sb, - struct security_mnt_opts *opts, - unsigned long kern_flags, - unsigned long *set_kern_flags) -{ - return call_int_hook(sb_set_mnt_opts, - opts->num_mnt_opts ? -EOPNOTSUPP : 0, sb, - opts, kern_flags, set_kern_flags); -} -EXPORT_SYMBOL(security_sb_set_mnt_opts); - -int security_sb_clone_mnt_opts(const struct super_block *oldsb, - struct super_block *newsb, - unsigned long kern_flags, - unsigned long *set_kern_flags) -{ - return call_int_hook(sb_clone_mnt_opts, 0, oldsb, newsb, - kern_flags, set_kern_flags); -} -EXPORT_SYMBOL(security_sb_clone_mnt_opts); - -int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts) -{ - return call_int_hook(sb_parse_opts_str, 0, options, opts); -} -EXPORT_SYMBOL(security_sb_parse_opts_str); - int security_move_mount(const struct path *from_path, const struct path *to_path) { return call_int_hook(move_mount, 0, from_path, to_path);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index d24298b..925ede8 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c
@@ -103,6 +103,69 @@ #include "audit.h" #include "avc_ss.h" +/* + * Parameter option indices. Keep this sorted so that it can be used as an + * index into selinux_param_keys[] to look up the option name. + */ +enum { + Opt_context, + Opt_defcontext, + Opt_fscontext, + Opt_rootcontext, + Opt_seclabel, + nr__selinux_params +}; + +static const struct fs_parameter_spec selinux_param_specs[nr__selinux_params] = { + [Opt_context] = { fs_param_is_string }, + [Opt_defcontext] = { fs_param_is_string }, + [Opt_fscontext] = { fs_param_is_string }, + [Opt_rootcontext] = { fs_param_is_string }, + [Opt_seclabel] = { fs_param_is_flag }, +}; + +static const char *const selinux_param_keys[nr__selinux_params] = { + [Opt_context] = "context", + [Opt_defcontext] = "defcontext", + [Opt_fscontext] = "fscontext", + [Opt_rootcontext] = "rootcontext", + [Opt_seclabel] = "seclabel", +}; + +static const struct fs_parameter_description selinux_fs_parameters = { + .name = "SELinux", + .nr_params = nr__selinux_params, + .keys = selinux_param_keys, + .specs = selinux_param_specs, + .no_source = true, +}; + +struct selinux_fs_context { + char *context[nr__selinux_params]; + union { + int sid[nr__selinux_params]; + struct { + u32 context_sid; + u32 defcontext_sid; + u32 fscontext_sid; + u32 __labelsupport; + u32 rootcontext_sid; + }; + + }; + unsigned int flags; +}; + +static const struct constant_table special_fs_sec[] = { + { "cgroup", SE_SBGENFS }, + { "cgroup2", SE_SBGENFS }, + { "debugfs", SE_SBGENFS }, + { "proc", SE_SBGENFS | SE_SBPROC }, + { "pstore", SE_SBGENFS }, + { "sysfs", SE_SBGENFS }, + { "tracefs", SE_SBGENFS }, +}; + struct selinux_state selinux_state; /* SECMARK reference count */ @@ -440,25 +503,15 @@ static inline int inode_doinit(struct inode *inode) return inode_doinit_with_dentry(inode, NULL); } -enum { - Opt_context = 0, - Opt_defcontext = 1, - Opt_fscontext = 2, - Opt_rootcontext = 3, - Opt_seclabel = 4, - nr__selinux_params -}; +static void clear_selinux_fs_context(struct selinux_fs_context *opts) +{ + int i; -#define NUM_SEL_MNT_OPTS (nr__selinux_params - 1) + for (i = 0; i < nr__selinux_params; i++) + kfree(opts->context[i]); +} -static const match_table_t tokens = { - {Opt_context, CONTEXT_STR "=%s"}, - {Opt_fscontext, FSCONTEXT_STR "=%s"}, - {Opt_defcontext, DEFCONTEXT_STR "=%s"}, - {Opt_rootcontext, ROOTCONTEXT_STR "=%s"}, - {Opt_seclabel, SECLABEL_STR}, - {-1, NULL}, -}; +#define NUM_SEL_MNT_OPTS (nr__selinux_params) #define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n" @@ -600,15 +653,11 @@ static int sb_finish_set_opts(struct super_block *sb) * mount options, or whatever. */ static int selinux_get_mnt_opts(const struct super_block *sb, - struct security_mnt_opts *opts) + struct selinux_fs_context *opts) { - int rc = 0, i; struct superblock_security_struct *sbsec = sb->s_security; - char *context = NULL; u32 len; - char tmp; - - security_init_mnt_opts(opts); + int rc, i; if (!(sbsec->flags & SE_SBINITIALIZED)) return -EINVAL; @@ -616,96 +665,47 @@ static int selinux_get_mnt_opts(const struct super_block *sb, if (!selinux_state.initialized) return -EINVAL; - tmp = sbsec->flags & SE_MNTMASK; - /* count the number of mount options for this sb */ - for (i = 0; i < NUM_SEL_MNT_OPTS; i++) { - if (tmp & (1 << i)) - opts->num_mnt_opts++; - } - /* Check if the Label support flag is set */ - if (sbsec->flags & SBLABEL_MNT) - opts->num_mnt_opts++; + /* make sure we always check enough bits to cover the mask */ + BUILD_BUG_ON(SE_MNTMASK >= (1 << NUM_SEL_MNT_OPTS)); - opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC); - if (!opts->mnt_opts) { - rc = -ENOMEM; - goto out_free; - } - - opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts, sizeof(int), GFP_ATOMIC); - if (!opts->mnt_opts_flags) { - rc = -ENOMEM; - goto out_free; - } - - i = 0; - if (sbsec->flags & FSCONTEXT_MNT) { - rc = security_sid_to_context(&selinux_state, sbsec->sid, - &context, &len); - if (rc) - goto out_free; - opts->mnt_opts[i] = context; - opts->mnt_opts_flags[i++] = FSCONTEXT_MNT; - } - if (sbsec->flags & CONTEXT_MNT) { - rc = security_sid_to_context(&selinux_state, - sbsec->mntpoint_sid, - &context, &len); - if (rc) - goto out_free; - opts->mnt_opts[i] = context; - opts->mnt_opts_flags[i++] = CONTEXT_MNT; - } - if (sbsec->flags & DEFCONTEXT_MNT) { - rc = security_sid_to_context(&selinux_state, sbsec->def_sid, - &context, &len); - if (rc) - goto out_free; - opts->mnt_opts[i] = context; - opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT; - } - if (sbsec->flags & ROOTCONTEXT_MNT) { + opts->flags = sbsec->flags & (SE_MNTMASK | SBLABEL_MNT); + if (opts->flags & FSCONTEXT_MNT) + opts->sid[Opt_fscontext] = sbsec->sid; + if (opts->flags & CONTEXT_MNT) + opts->sid[Opt_fscontext] = sbsec->mntpoint_sid; + if (opts->flags & DEFCONTEXT_MNT) + opts->sid[Opt_fscontext] = sbsec->def_sid; + if (opts->flags & ROOTCONTEXT_MNT) { struct dentry *root = sbsec->sb->s_root; struct inode_security_struct *isec = backing_inode_security(root); - rc = security_sid_to_context(&selinux_state, isec->sid, - &context, &len); - if (rc) - goto out_free; - opts->mnt_opts[i] = context; - opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT; - } - if (sbsec->flags & SBLABEL_MNT) { - opts->mnt_opts[i] = NULL; - opts->mnt_opts_flags[i++] = SBLABEL_MNT; + opts->sid[Opt_fscontext] = isec->sid; } - BUG_ON(i != opts->num_mnt_opts); + for (i = 0; i < nr__selinux_params; i++) { + if (!((1 << i) & SE_MNTMASK)) + continue; + rc = security_sid_to_context(&selinux_state, opts->sid[i], + &opts->context[i], &len); + if (rc < 0) + goto out_free; + } return 0; out_free: - security_free_mnt_opts(opts); + clear_selinux_fs_context(opts); return rc; } static int bad_option(struct superblock_security_struct *sbsec, char flag, u32 old_sid, u32 new_sid) { - char mnt_flags = sbsec->flags & SE_MNTMASK; - /* check if the old mount command had the same options */ if (sbsec->flags & SE_SBINITIALIZED) 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->flags & SE_SBINITIALIZED)) - if (mnt_flags & flag) - return 1; return 0; } @@ -713,58 +713,21 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag, * Allow filesystems with binary mount data to explicitly set mount point * labeling information. */ -static int selinux_set_mnt_opts(struct super_block *sb, - struct security_mnt_opts *opts, - unsigned long kern_flags, - unsigned long *set_kern_flags) +static int selinux_set_mnt_opts(struct fs_context *fc) { - const struct cred *cred = current_cred(); - int rc = 0, i; - struct superblock_security_struct *sbsec = sb->s_security; - const char *name = sb->s_type->name; - struct dentry *root = sbsec->sb->s_root; + struct superblock_security_struct *sbsec = fc->root->d_sb->s_security; struct inode_security_struct *root_isec; - u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0; - u32 defcontext_sid = 0; - char **mount_options = opts->mnt_opts; - int *flags = opts->mnt_opts_flags; - int num_opts = opts->num_mnt_opts; + struct selinux_fs_context *opts = fc->security; + const struct cred *cred = current_cred(); + struct dentry *root = sbsec->sb->s_root; + const char *name = fc->fs_type->name; + int rc = 0, i; - mutex_lock(&sbsec->lock); - - if (!selinux_state.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. */ - goto out; - } - rc = -EINVAL; - pr_warn("SELinux: Unable to set superblock options " - "before the security server is initialized\n"); - goto out; - } - if (kern_flags && !set_kern_flags) { - /* Specifying internal flags without providing a place to - * place the results is not allowed */ - rc = -EINVAL; - goto out; - } - - /* - * Binary mount data FS will come through this function twice. Once - * from an explicit call and once from the generic calls from the vfs. - * Since the generic VFS calls will not contain any security mount data - * we need to skip the double mount verification. - * - * This does open a hole in which we will not notice if the first - * mount using this sb set explict options and a second mount using - * this sb does not set any security options. (The first options - * will be used for both mounts) - */ - if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) - && (num_opts == 0)) - goto out; + if (!selinux_state.initialized) + /* Defer initialization until selinux_complete_init, + after the initial policy is loaded and the security + server is ready to handle calls. */ + return 0; root_isec = backing_inode_security_novalidate(root); @@ -773,94 +736,55 @@ static int selinux_set_mnt_opts(struct super_block *sb, * 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; + for (i = 0; i < nr__selinux_params; i++) { + u32 sid = opts->sid[i]; - if (flags[i] == SBLABEL_MNT) + if (!opts->context[i]) continue; - rc = security_context_str_to_sid(&selinux_state, - mount_options[i], &sid, - GFP_KERNEL); - if (rc) { - pr_warn("SELinux: security_context_str_to_sid" - "(%s) failed for (dev %s, type %s) errno=%d\n", - 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)) + switch (i) { + case Opt_fscontext: + if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, 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)) + case Opt_context: + if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, 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)) + case Opt_rootcontext: + if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, 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)) + case Opt_defcontext: + if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid)) goto out_double_mount; - - sbsec->flags |= DEFCONTEXT_MNT; - break; default: - rc = -EINVAL; - goto out; + break; } } + sbsec->flags |= opts->flags; + if (sbsec->flags & SE_SBINITIALIZED) { /* previously mounted with options, but not on this attempt? */ - if ((sbsec->flags & SE_MNTMASK) && !num_opts) + if ((sbsec->flags & SE_MNTMASK) && !opts->flags) goto out_double_mount; - rc = 0; - goto out; + return 0; } - if (strcmp(sb->s_type->name, "proc") == 0) - sbsec->flags |= SE_SBPROC | SE_SBGENFS; - - 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, "cgroup") || - !strcmp(sb->s_type->name, "cgroup2")) - sbsec->flags |= SE_SBGENFS; + sbsec->flags |= lookup_constant(special_fs_sec, name, 0); if (!sbsec->behavior) { /* * Determine the labeling behavior to use for this * filesystem type. */ - rc = security_fs_use(&selinux_state, sb); + rc = security_fs_use(&selinux_state, sbsec->sb); if (rc) { - pr_warn("%s: security_fs_use(%s) returned %d\n", - __func__, sb->s_type->name, rc); - goto out; + errorf(fc, "%s: security_fs_use(%s) returned %d\n", + __func__, name, rc); + return rc; } } @@ -869,15 +793,16 @@ static int selinux_set_mnt_opts(struct super_block *sb, * explicitly whitelisted, then no contexts are allowed on the command * line and security labels must be ignored. */ - if (sb->s_user_ns != &init_user_ns && - strcmp(sb->s_type->name, "tmpfs") && - strcmp(sb->s_type->name, "ramfs") && - strcmp(sb->s_type->name, "devpts")) { - if (context_sid || fscontext_sid || rootcontext_sid || - defcontext_sid) { - rc = -EACCES; - goto out; - } + if (fc->user_ns != &init_user_ns && + strcmp(name, "tmpfs") != 0 && + strcmp(name, "ramfs") != 0 && + strcmp(name, "devpts") != 0) { + if (opts->context_sid || + opts->fscontext_sid || + opts->rootcontext_sid || + opts->defcontext_sid) + return -EACCES; + if (sbsec->behavior == SECURITY_FS_USE_XATTR) { sbsec->behavior = SECURITY_FS_USE_MNTPOINT; rc = security_transition_sid(&selinux_state, @@ -886,18 +811,18 @@ static int selinux_set_mnt_opts(struct super_block *sb, SECCLASS_FILE, NULL, &sbsec->mntpoint_sid); if (rc) - goto out; + return rc; } goto out_set_opts; } /* sets the context of the superblock for the fs being mounted. */ - if (fscontext_sid) { - rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred); + if (opts->fscontext_sid) { + rc = may_context_mount_sb_relabel(opts->fscontext_sid, sbsec, cred); if (rc) - goto out; + return rc; - sbsec->sid = fscontext_sid; + sbsec->sid = opts->fscontext_sid; } /* @@ -905,380 +830,102 @@ static int selinux_set_mnt_opts(struct super_block *sb, * sets the label used on all file below the mountpoint, and will set * the superblock context if not already set. */ - if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) { + if (fc->lsm_flags & SECURITY_LSM_NATIVE_LABELS && !opts->context_sid) sbsec->behavior = SECURITY_FS_USE_NATIVE; - *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS; - } + else + fc->lsm_flags &= ~SECURITY_LSM_NATIVE_LABELS; - if (context_sid) { - if (!fscontext_sid) { - rc = may_context_mount_sb_relabel(context_sid, sbsec, - cred); + if (opts->context_sid) { + if (!opts->fscontext_sid) { + rc = may_context_mount_sb_relabel(opts->context_sid, + sbsec, cred); if (rc) - goto out; - sbsec->sid = context_sid; + return rc; + sbsec->sid = opts->context_sid; } else { - rc = may_context_mount_inode_relabel(context_sid, sbsec, - cred); + rc = may_context_mount_inode_relabel(opts->context_sid, + sbsec, cred); if (rc) - goto out; + return rc; } - if (!rootcontext_sid) - rootcontext_sid = context_sid; + if (!opts->rootcontext_sid) + opts->rootcontext_sid = opts->context_sid; - sbsec->mntpoint_sid = context_sid; + sbsec->mntpoint_sid = opts->context_sid; sbsec->behavior = SECURITY_FS_USE_MNTPOINT; } - if (rootcontext_sid) { - rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec, - cred); + if (opts->rootcontext_sid) { + rc = may_context_mount_inode_relabel(opts->rootcontext_sid, + sbsec, cred); if (rc) - goto out; + return rc; - root_isec->sid = rootcontext_sid; + root_isec->sid = opts->rootcontext_sid; root_isec->initialized = LABEL_INITIALIZED; } - if (defcontext_sid) { + if (opts->defcontext_sid) { if (sbsec->behavior != SECURITY_FS_USE_XATTR && - sbsec->behavior != SECURITY_FS_USE_NATIVE) { - rc = -EINVAL; - pr_warn("SELinux: defcontext option is " - "invalid for this filesystem type\n"); - goto out; - } + sbsec->behavior != SECURITY_FS_USE_NATIVE) + return invalf(fc, "SELinux: defcontext option is " + "invalid for this filesystem type\n"); - if (defcontext_sid != sbsec->def_sid) { - rc = may_context_mount_inode_relabel(defcontext_sid, + if (opts->defcontext_sid != sbsec->def_sid) { + rc = may_context_mount_inode_relabel(opts->defcontext_sid, sbsec, cred); if (rc) - goto out; + return rc; } - sbsec->def_sid = defcontext_sid; + sbsec->def_sid = opts->defcontext_sid; } out_set_opts: - rc = sb_finish_set_opts(sb); -out: - mutex_unlock(&sbsec->lock); - return rc; + return sb_finish_set_opts(sbsec->sb); + out_double_mount: - rc = -EINVAL; - pr_warn("SELinux: mount invalid. Same superblock, different " - "security settings for (dev %s, type %s)\n", sb->s_id, name); - goto out; -} - -static int selinux_cmp_sb_context(const struct super_block *oldsb, - const struct super_block *newsb) -{ - struct superblock_security_struct *old = oldsb->s_security; - struct superblock_security_struct *new = newsb->s_security; - char oldflags = old->flags & SE_MNTMASK; - char newflags = new->flags & SE_MNTMASK; - - if (oldflags != newflags) - goto mismatch; - if ((oldflags & FSCONTEXT_MNT) && old->sid != new->sid) - goto mismatch; - if ((oldflags & CONTEXT_MNT) && old->mntpoint_sid != new->mntpoint_sid) - goto mismatch; - if ((oldflags & DEFCONTEXT_MNT) && old->def_sid != new->def_sid) - goto mismatch; - if (oldflags & ROOTCONTEXT_MNT) { - struct inode_security_struct *oldroot = backing_inode_security(oldsb->s_root); - struct inode_security_struct *newroot = backing_inode_security(newsb->s_root); - if (oldroot->sid != newroot->sid) - goto mismatch; - } - return 0; -mismatch: - pr_warn("SELinux: mount invalid. Same superblock, " - "different security settings for (dev %s, " - "type %s)\n", newsb->s_id, newsb->s_type->name); - return -EBUSY; -} - -static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, - struct super_block *newsb, - unsigned long kern_flags, - unsigned long *set_kern_flags) -{ - int rc = 0; - const struct superblock_security_struct *oldsbsec = oldsb->s_security; - struct superblock_security_struct *newsbsec = newsb->s_security; - - int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT); - int set_context = (oldsbsec->flags & CONTEXT_MNT); - int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT); - - /* - * if the parent was able to be mounted it clearly had no special lsm - * mount options. thus we can safely deal with this superblock later - */ - if (!selinux_state.initialized) - return 0; - - /* - * Specifying internal flags without providing a place to - * place the results is not allowed. - */ - if (kern_flags && !set_kern_flags) - return -EINVAL; - - /* how can we clone if the old one wasn't set up?? */ - BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED)); - - /* if fs is reusing a sb, make sure that the contexts match */ - if (newsbsec->flags & SE_SBINITIALIZED) - return selinux_cmp_sb_context(oldsb, newsb); - - mutex_lock(&newsbsec->lock); - - newsbsec->flags = oldsbsec->flags; - - newsbsec->sid = oldsbsec->sid; - newsbsec->def_sid = oldsbsec->def_sid; - newsbsec->behavior = oldsbsec->behavior; - - if (newsbsec->behavior == SECURITY_FS_USE_NATIVE && - !(kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) { - rc = security_fs_use(&selinux_state, newsb); - if (rc) - goto out; - } - - if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !set_context) { - newsbsec->behavior = SECURITY_FS_USE_NATIVE; - *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS; - } - - if (set_context) { - u32 sid = oldsbsec->mntpoint_sid; - - if (!set_fscontext) - newsbsec->sid = sid; - if (!set_rootcontext) { - struct inode_security_struct *newisec = backing_inode_security(newsb->s_root); - newisec->sid = sid; - } - newsbsec->mntpoint_sid = sid; - } - if (set_rootcontext) { - const struct inode_security_struct *oldisec = backing_inode_security(oldsb->s_root); - struct inode_security_struct *newisec = backing_inode_security(newsb->s_root); - - newisec->sid = oldisec->sid; - } - - sb_finish_set_opts(newsb); -out: - mutex_unlock(&newsbsec->lock); - return rc; -} - -static int selinux_parse_opts_str(char *options, - struct security_mnt_opts *opts) -{ - char *p; - char *context = NULL, *defcontext = NULL; - char *fscontext = NULL, *rootcontext = NULL; - int rc, num_mnt_opts = 0; - - opts->num_mnt_opts = 0; - - /* Standard string-based options. */ - while ((p = strsep(&options, "|")) != NULL) { - int token; - substring_t args[MAX_OPT_ARGS]; - - if (!*p) - continue; - - token = match_token(p, tokens, args); - - switch (token) { - case Opt_context: - if (context || defcontext) { - rc = -EINVAL; - pr_warn(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; - pr_warn(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; - pr_warn(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; - pr_warn(SEL_MOUNT_FAIL_MSG); - goto out_err; - } - defcontext = match_strdup(&args[0]); - if (!defcontext) { - rc = -ENOMEM; - goto out_err; - } - break; - case Opt_seclabel: - break; - default: - rc = -EINVAL; - pr_warn("SELinux: unknown mount option\n"); - goto out_err; - - } - } - - rc = -ENOMEM; - opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_KERNEL); - if (!opts->mnt_opts) - goto out_err; - - opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), - GFP_KERNEL); - if (!opts->mnt_opts_flags) - goto out_err; - - if (fscontext) { - opts->mnt_opts[num_mnt_opts] = fscontext; - opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT; - } - if (context) { - opts->mnt_opts[num_mnt_opts] = context; - opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT; - } - if (rootcontext) { - opts->mnt_opts[num_mnt_opts] = rootcontext; - opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT; - } - if (defcontext) { - opts->mnt_opts[num_mnt_opts] = defcontext; - opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT; - } - - opts->num_mnt_opts = num_mnt_opts; - return 0; - -out_err: - security_free_mnt_opts(opts); - kfree(context); - kfree(defcontext); - kfree(fscontext); - kfree(rootcontext); - return rc; -} -/* - * string mount options parsing and call set the sbsec - */ -static int superblock_doinit(struct super_block *sb, void *data) -{ - int rc = 0; - char *options = data; - struct security_mnt_opts opts; - - security_init_mnt_opts(&opts); - - if (!data) - goto out; - - BUG_ON(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA); - - rc = selinux_parse_opts_str(options, &opts); - if (rc) - goto out_err; - -out: - rc = selinux_set_mnt_opts(sb, &opts, 0, NULL); - -out_err: - security_free_mnt_opts(&opts); - return rc; + return invalf(fc, "SELinux: mount invalid. Same superblock, different " + "security settings for (dev %s, type %s)\n", + sbsec->sb->s_id, name); } static void selinux_write_opts(struct seq_file *m, - struct security_mnt_opts *opts) + struct selinux_fs_context *opts) { int i; - char *prefix; - for (i = 0; i < opts->num_mnt_opts; i++) { - char *has_comma; + for (i = 0; i < nr__selinux_params; i++) { + const char *prefix = selinux_param_keys[i]; + char *context = opts->context[i]; + bool has_comma = false; - if (opts->mnt_opts[i]) - has_comma = strchr(opts->mnt_opts[i], ','); - else - has_comma = NULL; - - switch (opts->mnt_opts_flags[i]) { - case CONTEXT_MNT: - prefix = CONTEXT_STR; - break; - case FSCONTEXT_MNT: - prefix = FSCONTEXT_STR; - break; - case ROOTCONTEXT_MNT: - prefix = ROOTCONTEXT_STR; - break; - case DEFCONTEXT_MNT: - prefix = DEFCONTEXT_STR; - break; - case SBLABEL_MNT: - seq_putc(m, ','); - seq_puts(m, SECLABEL_STR); + if (!(opts->flags & (1 << i))) continue; - default: - BUG(); - return; - }; + /* we need a comma before each option */ seq_putc(m, ','); seq_puts(m, prefix); - seq_putc(m, '='); - if (has_comma) - seq_putc(m, '\"'); - seq_escape(m, opts->mnt_opts[i], "\"\n\\"); - if (has_comma) - seq_putc(m, '\"'); + + if (i != Opt_seclabel) { + seq_putc(m, '='); + + has_comma = strchr(context, ','); + if (has_comma) + seq_putc(m, '\"'); + seq_escape(m, context, "\"\n\\"); + if (has_comma) + seq_putc(m, '\"'); + } } } static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb) { - struct security_mnt_opts opts; + struct selinux_fs_context opts; int rc; + memset(&opts, 0, sizeof(opts)); rc = selinux_get_mnt_opts(sb, &opts); if (rc) { /* before policy load we may get EINVAL, don't show anything */ @@ -1289,8 +936,7 @@ static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb) selinux_write_opts(m, &opts); - security_free_mnt_opts(&opts); - + clear_selinux_fs_context(&opts); return rc; } @@ -2746,97 +2392,6 @@ static void selinux_sb_free_security(struct super_block *sb) superblock_free_security(sb); } -static inline int match_prefix(char *prefix, int plen, char *option, int olen) -{ - if (plen > olen) - return 0; - - return !memcmp(prefix, option, plen); -} - -static inline int selinux_option(char *option, int len) -{ - return (match_prefix(CONTEXT_STR"=", sizeof(CONTEXT_STR)-1, option, len) || - match_prefix(FSCONTEXT_STR"=", sizeof(FSCONTEXT_STR)-1, option, len) || - match_prefix(DEFCONTEXT_STR"=", sizeof(DEFCONTEXT_STR)-1, option, len) || - match_prefix(ROOTCONTEXT_STR"=", sizeof(ROOTCONTEXT_STR)-1, option, len) || - match_prefix(SECLABEL_STR"=", sizeof(SECLABEL_STR)-1, option, len)); -} - -static inline void take_option(char **to, char *from, int *first, int len) -{ - if (!*first) { - **to = ','; - *to += 1; - } else - *first = 0; - memcpy(*to, from, len); - *to += len; -} - -static inline void take_selinux_option(char **to, char *from, int *first, - int len) -{ - int current_size = 0; - - if (!*first) { - **to = '|'; - *to += 1; - } else - *first = 0; - - while (current_size < len) { - if (*from != '"') { - **to = *from; - *to += 1; - } - from += 1; - current_size += 1; - } -} - -static int selinux_sb_copy_data(char *orig, size_t data_size, char *copy) -{ - int fnosec, fsec, rc = 0; - char *in_save, *in_curr, *in_end; - char *sec_curr, *nosec_save, *nosec; - int open_quote = 0; - - in_curr = orig; - sec_curr = copy; - - nosec = (char *)get_zeroed_page(GFP_KERNEL); - if (!nosec) { - rc = -ENOMEM; - goto out; - } - - nosec_save = nosec; - fnosec = fsec = 1; - in_save = in_end = orig; - - do { - if (*in_end == '"') - open_quote = !open_quote; - if ((*in_end == ',' && open_quote == 0) || - *in_end == '\0') { - int len = in_end - in_curr; - - if (selinux_option(in_curr, len)) - take_selinux_option(&sec_curr, in_curr, &fsec, len); - else - take_option(&nosec, in_curr, &fnosec, len); - - in_curr = in_end + 1; - } - } while (*in_end++); - - strcpy(in_save, nosec_save); - free_page((unsigned long)nosec_save); -out: - return rc; -} - static int selinux_sb_statfs(struct dentry *dentry) { const struct cred *cred = current_cred(); @@ -2876,7 +2431,13 @@ static int selinux_umount(struct vfsmount *mnt, int flags) static int selinux_fs_context_alloc(struct fs_context *fc, struct dentry *reference) { - struct security_mnt_opts *opts; + struct selinux_fs_context *opts; + + BUILD_BUG_ON(CONTEXT_MNT != (1 << Opt_context) || + DEFCONTEXT_MNT != (1 << Opt_defcontext) || + FSCONTEXT_MNT != (1 << Opt_fscontext) || + SBLABEL_MNT != (1 << Opt_seclabel) || + ROOTCONTEXT_MNT != (1 << Opt_rootcontext)); opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) @@ -2889,151 +2450,85 @@ static int selinux_fs_context_alloc(struct fs_context *fc, static int selinux_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc) { - const struct security_mnt_opts *src = src_fc->security; - struct security_mnt_opts *opts; - int i, n; + const struct selinux_fs_context *src = src_fc->security; + struct selinux_fs_context *opts; + int i; opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) return -ENOMEM; fc->security = opts; - if (!src || !src->num_mnt_opts) - return 0; - n = opts->num_mnt_opts = src->num_mnt_opts; - - if (src->mnt_opts) { - opts->mnt_opts = kcalloc(n, sizeof(char *), GFP_KERNEL); - if (!opts->mnt_opts) + for (i = 0; i < nr__selinux_params; i++) { + if (!src->context[i]) + continue; + opts->context[i] = kstrdup(src->context[i], GFP_KERNEL); + if (!opts->context[i]) return -ENOMEM; - - for (i = 0; i < n; i++) { - if (src->mnt_opts[i]) { - opts->mnt_opts[i] = kstrdup(src->mnt_opts[i], - GFP_KERNEL); - if (!opts->mnt_opts[i]) - return -ENOMEM; - } - } + opts->sid[i] = src->sid[i]; } - if (src->mnt_opts_flags) { - opts->mnt_opts_flags = kmemdup(src->mnt_opts_flags, - n * sizeof(int), GFP_KERNEL); - if (!opts->mnt_opts_flags) - return -ENOMEM; - } - + opts->flags = src->flags; return 0; } static void selinux_fs_context_free(struct fs_context *fc) { - struct security_mnt_opts *opts = fc->security; + struct selinux_fs_context *opts = fc->security; if (opts) { - security_free_mnt_opts(opts); + clear_selinux_fs_context(opts); fc->security = NULL; } } -static const struct fs_parameter_spec selinux_param_specs[nr__selinux_params] = { - [Opt_context] = { fs_param_is_string }, - [Opt_defcontext] = { fs_param_is_string }, - [Opt_fscontext] = { fs_param_is_string }, - [Opt_rootcontext] = { fs_param_is_string }, - [Opt_seclabel] = { fs_param_is_flag }, -}; - -static const char *const selinux_param_keys[nr__selinux_params] = { - [Opt_context] = CONTEXT_STR, - [Opt_defcontext] = DEFCONTEXT_STR, - [Opt_fscontext] = FSCONTEXT_STR, - [Opt_rootcontext] = ROOTCONTEXT_STR, - [Opt_seclabel] = SECLABEL_STR, -}; - -static const struct fs_parameter_description selinux_fs_parameters = { - .name = "SELinux", - .nr_params = nr__selinux_params, - .keys = selinux_param_keys, - .specs = selinux_param_specs, - .no_source = true, -}; - +/* + * Parse a superblock configuration parameter to see if it belongs to or is + * relevant to SELinux. We return 1 to claim it. + */ static int selinux_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param) { - struct security_mnt_opts *opts = fc->security; + struct selinux_fs_context *opts = fc->security; struct fs_parse_result result; - unsigned int have; - char **oo; - int opt, ctx, i, *of; + int opt; opt = fs_parse(fc, &selinux_fs_parameters, param, &result); if (opt < 0) return opt; - have = 0; - for (i = 0; i < opts->num_mnt_opts; i++) - have |= 1 << opts->mnt_opts_flags[i]; - if (have & (1 << opt)) - return -EINVAL; + if (opts->context[opt]) + return invalf(fc, "SELinux: Duplicate %s specification", + param->key); switch (opt) { case Opt_context: - if (have & (1 << Opt_defcontext)) - goto incompatible; - ctx = CONTEXT_MNT; - goto copy_context_string; + if (opts->context[Opt_defcontext]) + return invalf(fc, "SELinux: context not compatible with defcontext"); + goto save_context_string; case Opt_fscontext: - ctx = FSCONTEXT_MNT; - goto copy_context_string; - case Opt_rootcontext: - ctx = ROOTCONTEXT_MNT; - goto copy_context_string; + goto save_context_string; case Opt_defcontext: - if (have & (1 << Opt_context)) - goto incompatible; - ctx = DEFCONTEXT_MNT; - goto copy_context_string; + if (opts->context[Opt_context]) + return invalf(fc, "SELinux: defcontext not compatible with context"); + goto save_context_string; case Opt_seclabel: + opts->flags |= SBLABEL_MNT; return 1; default: return -EINVAL; } -copy_context_string: - if (opts->num_mnt_opts > 3) - return -EINVAL; - - of = krealloc(opts->mnt_opts_flags, - (opts->num_mnt_opts + 1) * sizeof(int), GFP_KERNEL); - if (!of) - return -ENOMEM; - of[opts->num_mnt_opts] = 0; - opts->mnt_opts_flags = of; - - oo = krealloc(opts->mnt_opts, - (opts->num_mnt_opts + 1) * sizeof(char *), GFP_KERNEL); - if (!oo) - return -ENOMEM; - oo[opts->num_mnt_opts] = NULL; - opts->mnt_opts = oo; - - opts->mnt_opts[opts->num_mnt_opts] = param->string; - opts->mnt_opts_flags[opts->num_mnt_opts] = ctx; - opts->num_mnt_opts++; +save_context_string: + opts->flags |= 1 << opt; + opts->context[result.key] = param->string; param->string = NULL; return 1; - -incompatible: - return -EINVAL; } /* @@ -3042,81 +2537,99 @@ static int selinux_fs_context_parse_param(struct fs_context *fc, */ static int selinux_validate_for_sb_reconfigure(struct fs_context *fc) { + struct selinux_fs_context *opts = fc->security; struct super_block *sb = fc->root->d_sb; struct superblock_security_struct *sbsec = sb->s_security; - struct security_mnt_opts *opts = fc->security; - int rc, i, *flags; - char **mount_options; + struct inode_security_struct *root_isec; + int i; if (!(sbsec->flags & SE_SBINITIALIZED)) return 0; - mount_options = opts->mnt_opts; - flags = opts->mnt_opts_flags; + if ((opts->flags & ~sbsec->flags) & (SE_MNTMASK | SBLABEL_MNT)) + goto cant_change; + + for (i = 0; i < nr__selinux_params; i++) { + const char *ctx = opts->context[i]; + u32 sid = opts->sid[i]; - for (i = 0; i < opts->num_mnt_opts; i++) { - u32 sid; - - if (flags[i] == SBLABEL_MNT) + if (!ctx) continue; - rc = security_context_str_to_sid(&selinux_state, mount_options[i], - &sid, GFP_KERNEL); - if (rc) { - pr_warn("SELinux: security_context_str_to_sid" - "(%s) failed for (dev %s, type %s) errno=%d\n", - mount_options[i], sb->s_id, sb->s_type->name, rc); - goto inval; - } - - switch (flags[i]) { - case FSCONTEXT_MNT: - if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid)) - goto bad_option; + switch (i) { + case Opt_fscontext: + if (sid != sbsec->sid) + goto cant_change; break; - case CONTEXT_MNT: - if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid)) - goto bad_option; + case Opt_context: + if (sid != sbsec->mntpoint_sid) + goto cant_change; break; - case ROOTCONTEXT_MNT: { - struct inode_security_struct *root_isec; + case Opt_rootcontext: root_isec = backing_inode_security(sb->s_root); - - if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid)) - goto bad_option; + if (sid != root_isec->sid) + goto cant_change; break; - } - case DEFCONTEXT_MNT: - if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid)) - goto bad_option; + case Opt_defcontext: + if (sid != sbsec->def_sid) + goto cant_change; break; default: - goto inval; + return -EINVAL; } } - rc = 0; -out: - return rc; + return 0; -bad_option: - pr_warn("SELinux: unable to change security options " - "during remount (dev %s, type=%s)\n", - sb->s_id, sb->s_type->name); -inval: - rc = -EINVAL; - goto out; +cant_change: + return invalf(fc, "SELinux: unable to change security options " + "during remount (dev %s, type=%s)", + sb->s_id, sb->s_type->name); } /* - * Validate the security context assembled from the option data supplied to - * mount. + * Validate the security context assembled from the parameters supplied to + * mount and convert any text labels into sids. */ static int selinux_fs_context_validate(struct fs_context *fc) { - if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) + struct selinux_fs_context *opts = fc->security; + int rc, i; + + if (!opts || !opts->flags) + return 0; + + if (!selinux_state.initialized) { + pr_warn("SELinux: Unable to set superblock options " + "before the security server is initialized\n"); + return -EINVAL; + } + + for (i = 0; i < nr__selinux_params; i++) { + const char *ctx = opts->context[i]; + u32 sid; + + if (!ctx) + continue; + + rc = security_context_str_to_sid(&selinux_state, ctx, &sid, + GFP_KERNEL); + if (rc) + goto sid_not_found; + } + + switch (fc->purpose) { + case FS_CONTEXT_FOR_RECONFIGURE: return selinux_validate_for_sb_reconfigure(fc); - return 0; + default: + return 0; + } + +sid_not_found: + return invalf(fc, "SELinux: security_context_str_to_sid" + "(%s) failed for (dev %s, type %s) errno=%d", + selinux_param_keys[i], + fc->root->d_sb->s_id, fc->fs_type->name, rc); } /* @@ -3124,11 +2637,14 @@ static int selinux_fs_context_validate(struct fs_context *fc) */ static int selinux_sb_get_tree(struct fs_context *fc) { - const struct cred *cred = current_cred(); + struct superblock_security_struct *sbsec = fc->root->d_sb->s_security; struct common_audit_data ad; + const struct cred *cred = current_cred(); int rc; - rc = selinux_set_mnt_opts(fc->root->d_sb, fc->security, 0, NULL); + mutex_lock(&sbsec->lock); + rc = selinux_set_mnt_opts(fc); + mutex_unlock(&sbsec->lock); if (rc) return rc; @@ -7109,9 +6625,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(sb_statfs, selinux_sb_statfs), LSM_HOOK_INIT(sb_mount, selinux_mount), LSM_HOOK_INIT(sb_umount, selinux_umount), - LSM_HOOK_INIT(sb_set_mnt_opts, selinux_set_mnt_opts), - LSM_HOOK_INIT(sb_clone_mnt_opts, selinux_sb_clone_mnt_opts), - LSM_HOOK_INIT(sb_parse_opts_str, selinux_parse_opts_str), LSM_HOOK_INIT(dentry_init_security, selinux_dentry_init_security), LSM_HOOK_INIT(dentry_create_files_as, selinux_dentry_create_files_as), @@ -7372,9 +6885,78 @@ static __init int selinux_init(void) return 0; } +/* + * string mount options parsing and call set the sbsec + */ +static int init_one_superblock(struct super_block *sb) +{ + struct superblock_security_struct *sbsec = sb->s_security; + const char *name = sb->s_type->name; + int rc = 0; + + if (!selinux_state.initialized) + /* Defer initialization until selinux_complete_init, + after the initial policy is loaded and the security + server is ready to handle calls. */ + return 0; + + if (sbsec->flags & SE_SBINITIALIZED) { + if ((sbsec->flags & SE_MNTMASK)) + goto out_double_mount; + return 0; + } + + sbsec->flags |= lookup_constant(special_fs_sec, sb->s_type->name, 0); + + if (!sbsec->behavior) { + /* + * Determine the labeling behavior to use for this + * filesystem type. + */ + rc = security_fs_use(&selinux_state, sb); + if (rc) { + pr_warn("%s: security_fs_use(%s) returned %d\n", + __func__, sb->s_type->name, rc); + return rc; + } + } + + /* + * If this is a user namespace mount and the filesystem type is not + * explicitly whitelisted, then no contexts are allowed on the command + * line and security labels must be ignored. + */ + if (sb->s_user_ns != &init_user_ns && + strcmp(sb->s_type->name, "tmpfs") != 0 && + strcmp(sb->s_type->name, "ramfs") != 0 && + strcmp(sb->s_type->name, "devpts") != 0) { + if (sbsec->behavior == SECURITY_FS_USE_XATTR) { + sbsec->behavior = SECURITY_FS_USE_MNTPOINT; + rc = security_transition_sid(&selinux_state, + current_sid(), + current_sid(), + SECCLASS_FILE, NULL, + &sbsec->mntpoint_sid); + if (rc) + return rc; + } + } + + return sb_finish_set_opts(sb); + +out_double_mount: + pr_warn("SELinux: mount invalid. Same superblock, different " + "security settings for (dev %s, type %s)\n", sb->s_id, name); + return -EINVAL; +} + static void delayed_superblock_init(struct super_block *sb, void *unused) { - superblock_doinit(sb, NULL); + struct superblock_security_struct *sbsec = sb->s_security; + + mutex_lock(&sbsec->lock); + init_one_superblock(sb); + mutex_unlock(&sbsec->lock); } void selinux_complete_init(void)
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 7c10028..829dd85 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h
@@ -47,24 +47,23 @@ /* Mask for just the mount related flags */ #define SE_MNTMASK 0x0f -/* Super block security struct flags for mount options */ -/* BE CAREFUL, these need to be the low order bits for selinux_get_mnt_opts */ + +/* + * Super block security struct flags for mount options. These must + * match the Opt_* enum values so that those can be bit-shifted to + * these. + */ #define CONTEXT_MNT 0x01 #define DEFCONTEXT_MNT 0x02 #define FSCONTEXT_MNT 0x04 #define ROOTCONTEXT_MNT 0x08 #define SBLABEL_MNT 0x10 + /* Non-mount related flags */ #define SE_SBINITIALIZED 0x0100 #define SE_SBPROC 0x0200 #define SE_SBGENFS 0x0400 -#define CONTEXT_STR "context" -#define FSCONTEXT_STR "fscontext" -#define ROOTCONTEXT_STR "rootcontext" -#define DEFCONTEXT_STR "defcontext" -#define SECLABEL_STR "seclabel" - struct netlbl_lsm_secattr; extern int selinux_enabled;
diff --git a/security/smack/smack.h b/security/smack/smack.h index 891a307..c1e4771 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h
@@ -191,27 +191,6 @@ struct smack_known_list_elem { #define FSROOT_MNT 0x08 #define FSTRANS_MNT 0x10 -#define NUM_SMK_MNT_OPTS 5 - -enum { - Opt_error = -1, - Opt_fsdefault = 0, - Opt_fsfloor = 1, - Opt_fshat = 2, - Opt_fsroot = 3, - Opt_fstransmute = 4, - nr__smack_params -}; - -/* - * Mount options - */ -#define SMK_FSDEFAULT "smackfsdef" -#define SMK_FSFLOOR "smackfsfloor" -#define SMK_FSHAT "smackfshat" -#define SMK_FSROOT "smackfsroot" -#define SMK_FSTRANS "smackfstransmute" - #define SMACK_DELETE_OPTION "-DELETE" #define SMACK_CIPSO_OPTION "-CIPSO"
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 1bf6e6e..f82a39f 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c
@@ -54,6 +54,15 @@ #define SMK_RECEIVING 1 #define SMK_SENDING 2 +enum { + Opt_fsdefault = 0, + Opt_fsfloor = 1, + Opt_fshat = 2, + Opt_fsroot = 3, + Opt_fstransmute = 4, + nr__smack_params +}; + #ifdef SMACK_IPV6_PORT_LABELING DEFINE_MUTEX(smack_ipv6_lock); static LIST_HEAD(smk_ipv6_port_list); @@ -61,15 +70,6 @@ static LIST_HEAD(smk_ipv6_port_list); static struct kmem_cache *smack_inode_cache; int smack_enabled; -static const match_table_t smk_mount_tokens = { - {Opt_fsdefault, SMK_FSDEFAULT "=%s"}, - {Opt_fsfloor, SMK_FSFLOOR "=%s"}, - {Opt_fshat, SMK_FSHAT "=%s"}, - {Opt_fsroot, SMK_FSROOT "=%s"}, - {Opt_fstransmute, SMK_FSTRANS "=%s"}, - {Opt_error, NULL}, -}; - #ifdef CONFIG_SECURITY_SMACK_BRINGUP static char *smk_bu_mess[] = { "Bringup Error", /* Unused */ @@ -539,8 +539,7 @@ struct smack_fs_context { char *fsroot; char *fstransmute; }; - char *ptrs[5]; - + char *labels[nr__smack_params]; }; struct superblock_smack *sbsp; struct inode_smack *isp; @@ -557,8 +556,8 @@ static void smack_fs_context_free(struct fs_context *fc) int i; if (ctx) { - for (i = 0; i < ARRAY_SIZE(ctx->ptrs); i++) - kfree(ctx->ptrs[i]); + for (i = 0; i < ARRAY_SIZE(ctx->labels); i++) + kfree(ctx->labels[i]); kfree(ctx->isp); kfree(ctx->sbsp); kfree(ctx); @@ -643,10 +642,10 @@ static int smack_fs_context_dup(struct fs_context *fc, if (!dst->sbsp) goto nomem_free; - for (i = 0; i < ARRAY_SIZE(dst->ptrs); i++) { - if (src->ptrs[i]) { - dst->ptrs[i] = kstrdup(src->ptrs[i], GFP_KERNEL); - if (!dst->ptrs[i]) + for (i = 0; i < ARRAY_SIZE(dst->labels); i++) { + if (src->labels[i]) { + dst->labels[i] = kstrdup(src->labels[i], GFP_KERNEL); + if (!dst->labels[i]) goto nomem_free; } } @@ -668,11 +667,11 @@ static const struct fs_parameter_spec smack_param_specs[nr__smack_params] = { }; static const char *const smack_param_keys[nr__smack_params] = { - [Opt_fsdefault] = SMK_FSDEFAULT, - [Opt_fsfloor] = SMK_FSFLOOR, - [Opt_fshat] = SMK_FSHAT, - [Opt_fsroot] = SMK_FSROOT, - [Opt_fstransmute] = SMK_FSTRANS, + [Opt_fsdefault] = "smackfsdef", + [Opt_fsfloor] = "smackfsfloor", + [Opt_fshat] = "smackfshat", + [Opt_fsroot] = "smackfsroot", + [Opt_fstransmute] = "smackfstransmute", }; static const struct fs_parameter_description smack_fs_parameters = { @@ -705,41 +704,12 @@ static int smack_fs_context_parse_param(struct fs_context *fc, if (opt < 0) return opt; - switch (opt) { - case Opt_fsdefault: - if (ctx->fsdefault) - goto error_dup; - ctx->fsdefault = param->string; - break; - case Opt_fsfloor: - if (ctx->fsfloor) - goto error_dup; - ctx->fsfloor = param->string; - break; - case Opt_fshat: - if (ctx->fshat) - goto error_dup; - ctx->fshat = param->string; - break; - case Opt_fsroot: - if (ctx->fsroot) - goto error_dup; - ctx->fsroot = param->string; - break; - case Opt_fstransmute: - if (ctx->fstransmute) - goto error_dup; - ctx->fstransmute = param->string; - break; - default: - return invalf(fc, "Smack: unknown mount option\n"); - } + if (ctx->labels[opt]) + return invalf(fc, "Smack: duplicate mount option\n"); + ctx->labels[opt] = param->string; param->string = NULL; return 0; - -error_dup: - return invalf(fc, "Smack: duplicate mount option\n"); } /** @@ -883,242 +853,6 @@ static void smack_sb_free_security(struct super_block *sb) } /** - * smack_parse_opts_str - parse Smack specific mount options - * @options: mount options string - * @opts: where to store converted mount opts - * - * Returns 0 on success or -ENOMEM on error. - * - * converts Smack specific mount options to generic security option format - */ -static int smack_parse_opts_str(char *options, - struct security_mnt_opts *opts) -{ - char *p; - char *fsdefault = NULL; - char *fsfloor = NULL; - char *fshat = NULL; - char *fsroot = NULL; - char *fstransmute = NULL; - int rc = -ENOMEM; - int num_mnt_opts = 0; - int token; - - opts->num_mnt_opts = 0; - - if (!options) - return 0; - - while ((p = strsep(&options, ",")) != NULL) { - substring_t args[MAX_OPT_ARGS]; - - if (!*p) - continue; - - token = match_token(p, smk_mount_tokens, args); - - switch (token) { - case Opt_fsdefault: - if (fsdefault) - goto out_opt_err; - fsdefault = match_strdup(&args[0]); - if (!fsdefault) - goto out_err; - break; - case Opt_fsfloor: - if (fsfloor) - goto out_opt_err; - fsfloor = match_strdup(&args[0]); - if (!fsfloor) - goto out_err; - break; - case Opt_fshat: - if (fshat) - goto out_opt_err; - fshat = match_strdup(&args[0]); - if (!fshat) - goto out_err; - break; - case Opt_fsroot: - if (fsroot) - goto out_opt_err; - fsroot = match_strdup(&args[0]); - if (!fsroot) - goto out_err; - break; - case Opt_fstransmute: - if (fstransmute) - goto out_opt_err; - fstransmute = match_strdup(&args[0]); - if (!fstransmute) - goto out_err; - break; - default: - rc = -EINVAL; - pr_warn("Smack: unknown mount option\n"); - goto out_err; - } - } - - opts->mnt_opts = kcalloc(NUM_SMK_MNT_OPTS, sizeof(char *), GFP_KERNEL); - if (!opts->mnt_opts) - goto out_err; - - opts->mnt_opts_flags = kcalloc(NUM_SMK_MNT_OPTS, sizeof(int), - GFP_KERNEL); - if (!opts->mnt_opts_flags) - goto out_err; - - if (fsdefault) { - opts->mnt_opts[num_mnt_opts] = fsdefault; - opts->mnt_opts_flags[num_mnt_opts++] = FSDEFAULT_MNT; - } - if (fsfloor) { - opts->mnt_opts[num_mnt_opts] = fsfloor; - opts->mnt_opts_flags[num_mnt_opts++] = FSFLOOR_MNT; - } - if (fshat) { - opts->mnt_opts[num_mnt_opts] = fshat; - opts->mnt_opts_flags[num_mnt_opts++] = FSHAT_MNT; - } - if (fsroot) { - opts->mnt_opts[num_mnt_opts] = fsroot; - opts->mnt_opts_flags[num_mnt_opts++] = FSROOT_MNT; - } - if (fstransmute) { - opts->mnt_opts[num_mnt_opts] = fstransmute; - opts->mnt_opts_flags[num_mnt_opts++] = FSTRANS_MNT; - } - - opts->num_mnt_opts = num_mnt_opts; - return 0; - -out_opt_err: - rc = -EINVAL; - pr_warn("Smack: duplicate mount options\n"); - -out_err: - kfree(fsdefault); - kfree(fsfloor); - kfree(fshat); - kfree(fsroot); - kfree(fstransmute); - return rc; -} - -/** - * smack_set_mnt_opts - set Smack specific mount options - * @sb: the file system superblock - * @opts: Smack mount options - * @kern_flags: mount option from kernel space or user space - * @set_kern_flags: where to store converted mount opts - * - * Returns 0 on success, an error code on failure - * - * Allow filesystems with binary mount data to explicitly set Smack mount - * labels. - */ -static int smack_set_mnt_opts(struct super_block *sb, - struct security_mnt_opts *opts, - unsigned long kern_flags, - unsigned long *set_kern_flags) -{ - struct dentry *root = sb->s_root; - struct inode *inode = d_backing_inode(root); - struct superblock_smack *sp = sb->s_security; - struct inode_smack *isp; - struct smack_known *skp; - int i; - int num_opts = opts->num_mnt_opts; - int transmute = 0; - - if (sp->smk_flags & SMK_SB_INITIALIZED) - return 0; - - if (!smack_privileged(CAP_MAC_ADMIN)) { - /* - * Unprivileged mounts don't get to specify Smack values. - */ - if (num_opts) - return -EPERM; - /* - * Unprivileged mounts get root and default from the caller. - */ - skp = smk_of_current(); - sp->smk_root = skp; - sp->smk_default = skp; - /* - * For a handful of fs types with no user-controlled - * backing store it's okay to trust security labels - * in the filesystem. The rest are untrusted. - */ - if (sb->s_user_ns != &init_user_ns && - sb->s_magic != SYSFS_MAGIC && sb->s_magic != TMPFS_MAGIC && - sb->s_magic != RAMFS_MAGIC) { - transmute = 1; - sp->smk_flags |= SMK_SB_UNTRUSTED; - } - } - - sp->smk_flags |= SMK_SB_INITIALIZED; - - for (i = 0; i < num_opts; i++) { - switch (opts->mnt_opts_flags[i]) { - case FSDEFAULT_MNT: - skp = smk_import_entry(opts->mnt_opts[i], 0); - if (IS_ERR(skp)) - return PTR_ERR(skp); - sp->smk_default = skp; - break; - case FSFLOOR_MNT: - skp = smk_import_entry(opts->mnt_opts[i], 0); - if (IS_ERR(skp)) - return PTR_ERR(skp); - sp->smk_floor = skp; - break; - case FSHAT_MNT: - skp = smk_import_entry(opts->mnt_opts[i], 0); - if (IS_ERR(skp)) - return PTR_ERR(skp); - sp->smk_hat = skp; - break; - case FSROOT_MNT: - skp = smk_import_entry(opts->mnt_opts[i], 0); - if (IS_ERR(skp)) - return PTR_ERR(skp); - sp->smk_root = skp; - break; - case FSTRANS_MNT: - skp = smk_import_entry(opts->mnt_opts[i], 0); - if (IS_ERR(skp)) - return PTR_ERR(skp); - sp->smk_root = skp; - transmute = 1; - break; - default: - break; - } - } - - /* - * Initialize the root inode. - */ - isp = inode->i_security; - if (isp == NULL) { - isp = new_inode_smack(sp->smk_root); - if (isp == NULL) - return -ENOMEM; - inode->i_security = isp; - } else - isp->smk_inode = sp->smk_root; - - if (transmute) - isp->smk_flags |= SMK_INODE_TRANSMUTE; - - return 0; -} - -/** * smack_sb_statfs - Smack check on statfs * @dentry: identifies the file system in question * @@ -4912,8 +4646,6 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(sb_alloc_security, smack_sb_alloc_security), LSM_HOOK_INIT(sb_free_security, smack_sb_free_security), LSM_HOOK_INIT(sb_statfs, smack_sb_statfs), - LSM_HOOK_INIT(sb_set_mnt_opts, smack_set_mnt_opts), - LSM_HOOK_INIT(sb_parse_opts_str, smack_parse_opts_str), LSM_HOOK_INIT(bprm_set_creds, smack_bprm_set_creds),
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index e637ce7..2bf22f3 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h
@@ -975,8 +975,7 @@ int tomoyo_mount_permission_fc(struct fs_context *fc, const struct path *mountpoint, unsigned int mnt_flags); int tomoyo_mount_permission(const char *dev_name, const struct path *path, - const char *type, unsigned long flags, - void *data_page); + const char *type, unsigned long flags); int tomoyo_open_control(const u8 type, struct file *file); int tomoyo_path2_perm(const u8 operation, const struct path *path1, const struct path *path2);
diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c index 9ec84ab..1543f01 100644 --- a/security/tomoyo/mount.c +++ b/security/tomoyo/mount.c
@@ -188,8 +188,7 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, * Returns 0 on success, negative value otherwise. */ int tomoyo_mount_permission(const char *dev_name, const struct path *path, - const char *type, unsigned long flags, - void *data_page) + const char *type, unsigned long flags) { struct tomoyo_request_info r; int error;
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index dcb7980..a9729f6 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c
@@ -421,7 +421,7 @@ static int tomoyo_sb_mount(const char *dev_name, const struct path *path, const char *type, unsigned long flags, void *data, size_t data_size) { - return tomoyo_mount_permission(dev_name, path, type, flags, data); + return tomoyo_mount_permission(dev_name, path, type, flags); } /**