On 5/17/2015 10:14 PM, VIVEK TRIVEDI wrote:
> EP-79F327334E67427298A99177E8F035A1
>
> Add support for setting smack mount labels(using smackfsdef, smackfsroot,
> smackfshat, smackfsfloor, smackfstransmute) for filesystems with binary
> mount data like NFS.
>
> To achieve this, implement sb_parse_opts_str and sb_set_mnt_opts security
> operations in smack LSM similar to SELinux.
>
> Signed-off-by: Vivek Trivedi <t.vi...@samsung.com>
> Signed-off-by: Amit Sahrawat <a.sahra...@samsung.com>
> ---
>  security/smack/smack.h     |   18 ++++
>  security/smack/smack_lsm.c |  250 
> ++++++++++++++++++++++++++++++++++++--------
>  2 files changed, 223 insertions(+), 45 deletions(-)
>
> diff --git a/security/smack/smack.h b/security/smack/smack.h
> index b8c1a86..f5db743 100644
> --- a/security/smack/smack.h
> +++ b/security/smack/smack.h
> @@ -138,6 +138,24 @@ struct smk_port_label {
>       struct smack_known      *smk_out;       /* outgoing label */
>  };
>  
> +/* Super block security struct flags for mount options */
> +#define FSDEFAULT_MNT        0x01
> +#define FSFLOOR_MNT  0x02
> +#define FSHAT_MNT    0x04
> +#define FSROOT_MNT   0x08
> +#define FSTRANS_MNT  0x10
> +
> +#define NUM_SMK_MNT_OPTS     5
> +
> +enum {
> +     Opt_error = -1,
> +     Opt_fsdefault = 1,
> +     Opt_fsfloor = 2,
> +     Opt_fshat = 3,
> +     Opt_fsroot = 4,
> +     Opt_fstransmute = 5,
> +};
> +
>  /*
>   * Mount options
>   */
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index 5eae42c..d88c27e 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -41,6 +41,7 @@
>  #include <linux/msg.h>
>  #include <linux/shm.h>
>  #include <linux/binfmts.h>
> +#include <linux/parser.h>
>  #include "smack.h"
>  
>  #define TRANS_TRUE   "TRUE"
> @@ -64,6 +65,15 @@ static char *smk_bu_mess[] = {
>       "Unconfined Object",    /* SMACK_UNCONFINED_OBJECT */
>  };
>  
> +static const match_table_t 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},
> +};
> +
>  static void smk_bu_mode(int mode, char *s)
>  {
>       int i = 0;
> @@ -573,72 +583,188 @@ static int smack_sb_copy_data(char *orig, char 
> *smackopts)
>  }
>  
>  /**
> - * smack_sb_kern_mount - Smack specific mount processing
> + * 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, *fsfloor = NULL;
> +     char *fshat = NULL, *fsroot = NULL, *fstransmute = NULL;
> +     int rc = -ENOMEM, num_mnt_opts = 0;
> +
> +     opts->num_mnt_opts = 0;
> +
> +     if (!options)
> +             return 0;
> +
> +     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_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");

Please use "Smack: unknown mount option\n".

> +                     goto out_err;
> +             }
> +     }
> +
> +     opts->mnt_opts = kcalloc(NUM_SMK_MNT_OPTS, sizeof(char *), GFP_ATOMIC);
> +     if (!opts->mnt_opts)
> +             goto out_err;
> +
> +     opts->mnt_opts_flags = kcalloc(NUM_SMK_MNT_OPTS, sizeof(int),
> +                     GFP_ATOMIC);
> +     if (!opts->mnt_opts_flags) {
> +             kfree(opts->mnt_opts);
> +             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");

Please use "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
> - * @flags: the mount flags
> - * @data: the smack mount options
> + * @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
> + * Returns 0 on success or -EPERM/ENOMEM on error.
> + *
> + * Allow filesystems with binary mount data to explicitly set Smack mount
> + * labels.
>   */
> -static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
> +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;
> -     char *op;
> -     char *commap;
> +     int i, num_opts = opts->num_mnt_opts;
>       int transmute = 0;
> -     int specified = 0;
>  
>       if (sp->smk_initialized)
>               return 0;
>  
>       sp->smk_initialized = 1;
>  
> -     for (op = data; op != NULL; op = commap) {
> -             commap = strchr(op, ',');
> -             if (commap != NULL)
> -                     *commap++ = '\0';
> -
> -             if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) {
> -                     op += strlen(SMK_FSHAT);
> -                     skp = smk_import_entry(op, 0);
> -                     if (skp != NULL) {
> -                             sp->smk_hat = skp;
> -                             specified = 1;
> -                     }
> -             } else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) {
> -                     op += strlen(SMK_FSFLOOR);
> -                     skp = smk_import_entry(op, 0);
> -                     if (skp != NULL) {
> -                             sp->smk_floor = skp;
> -                             specified = 1;
> -                     }
> -             } else if (strncmp(op, SMK_FSDEFAULT,
> -                                strlen(SMK_FSDEFAULT)) == 0) {
> -                     op += strlen(SMK_FSDEFAULT);
> -                     skp = smk_import_entry(op, 0);
> -                     if (skp != NULL) {
> +     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 (skp != NULL)
>                               sp->smk_default = skp;
> -                             specified = 1;
> -                     }
> -             } else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) {
> -                     op += strlen(SMK_FSROOT);
> -                     skp = smk_import_entry(op, 0);
> -                     if (skp != NULL) {
> +                     break;
> +             case FSFLOOR_MNT:
> +                     skp = smk_import_entry(opts->mnt_opts[i], 0);
> +                     if (skp != NULL)
> +                             sp->smk_floor = skp;
> +                     break;
> +             case FSHAT_MNT:
> +                     skp = smk_import_entry(opts->mnt_opts[i], 0);
> +                     if (skp != NULL)
> +                             sp->smk_hat = skp;
> +                     break;
> +             case FSROOT_MNT:
> +                     skp = smk_import_entry(opts->mnt_opts[i], 0);
> +                     if (skp != NULL)
>                               sp->smk_root = skp;
> -                             specified = 1;
> -                     }
> -             } else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) {
> -                     op += strlen(SMK_FSTRANS);
> -                     skp = smk_import_entry(op, 0);
> +                     break;
> +             case FSTRANS_MNT:
> +                     skp = smk_import_entry(opts->mnt_opts[i], 0);
>                       if (skp != NULL) {
>                               sp->smk_root = skp;
>                               transmute = 1;
> -                             specified = 1;
>                       }
> +                     break;
> +             default:
> +                     break;
>               }
>       }
>  
> @@ -646,7 +772,7 @@ static int smack_sb_kern_mount(struct super_block *sb, 
> int flags, void *data)
>               /*
>                * Unprivileged mounts don't get to specify Smack values.
>                */
> -             if (specified)
> +             if (num_opts)
>                       return -EPERM;
>               /*
>                * Unprivileged mounts get root and default from the caller.
> @@ -655,6 +781,7 @@ static int smack_sb_kern_mount(struct super_block *sb, 
> int flags, void *data)
>               sp->smk_root = skp;
>               sp->smk_default = skp;
>       }
> +
>       /*
>        * Initialize the root inode.
>        */
> @@ -674,6 +801,37 @@ static int smack_sb_kern_mount(struct super_block *sb, 
> int flags, void *data)
>  }
>  
>  /**
> + * smack_sb_kern_mount - Smack specific mount processing
> + * @sb: the file system superblock
> + * @flags: the mount flags
> + * @data: the smack mount options
> + *
> + * Returns 0 on success, an error code on failure
> + */
> +static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
> +{
> +     int rc = 0;
> +     char *options = data;
> +     struct security_mnt_opts opts;
> +
> +     security_init_mnt_opts(&opts);
> +
> +     if (!options)
> +             goto out;
> +
> +     rc = smack_parse_opts_str(options, &opts);
> +     if (rc)
> +             goto out_err;
> +
> +out:
> +     rc = smack_set_mnt_opts(sb, &opts, 0, NULL);
> +
> +out_err:
> +     security_free_mnt_opts(&opts);
> +     return rc;
> +}
> +
> +/**
>   * smack_sb_statfs - Smack check on statfs
>   * @dentry: identifies the file system in question
>   *
> @@ -4246,6 +4404,8 @@ struct security_hook_list smack_hooks[] = {
>       LSM_HOOK_INIT(sb_copy_data, smack_sb_copy_data),
>       LSM_HOOK_INIT(sb_kern_mount, smack_sb_kern_mount),
>       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),
>       LSM_HOOK_INIT(bprm_committing_creds, smack_bprm_committing_creds),

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to