smack: allow mount opts setting over filesystems with binary mount data
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.vivek@samsung.com> Signed-off-by: Amit Sahrawat <a.sahrawat@samsung.com> Acked-by: Casey Schaufler <casey@schaufler-ca.com>
This commit is contained in:
Родитель
fe6c59dc17
Коммит
3bf2789cad
|
@ -143,6 +143,24 @@ struct smack_onlycap {
|
||||||
struct smack_known *smk_label;
|
struct smack_known *smk_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
|
* Mount options
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include <linux/msg.h>
|
#include <linux/msg.h>
|
||||||
#include <linux/shm.h>
|
#include <linux/shm.h>
|
||||||
#include <linux/binfmts.h>
|
#include <linux/binfmts.h>
|
||||||
|
#include <linux/parser.h>
|
||||||
#include "smack.h"
|
#include "smack.h"
|
||||||
|
|
||||||
#define TRANS_TRUE "TRUE"
|
#define TRANS_TRUE "TRUE"
|
||||||
|
@ -64,6 +65,15 @@ static char *smk_bu_mess[] = {
|
||||||
"Unconfined Object", /* SMACK_UNCONFINED_OBJECT */
|
"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)
|
static void smk_bu_mode(int mode, char *s)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -577,76 +587,193 @@ 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");
|
||||||
|
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");
|
||||||
|
|
||||||
|
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
|
* @sb: the file system superblock
|
||||||
* @flags: the mount flags
|
* @opts: Smack mount options
|
||||||
* @data: the 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, an error code on failure
|
||||||
|
*
|
||||||
|
* 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 dentry *root = sb->s_root;
|
||||||
struct inode *inode = d_backing_inode(root);
|
struct inode *inode = d_backing_inode(root);
|
||||||
struct superblock_smack *sp = sb->s_security;
|
struct superblock_smack *sp = sb->s_security;
|
||||||
struct inode_smack *isp;
|
struct inode_smack *isp;
|
||||||
struct smack_known *skp;
|
struct smack_known *skp;
|
||||||
char *op;
|
int i;
|
||||||
char *commap;
|
int num_opts = opts->num_mnt_opts;
|
||||||
int transmute = 0;
|
int transmute = 0;
|
||||||
int specified = 0;
|
|
||||||
|
|
||||||
if (sp->smk_initialized)
|
if (sp->smk_initialized)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
sp->smk_initialized = 1;
|
sp->smk_initialized = 1;
|
||||||
|
|
||||||
for (op = data; op != NULL; op = commap) {
|
for (i = 0; i < num_opts; i++) {
|
||||||
commap = strchr(op, ',');
|
switch (opts->mnt_opts_flags[i]) {
|
||||||
if (commap != NULL)
|
case FSDEFAULT_MNT:
|
||||||
*commap++ = '\0';
|
skp = smk_import_entry(opts->mnt_opts[i], 0);
|
||||||
|
|
||||||
if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) {
|
|
||||||
op += strlen(SMK_FSHAT);
|
|
||||||
skp = smk_import_entry(op, 0);
|
|
||||||
if (IS_ERR(skp))
|
|
||||||
return PTR_ERR(skp);
|
|
||||||
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 (IS_ERR(skp))
|
|
||||||
return PTR_ERR(skp);
|
|
||||||
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 (IS_ERR(skp))
|
if (IS_ERR(skp))
|
||||||
return PTR_ERR(skp);
|
return PTR_ERR(skp);
|
||||||
sp->smk_default = skp;
|
sp->smk_default = skp;
|
||||||
specified = 1;
|
break;
|
||||||
|
case FSFLOOR_MNT:
|
||||||
} else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) {
|
skp = smk_import_entry(opts->mnt_opts[i], 0);
|
||||||
op += strlen(SMK_FSROOT);
|
if (IS_ERR(skp))
|
||||||
skp = smk_import_entry(op, 0);
|
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))
|
if (IS_ERR(skp))
|
||||||
return PTR_ERR(skp);
|
return PTR_ERR(skp);
|
||||||
sp->smk_root = skp;
|
sp->smk_root = skp;
|
||||||
specified = 1;
|
break;
|
||||||
|
case FSTRANS_MNT:
|
||||||
} else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) {
|
skp = smk_import_entry(opts->mnt_opts[i], 0);
|
||||||
op += strlen(SMK_FSTRANS);
|
|
||||||
skp = smk_import_entry(op, 0);
|
|
||||||
if (IS_ERR(skp))
|
if (IS_ERR(skp))
|
||||||
return PTR_ERR(skp);
|
return PTR_ERR(skp);
|
||||||
sp->smk_root = skp;
|
sp->smk_root = skp;
|
||||||
transmute = 1;
|
transmute = 1;
|
||||||
specified = 1;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,7 +781,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
|
||||||
/*
|
/*
|
||||||
* Unprivileged mounts don't get to specify Smack values.
|
* Unprivileged mounts don't get to specify Smack values.
|
||||||
*/
|
*/
|
||||||
if (specified)
|
if (num_opts)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
/*
|
/*
|
||||||
* Unprivileged mounts get root and default from the caller.
|
* Unprivileged mounts get root and default from the caller.
|
||||||
|
@ -663,6 +790,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
|
||||||
sp->smk_root = skp;
|
sp->smk_root = skp;
|
||||||
sp->smk_default = skp;
|
sp->smk_default = skp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the root inode.
|
* Initialize the root inode.
|
||||||
*/
|
*/
|
||||||
|
@ -681,6 +809,37 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* smack_sb_statfs - Smack check on statfs
|
||||||
* @dentry: identifies the file system in question
|
* @dentry: identifies the file system in question
|
||||||
|
@ -4264,6 +4423,8 @@ struct security_hook_list smack_hooks[] = {
|
||||||
LSM_HOOK_INIT(sb_copy_data, smack_sb_copy_data),
|
LSM_HOOK_INIT(sb_copy_data, smack_sb_copy_data),
|
||||||
LSM_HOOK_INIT(sb_kern_mount, smack_sb_kern_mount),
|
LSM_HOOK_INIT(sb_kern_mount, smack_sb_kern_mount),
|
||||||
LSM_HOOK_INIT(sb_statfs, smack_sb_statfs),
|
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_set_creds, smack_bprm_set_creds),
|
||||||
LSM_HOOK_INIT(bprm_committing_creds, smack_bprm_committing_creds),
|
LSM_HOOK_INIT(bprm_committing_creds, smack_bprm_committing_creds),
|
||||||
|
|
Загрузка…
Ссылка в новой задаче