lkml.org 
[lkml]   [2018]   [Aug]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[PATCH 10/33] smack: Implement filesystem context security hooks [ver #11]
    From
    Date
    Implement filesystem context security hooks for the smack LSM.

    Question: Should the ->fs_context_parse_source() hook be implemented to
    check the labels on any source devices specified?

    Signed-off-by: David Howells <dhowells@redhat.com>
    cc: Casey Schaufler <casey@schaufler-ca.com>
    cc: linux-security-module@vger.kernel.org
    ---

    security/smack/smack.h | 11 +
    security/smack/smack_lsm.c | 337 ++++++++++++++++++++++++++++++++++++++++++++
    2 files changed, 343 insertions(+), 5 deletions(-)

    diff --git a/security/smack/smack.h b/security/smack/smack.h
    index f7db791fb566..e6d54e829394 100644
    --- a/security/smack/smack.h
    +++ b/security/smack/smack.h
    @@ -195,11 +195,12 @@ 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,
    + nr__smack_params
    };

    /*
    diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
    index 9811476c8441..339ac4d42785 100644
    --- a/security/smack/smack_lsm.c
    +++ b/security/smack/smack_lsm.c
    @@ -42,6 +42,8 @@
    #include <linux/shm.h>
    #include <linux/binfmts.h>
    #include <linux/parser.h>
    +#include <linux/fs_context.h>
    +#include <linux/fs_parser.h>
    #include "smack.h"

    #define TRANS_TRUE "TRUE"
    @@ -521,6 +523,334 @@ static int smack_syslog(int typefrom_file)
    return rc;
    }

    +/*
    + * Mount context operations
    + */
    +
    +struct smack_fs_context {
    + union {
    + struct {
    + char *fsdefault;
    + char *fsfloor;
    + char *fshat;
    + char *fsroot;
    + char *fstransmute;
    + };
    + char *ptrs[5];
    +
    + };
    + struct superblock_smack *sbsp;
    + struct inode_smack *isp;
    + bool transmute;
    +};
    +
    +/**
    + * smack_fs_context_free - Free the security data from a filesystem context
    + * @fc: The filesystem context to be cleaned up.
    + */
    +static void smack_fs_context_free(struct fs_context *fc)
    +{
    + struct smack_fs_context *ctx = fc->security;
    + int i;
    +
    + if (ctx) {
    + for (i = 0; i < ARRAY_SIZE(ctx->ptrs); i++)
    + kfree(ctx->ptrs[i]);
    + kfree(ctx->isp);
    + kfree(ctx->sbsp);
    + kfree(ctx);
    + fc->security = NULL;
    + }
    +}
    +
    +/**
    + * smack_fs_context_alloc - Allocate security data for a filesystem context
    + * @fc: The filesystem context.
    + * @reference: Reference dentry (automount/reconfigure) or NULL
    + *
    + * Returns 0 on success or -ENOMEM on error.
    + */
    +static int smack_fs_context_alloc(struct fs_context *fc,
    + struct dentry *reference)
    +{
    + struct smack_fs_context *ctx;
    + struct superblock_smack *sbsp;
    + struct inode_smack *isp;
    + struct smack_known *skp;
    +
    + ctx = kzalloc(sizeof(struct smack_fs_context), GFP_KERNEL);
    + if (!ctx)
    + goto nomem;
    + fc->security = ctx;
    +
    + sbsp = kzalloc(sizeof(struct superblock_smack), GFP_KERNEL);
    + if (!sbsp)
    + goto nomem_free;
    + ctx->sbsp = sbsp;
    +
    + isp = new_inode_smack(NULL);
    + if (!isp)
    + goto nomem_free;
    + ctx->isp = isp;
    +
    + if (reference) {
    + if (reference->d_sb->s_security)
    + memcpy(sbsp, reference->d_sb->s_security, sizeof(*sbsp));
    + } else if (!smack_privileged(CAP_MAC_ADMIN)) {
    + /* Unprivileged mounts get root and default from the caller. */
    + skp = smk_of_current();
    + sbsp->smk_root = skp;
    + sbsp->smk_default = skp;
    + } else {
    + sbsp->smk_root = &smack_known_floor;
    + sbsp->smk_default = &smack_known_floor;
    + sbsp->smk_floor = &smack_known_floor;
    + sbsp->smk_hat = &smack_known_hat;
    + /* SMK_SB_INITIALIZED will be zero from kzalloc. */
    + }
    +
    + return 0;
    +
    +nomem_free:
    + smack_fs_context_free(fc);
    +nomem:
    + return -ENOMEM;
    +}
    +
    +/**
    + * 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_fs_context *dst, *src = src_fc->security;
    + int i;
    +
    + dst = kzalloc(sizeof(struct smack_fs_context), GFP_KERNEL);
    + if (!dst)
    + goto nomem;
    + fc->security = dst;
    +
    + dst->sbsp = kmemdup(src->sbsp, sizeof(struct superblock_smack),
    + GFP_KERNEL);
    + 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])
    + goto nomem_free;
    + }
    + }
    +
    + return 0;
    +
    +nomem_free:
    + smack_fs_context_free(fc);
    +nomem:
    + return -ENOMEM;
    +}
    +
    +static const struct fs_parameter_spec smack_param_specs[nr__smack_params] = {
    + [Opt_fsdefault] = { fs_param_is_string },
    + [Opt_fsfloor] = { fs_param_is_string },
    + [Opt_fshat] = { fs_param_is_string },
    + [Opt_fsroot] = { fs_param_is_string },
    + [Opt_fstransmute] = { fs_param_is_string },
    +};
    +
    +static const struct constant_table smack_param_keys[] = {
    + { SMK_FSDEFAULT, Opt_fsdefault },
    + { SMK_FSFLOOR, Opt_fsfloor },
    + { SMK_FSHAT, Opt_fshat },
    + { SMK_FSROOT, Opt_fsroot },
    + { SMK_FSTRANS, Opt_fstransmute },
    +};
    +
    +static const struct fs_parameter_description smack_fs_parameters = {
    + .name = "smack",
    + .nr_params = nr__smack_params,
    + .nr_keys = ARRAY_SIZE(smack_param_keys),
    + .keys = smack_param_keys,
    + .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 or -ENOMEM on error.
    + */
    +static int smack_fs_context_parse_param(struct fs_context *fc,
    + struct fs_parameter *param)
    +{
    + struct smack_fs_context *ctx = fc->security;
    + struct fs_parse_result result;
    + int ret;
    +
    + /* Unprivileged mounts don't get to specify Smack values. */
    + if (!smack_privileged(CAP_MAC_ADMIN))
    + return -EPERM;
    +
    + ret = fs_parse(fc, &smack_fs_parameters, param, &result);
    + if (ret <= 0)
    + return ret; /* Note: 0 indicates no match */
    +
    + switch (result.key) {
    + case Opt_fsdefault:
    + if (ctx->fsdefault)
    + goto error_dup;
    + ctx->fsdefault = param->string;
    + if (!ctx->fsdefault)
    + goto error;
    + break;
    + case Opt_fsfloor:
    + if (ctx->fsfloor)
    + goto error_dup;
    + ctx->fsfloor = param->string;
    + if (!ctx->fsfloor)
    + goto error;
    + break;
    + case Opt_fshat:
    + if (ctx->fshat)
    + goto error_dup;
    + ctx->fshat = param->string;
    + if (!ctx->fshat)
    + goto error;
    + break;
    + case Opt_fsroot:
    + if (ctx->fsroot)
    + goto error_dup;
    + ctx->fsroot = param->string;
    + if (!ctx->fsroot)
    + goto error;
    + break;
    + case Opt_fstransmute:
    + if (ctx->fstransmute)
    + goto error_dup;
    + ctx->fstransmute = param->string;
    + if (!ctx->fstransmute)
    + goto error;
    + break;
    + default:
    + pr_warn("Smack: unknown mount option\n");
    + goto error_inval;
    + }
    +
    + param->string = NULL;
    + return 0;
    +
    +error_dup:
    + warnf(fc, "Smack: duplicate mount option\n");
    +error_inval:
    + ret = -EINVAL;
    +error:
    + return ret;
    +}
    +
    +/**
    + * smack_fs_context_validate - Validate the filesystem context security data
    + * @fc: The filesystem context.
    + *
    + * Returns 0 on success or -ENOMEM on error.
    + */
    +static int smack_fs_context_validate(struct fs_context *fc)
    +{
    + struct smack_fs_context *ctx = fc->security;
    + struct superblock_smack *sbsp = ctx->sbsp;
    + struct inode_smack *isp = ctx->isp;
    + struct smack_known *skp;
    +
    + if (ctx->fsdefault) {
    + skp = smk_import_entry(ctx->fsdefault, 0);
    + if (IS_ERR(skp))
    + return PTR_ERR(skp);
    + sbsp->smk_default = skp;
    + }
    +
    + if (ctx->fsfloor) {
    + skp = smk_import_entry(ctx->fsfloor, 0);
    + if (IS_ERR(skp))
    + return PTR_ERR(skp);
    + sbsp->smk_floor = skp;
    + }
    +
    + if (ctx->fshat) {
    + skp = smk_import_entry(ctx->fshat, 0);
    + if (IS_ERR(skp))
    + return PTR_ERR(skp);
    + sbsp->smk_hat = skp;
    + }
    +
    + if (ctx->fsroot || ctx->fstransmute) {
    + skp = smk_import_entry(ctx->fstransmute ?: ctx->fsroot, 0);
    + if (IS_ERR(skp))
    + return PTR_ERR(skp);
    + sbsp->smk_root = skp;
    + ctx->transmute = !!ctx->fstransmute;
    + }
    +
    + isp->smk_inode = sbsp->smk_root;
    + return 0;
    +}
    +
    +/**
    + * smack_sb_get_tree - Assign the context to a newly created superblock
    + * @fc: The new filesystem context.
    + *
    + * Returns 0 on success or -ENOMEM on error.
    + */
    +static int smack_sb_get_tree(struct fs_context *fc)
    +{
    + struct smack_fs_context *ctx = fc->security;
    + struct superblock_smack *sbsp = ctx->sbsp;
    + struct dentry *root = fc->root;
    + struct inode *inode = d_backing_inode(root);
    + struct super_block *sb = root->d_sb;
    + struct inode_smack *isp;
    + bool transmute = ctx->transmute;
    +
    + if (sb->s_security)
    + return 0;
    +
    + if (!smack_privileged(CAP_MAC_ADMIN)) {
    + /*
    + * 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 (fc->user_ns != &init_user_ns &&
    + sb->s_magic != SYSFS_MAGIC && sb->s_magic != TMPFS_MAGIC &&
    + sb->s_magic != RAMFS_MAGIC) {
    + transmute = true;
    + sbsp->smk_flags |= SMK_SB_UNTRUSTED;
    + }
    + }
    +
    + sbsp->smk_flags |= SMK_SB_INITIALIZED;
    + sb->s_security = sbsp;
    + ctx->sbsp = NULL;
    +
    + /* Initialize the root inode. */
    + isp = inode->i_security;
    + if (isp == NULL) {
    + isp = ctx->isp;
    + ctx->isp = NULL;
    + inode->i_security = isp;
    + } else
    + isp->smk_inode = sbsp->smk_root;
    +
    + if (transmute)
    + isp->smk_flags |= SMK_INODE_TRANSMUTE;
    +
    + return 0;
    +}

    /*
    * Superblock Hooks.
    @@ -4649,6 +4979,13 @@ 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_alloc, smack_fs_context_alloc),
    + LSM_HOOK_INIT(fs_context_dup, smack_fs_context_dup),
    + LSM_HOOK_INIT(fs_context_free, smack_fs_context_free),
    + LSM_HOOK_INIT(fs_context_parse_param, smack_fs_context_parse_param),
    + LSM_HOOK_INIT(fs_context_validate, smack_fs_context_validate),
    + LSM_HOOK_INIT(sb_get_tree, smack_sb_get_tree),
    +
    LSM_HOOK_INIT(sb_alloc_security, smack_sb_alloc_security),
    LSM_HOOK_INIT(sb_free_security, smack_sb_free_security),
    LSM_HOOK_INIT(sb_copy_data, smack_sb_copy_data),
    \
     
     \ /
      Last update: 2018-08-01 17:29    [W:4.360 / U:0.248 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site