From da2441fdffbf7602da702aea5bd95ca4dc3d63fc Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 1 Nov 2018 23:07:24 +0000 Subject: vfs: Add LSM hooks for the new mount API Add LSM hooks for use by the new mount API and filesystem context code. This includes: (1) Hooks to handle allocation, duplication and freeing of the security record attached to a filesystem context. (2) A hook to snoop source specifications. There may be multiple of these if the filesystem supports it. They will to be local files/devices if fs_context::source_is_dev is true and will be something else, possibly remote server specifications, if false. (3) A hook to snoop superblock configuration options in key[=val] form. If the LSM decides it wants to handle it, it can suppress the option being passed to the filesystem. Note that 'val' may include commas and binary data with the fsopen patch. (4) A hook to perform validation and allocation after the configuration has been done but before the superblock is allocated and set up. (5) A hook to transfer the security from the context to a newly created superblock. (6) A hook to rule on whether a path point can be used as a mountpoint. These are intended to replace: security_sb_copy_data security_sb_kern_mount security_sb_mount security_sb_set_mnt_opts security_sb_clone_mnt_opts security_sb_parse_opts_str [AV -- some of the methods being replaced are already gone, some of the methods are not added for the lack of need] Signed-off-by: David Howells cc: linux-security-module@vger.kernel.org Signed-off-by: Al Viro --- security/security.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'security') diff --git a/security/security.c b/security/security.c index f1b8d2587639..e5519488327d 100644 --- a/security/security.c +++ b/security/security.c @@ -374,6 +374,11 @@ void security_bprm_committed_creds(struct linux_binprm *bprm) call_void_hook(bprm_committed_creds, bprm); } +int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param) +{ + return call_int_hook(fs_context_parse_param, -ENOPARAM, fc, param); +} + int security_sb_alloc(struct super_block *sb) { return call_int_hook(sb_alloc_security, 0, sb); -- cgit v1.2.3 From 442155c1bd84f82bff2d05d0ec4d0090df17ecfa Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 1 Nov 2018 23:07:24 +0000 Subject: selinux: Implement the new mount API LSM hooks Implement the new mount API LSM hooks for SELinux. At some point the old hooks will need to be removed. Signed-off-by: David Howells cc: Paul Moore cc: Stephen Smalley cc: selinux@tycho.nsa.gov cc: linux-security-module@vger.kernel.org Signed-off-by: Al Viro --- security/selinux/hooks.c | 49 +++++++++++++++++++++++++++++++++---- security/selinux/include/security.h | 10 ++++---- 2 files changed, 49 insertions(+), 10 deletions(-) (limited to 'security') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index f0e36c3492ba..f99381e97d73 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -48,6 +48,8 @@ #include #include #include +#include +#include #include #include #include @@ -454,11 +456,11 @@ static inline int inode_doinit(struct inode *inode) enum { Opt_error = -1, - Opt_context = 1, + Opt_context = 0, + Opt_defcontext = 1, Opt_fscontext = 2, - Opt_defcontext = 3, - Opt_rootcontext = 4, - Opt_seclabel = 5, + Opt_rootcontext = 3, + Opt_seclabel = 4, }; #define A(s, has_arg) {#s, sizeof(#s) - 1, Opt_##s, has_arg} @@ -1089,6 +1091,7 @@ static int show_sid(struct seq_file *m, u32 sid) if (!rc) { bool has_comma = context && strchr(context, ','); + seq_putc(m, '='); if (has_comma) seq_putc(m, '\"'); seq_escape(m, context, "\"\n\\"); @@ -1142,7 +1145,7 @@ static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb) } if (sbsec->flags & SBLABEL_MNT) { seq_putc(m, ','); - seq_puts(m, LABELSUPP_STR); + seq_puts(m, SECLABEL_STR); } return 0; } @@ -2761,6 +2764,38 @@ static int selinux_umount(struct vfsmount *mnt, int flags) FILESYSTEM__UNMOUNT, NULL); } +static const struct fs_parameter_spec selinux_param_specs[] = { + fsparam_string(CONTEXT_STR, Opt_context), + fsparam_string(DEFCONTEXT_STR, Opt_defcontext), + fsparam_string(FSCONTEXT_STR, Opt_fscontext), + fsparam_string(ROOTCONTEXT_STR, Opt_rootcontext), + fsparam_flag (SECLABEL_STR, Opt_seclabel), + {} +}; + +static const struct fs_parameter_description selinux_fs_parameters = { + .name = "SELinux", + .specs = selinux_param_specs, +}; + +static int selinux_fs_context_parse_param(struct fs_context *fc, + struct fs_parameter *param) +{ + struct fs_parse_result result; + int opt, rc; + + opt = fs_parse(fc, &selinux_fs_parameters, param, &result); + if (opt < 0) + return opt; + + rc = selinux_add_opt(opt, param->string, &fc->security); + if (!rc) { + param->string = NULL; + rc = 1; + } + return rc; +} + /* inode security operations */ static int selinux_inode_alloc_security(struct inode *inode) @@ -6710,6 +6745,8 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds), LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds), + LSM_HOOK_INIT(fs_context_parse_param, selinux_fs_context_parse_param), + LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security), LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security), LSM_HOOK_INIT(sb_eat_lsm_opts, selinux_sb_eat_lsm_opts), @@ -6978,6 +7015,8 @@ static __init int selinux_init(void) else pr_debug("SELinux: Starting in permissive mode\n"); + fs_validate_description(&selinux_fs_parameters); + return 0; } diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index ba8eedf42b90..529d8941c9c5 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -59,11 +59,11 @@ #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 LABELSUPP_STR "seclabel" +#define CONTEXT_STR "context" +#define FSCONTEXT_STR "fscontext" +#define ROOTCONTEXT_STR "rootcontext" +#define DEFCONTEXT_STR "defcontext" +#define SECLABEL_STR "seclabel" struct netlbl_lsm_secattr; -- cgit v1.2.3 From 2febd254adc4958b2388c7a49ddc85227f41a158 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 1 Nov 2018 23:07:24 +0000 Subject: smack: Implement filesystem context security hooks Implement filesystem context security hooks for the smack LSM. Signed-off-by: David Howells cc: Casey Schaufler cc: linux-security-module@vger.kernel.org Signed-off-by: Al Viro --- security/smack/smack.h | 19 +++++-------------- security/smack/smack_lsm.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 15 deletions(-) (limited to 'security') diff --git a/security/smack/smack.h b/security/smack/smack.h index f7db791fb566..0380a9c89d3b 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -195,22 +195,13 @@ struct smack_known_list_elem { enum { Opt_error = -1, - Opt_fsdefault = 1, - Opt_fsfloor = 2, - Opt_fshat = 3, - Opt_fsroot = 4, - Opt_fstransmute = 5, + Opt_fsdefault = 0, + Opt_fsfloor = 1, + Opt_fshat = 2, + Opt_fsroot = 3, + Opt_fstransmute = 4, }; -/* - * 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 430d4f35e55c..5f93c4f84384 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include "smack.h" #define TRANS_TRUE "TRUE" @@ -541,7 +543,6 @@ static int smack_syslog(int typefrom_file) return rc; } - /* * Superblock Hooks. */ @@ -646,6 +647,44 @@ out_opt_err: return -EINVAL; } +static const struct fs_parameter_spec smack_param_specs[] = { + fsparam_string("fsdefault", Opt_fsdefault), + fsparam_string("fsfloor", Opt_fsfloor), + fsparam_string("fshat", Opt_fshat), + fsparam_string("fsroot", Opt_fsroot), + fsparam_string("fstransmute", Opt_fstransmute), + {} +}; + +static const struct fs_parameter_description smack_fs_parameters = { + .name = "smack", + .specs = smack_param_specs, +}; + +/** + * smack_fs_context_parse_param - Parse a single mount parameter + * @fc: The new filesystem context being constructed. + * @param: The parameter. + * + * Returns 0 on success, -ENOPARAM to pass the parameter on or anything else on + * error. + */ +static int smack_fs_context_parse_param(struct fs_context *fc, + struct fs_parameter *param) +{ + struct fs_parse_result result; + int opt, rc; + + opt = fs_parse(fc, &smack_fs_parameters, param, &result); + if (opt < 0) + return opt; + + rc = smack_add_opt(opt, param->string, &fc->security); + if (!rc) + param->string = NULL; + return rc; +} + static int smack_sb_eat_lsm_opts(char *options, void **mnt_opts) { char *from = options, *to = options; @@ -4587,6 +4626,8 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme), LSM_HOOK_INIT(syslog, smack_syslog), + LSM_HOOK_INIT(fs_context_parse_param, smack_fs_context_parse_param), + LSM_HOOK_INIT(sb_alloc_security, smack_sb_alloc_security), LSM_HOOK_INIT(sb_free_security, smack_sb_free_security), LSM_HOOK_INIT(sb_free_mnt_opts, smack_free_mnt_opts), -- cgit v1.2.3 From 0b52075ee62301dd150c9f2c3ddd0035ed894cde Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 23 Dec 2018 16:02:47 -0500 Subject: introduce cloning of fs_context new primitive: vfs_dup_fs_context(). Comes with fs_context method (->dup()) for copying the filesystem-specific parts of fs_context, along with LSM one (->fs_context_dup()) for doing the same to LSM parts. [needs better commit message, and change of Author:, anyway] Signed-off-by: Al Viro --- fs/fs_context.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/fs_context.h | 2 ++ include/linux/lsm_hooks.h | 7 +++++ include/linux/security.h | 6 +++++ security/security.c | 5 ++++ security/selinux/hooks.c | 39 +++++++++++++++++++++++++++ security/smack/smack_lsm.c | 49 +++++++++++++++++++++++++++++++++ 7 files changed, 175 insertions(+) (limited to 'security') diff --git a/fs/fs_context.c b/fs/fs_context.c index aa7e0ffb591a..57f61833ac83 100644 --- a/fs/fs_context.c +++ b/fs/fs_context.c @@ -337,6 +337,47 @@ void fc_drop_locked(struct fs_context *fc) static void legacy_fs_context_free(struct fs_context *fc); +/** + * vfs_dup_fc_config: Duplicate a filesystem context. + * @src_fc: The context to copy. + */ +struct fs_context *vfs_dup_fs_context(struct fs_context *src_fc) +{ + struct fs_context *fc; + int ret; + + if (!src_fc->ops->dup) + return ERR_PTR(-EOPNOTSUPP); + + fc = kmemdup(src_fc, sizeof(struct fs_context), GFP_KERNEL); + if (!fc) + return ERR_PTR(-ENOMEM); + + fc->fs_private = NULL; + fc->s_fs_info = NULL; + fc->source = NULL; + fc->security = NULL; + get_filesystem(fc->fs_type); + get_net(fc->net_ns); + get_user_ns(fc->user_ns); + get_cred(fc->cred); + + /* Can't call put until we've called ->dup */ + ret = fc->ops->dup(fc, src_fc); + if (ret < 0) + goto err_fc; + + ret = security_fs_context_dup(fc, src_fc); + if (ret < 0) + goto err_fc; + return fc; + +err_fc: + put_fs_context(fc); + return ERR_PTR(ret); +} +EXPORT_SYMBOL(vfs_dup_fs_context); + /** * put_fs_context - Dispose of a superblock configuration context. * @fc: The context to dispose of. @@ -380,6 +421,31 @@ static void legacy_fs_context_free(struct fs_context *fc) } } +/* + * Duplicate a legacy config. + */ +static int legacy_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc) +{ + struct legacy_fs_context *ctx; + struct legacy_fs_context *src_ctx = src_fc->fs_private; + + ctx = kmemdup(src_ctx, sizeof(*src_ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + if (ctx->param_type == LEGACY_FS_INDIVIDUAL_PARAMS) { + ctx->legacy_data = kmemdup(src_ctx->legacy_data, + src_ctx->data_size, GFP_KERNEL); + if (!ctx->legacy_data) { + kfree(ctx); + return -ENOMEM; + } + } + + fc->fs_private = ctx; + return 0; +} + /* * Add a parameter to a legacy config. We build up a comma-separated list of * options. @@ -514,6 +580,7 @@ static int legacy_reconfigure(struct fs_context *fc) const struct fs_context_operations legacy_fs_context_ops = { .free = legacy_fs_context_free, + .dup = legacy_fs_context_dup, .parse_param = legacy_parse_param, .parse_monolithic = legacy_parse_monolithic, .get_tree = legacy_get_tree, diff --git a/include/linux/fs_context.h b/include/linux/fs_context.h index b1a95db7a111..0db0b645c7b8 100644 --- a/include/linux/fs_context.h +++ b/include/linux/fs_context.h @@ -94,6 +94,7 @@ struct fs_context { struct fs_context_operations { void (*free)(struct fs_context *fc); + int (*dup)(struct fs_context *fc, struct fs_context *src_fc); int (*parse_param)(struct fs_context *fc, struct fs_parameter *param); int (*parse_monolithic)(struct fs_context *fc, void *data); int (*get_tree)(struct fs_context *fc); @@ -111,6 +112,7 @@ extern struct fs_context *fs_context_for_reconfigure(struct dentry *dentry, extern struct fs_context *fs_context_for_submount(struct file_system_type *fs_type, struct dentry *reference); +extern struct fs_context *vfs_dup_fs_context(struct fs_context *fc); extern int vfs_parse_fs_param(struct fs_context *fc, struct fs_parameter *param); extern int vfs_parse_fs_string(struct fs_context *fc, const char *key, const char *value, size_t v_size); diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 47ba4db4d8fb..356e78fe90a8 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -79,6 +79,11 @@ * Security hooks for mount using fs_context. * [See also Documentation/filesystems/mounting.txt] * + * @fs_context_dup: + * Allocate and attach a security structure to sc->security. This pointer + * is initialised to NULL by the caller. + * @fc indicates the new filesystem context. + * @src_fc indicates the original filesystem context. * @fs_context_parse_param: * Userspace provided a parameter to configure a superblock. The LSM may * reject it with an error and may use it for itself, in which case it @@ -1470,6 +1475,7 @@ union security_list_options { void (*bprm_committing_creds)(struct linux_binprm *bprm); void (*bprm_committed_creds)(struct linux_binprm *bprm); + int (*fs_context_dup)(struct fs_context *fc, struct fs_context *src_sc); int (*fs_context_parse_param)(struct fs_context *fc, struct fs_parameter *param); int (*sb_alloc_security)(struct super_block *sb); @@ -1813,6 +1819,7 @@ struct security_hook_heads { struct hlist_head bprm_check_security; struct hlist_head bprm_committing_creds; struct hlist_head bprm_committed_creds; + struct hlist_head fs_context_dup; struct hlist_head fs_context_parse_param; struct hlist_head sb_alloc_security; struct hlist_head sb_free_security; diff --git a/include/linux/security.h b/include/linux/security.h index 2da9336a987e..f28a1ebfd78e 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -223,6 +223,7 @@ int security_bprm_set_creds(struct linux_binprm *bprm); int security_bprm_check(struct linux_binprm *bprm); void security_bprm_committing_creds(struct linux_binprm *bprm); void security_bprm_committed_creds(struct linux_binprm *bprm); +int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc); int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param); int security_sb_alloc(struct super_block *sb); void security_sb_free(struct super_block *sb); @@ -521,6 +522,11 @@ static inline void security_bprm_committed_creds(struct linux_binprm *bprm) { } +static inline int security_fs_context_dup(struct fs_context *fc, + struct fs_context *src_fc) +{ + return 0; +} static inline int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param) { diff --git a/security/security.c b/security/security.c index e5519488327d..5759339319dc 100644 --- a/security/security.c +++ b/security/security.c @@ -374,6 +374,11 @@ void security_bprm_committed_creds(struct linux_binprm *bprm) call_void_hook(bprm_committed_creds, bprm); } +int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc) +{ + return call_int_hook(fs_context_dup, 0, fc, src_fc); +} + int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param) { return call_int_hook(fs_context_parse_param, -ENOPARAM, fc, param); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index f99381e97d73..4ba83de5fa80 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2764,6 +2764,44 @@ static int selinux_umount(struct vfsmount *mnt, int flags) FILESYSTEM__UNMOUNT, NULL); } +static int selinux_fs_context_dup(struct fs_context *fc, + struct fs_context *src_fc) +{ + const struct selinux_mnt_opts *src = src_fc->security; + struct selinux_mnt_opts *opts; + + if (!src) + return 0; + + fc->security = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL); + if (!fc->security) + return -ENOMEM; + + opts = fc->security; + + if (src->fscontext) { + opts->fscontext = kstrdup(src->fscontext, GFP_KERNEL); + if (!opts->fscontext) + return -ENOMEM; + } + if (src->context) { + opts->context = kstrdup(src->context, GFP_KERNEL); + if (!opts->context) + return -ENOMEM; + } + if (src->rootcontext) { + opts->rootcontext = kstrdup(src->rootcontext, GFP_KERNEL); + if (!opts->rootcontext) + return -ENOMEM; + } + if (src->defcontext) { + opts->defcontext = kstrdup(src->defcontext, GFP_KERNEL); + if (!opts->defcontext) + return -ENOMEM; + } + return 0; +} + static const struct fs_parameter_spec selinux_param_specs[] = { fsparam_string(CONTEXT_STR, Opt_context), fsparam_string(DEFCONTEXT_STR, Opt_defcontext), @@ -6745,6 +6783,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds), LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds), + LSM_HOOK_INIT(fs_context_dup, selinux_fs_context_dup), LSM_HOOK_INIT(fs_context_parse_param, selinux_fs_context_parse_param), LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security), diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 5f93c4f84384..03176f600a87 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -647,6 +647,54 @@ out_opt_err: return -EINVAL; } +/** + * smack_fs_context_dup - Duplicate the security data on fs_context duplication + * @fc: The new filesystem context. + * @src_fc: The source filesystem context being duplicated. + * + * Returns 0 on success or -ENOMEM on error. + */ +static int smack_fs_context_dup(struct fs_context *fc, + struct fs_context *src_fc) +{ + struct smack_mnt_opts *dst, *src = src_fc->security; + + if (!src) + return 0; + + fc->security = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL); + if (!fc->security) + return -ENOMEM; + dst = fc->security; + + if (src->fsdefault) { + dst->fsdefault = kstrdup(src->fsdefault, GFP_KERNEL); + if (!dst->fsdefault) + return -ENOMEM; + } + if (src->fsfloor) { + dst->fsfloor = kstrdup(src->fsfloor, GFP_KERNEL); + if (!dst->fsfloor) + return -ENOMEM; + } + if (src->fshat) { + dst->fshat = kstrdup(src->fshat, GFP_KERNEL); + if (!dst->fshat) + return -ENOMEM; + } + if (src->fsroot) { + dst->fsroot = kstrdup(src->fsroot, GFP_KERNEL); + if (!dst->fsroot) + return -ENOMEM; + } + if (src->fstransmute) { + dst->fstransmute = kstrdup(src->fstransmute, GFP_KERNEL); + if (!dst->fstransmute) + return -ENOMEM; + } + return 0; +} + static const struct fs_parameter_spec smack_param_specs[] = { fsparam_string("fsdefault", Opt_fsdefault), fsparam_string("fsfloor", Opt_fsfloor), @@ -4626,6 +4674,7 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme), LSM_HOOK_INIT(syslog, smack_syslog), + LSM_HOOK_INIT(fs_context_dup, smack_fs_context_dup), LSM_HOOK_INIT(fs_context_parse_param, smack_fs_context_parse_param), LSM_HOOK_INIT(sb_alloc_security, smack_sb_alloc_security), -- cgit v1.2.3