selinux: switch to private struct selinux_mnt_opts
none of the convolutions needed, just 4 strings, TYVM... Reviewed-by: David Howells <dhowells@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>pull/641/head
parent
204cc0ccf1
commit
bd3236557b
|
|
@ -433,16 +433,17 @@ static void superblock_free_security(struct super_block *sb)
|
||||||
kfree(sbsec);
|
kfree(sbsec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct selinux_mnt_opts {
|
||||||
|
const char *fscontext, *context, *rootcontext, *defcontext;
|
||||||
|
};
|
||||||
|
|
||||||
static void selinux_free_mnt_opts(void *mnt_opts)
|
static void selinux_free_mnt_opts(void *mnt_opts)
|
||||||
{
|
{
|
||||||
struct security_mnt_opts *opts = mnt_opts;
|
struct selinux_mnt_opts *opts = mnt_opts;
|
||||||
int i;
|
kfree(opts->fscontext);
|
||||||
|
kfree(opts->context);
|
||||||
if (opts->mnt_opts)
|
kfree(opts->rootcontext);
|
||||||
for (i = 0; i < opts->num_mnt_opts; i++)
|
kfree(opts->defcontext);
|
||||||
kfree(opts->mnt_opts[i]);
|
|
||||||
kfree(opts->mnt_opts);
|
|
||||||
kfree(opts->mnt_opts_flags);
|
|
||||||
kfree(opts);
|
kfree(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -624,6 +625,17 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int parse_sid(struct super_block *sb, const char *s, u32 *sid)
|
||||||
|
{
|
||||||
|
int rc = security_context_str_to_sid(&selinux_state, s,
|
||||||
|
sid, GFP_KERNEL);
|
||||||
|
if (rc)
|
||||||
|
pr_warn("SELinux: security_context_str_to_sid"
|
||||||
|
"(%s) failed for (dev %s, type %s) errno=%d\n",
|
||||||
|
s, sb->s_id, sb->s_type->name, rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allow filesystems with binary mount data to explicitly set mount point
|
* Allow filesystems with binary mount data to explicitly set mount point
|
||||||
* labeling information.
|
* labeling information.
|
||||||
|
|
@ -634,22 +646,18 @@ static int selinux_set_mnt_opts(struct super_block *sb,
|
||||||
unsigned long *set_kern_flags)
|
unsigned long *set_kern_flags)
|
||||||
{
|
{
|
||||||
const struct cred *cred = current_cred();
|
const struct cred *cred = current_cred();
|
||||||
int rc = 0, i;
|
|
||||||
struct superblock_security_struct *sbsec = sb->s_security;
|
struct superblock_security_struct *sbsec = sb->s_security;
|
||||||
const char *name = sb->s_type->name;
|
|
||||||
struct dentry *root = sbsec->sb->s_root;
|
struct dentry *root = sbsec->sb->s_root;
|
||||||
|
struct selinux_mnt_opts *opts = mnt_opts;
|
||||||
struct inode_security_struct *root_isec;
|
struct inode_security_struct *root_isec;
|
||||||
u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
|
u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
|
||||||
u32 defcontext_sid = 0;
|
u32 defcontext_sid = 0;
|
||||||
struct security_mnt_opts *opts = mnt_opts;
|
int rc = 0;
|
||||||
char **mount_options = opts ? opts->mnt_opts : NULL;
|
|
||||||
int *flags = opts ? opts->mnt_opts_flags : NULL;
|
|
||||||
int num_opts = opts ? opts->num_mnt_opts : 0;
|
|
||||||
|
|
||||||
mutex_lock(&sbsec->lock);
|
mutex_lock(&sbsec->lock);
|
||||||
|
|
||||||
if (!selinux_state.initialized) {
|
if (!selinux_state.initialized) {
|
||||||
if (!num_opts) {
|
if (!opts) {
|
||||||
/* Defer initialization until selinux_complete_init,
|
/* Defer initialization until selinux_complete_init,
|
||||||
after the initial policy is loaded and the security
|
after the initial policy is loaded and the security
|
||||||
server is ready to handle calls. */
|
server is ready to handle calls. */
|
||||||
|
|
@ -679,7 +687,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
|
||||||
* will be used for both mounts)
|
* will be used for both mounts)
|
||||||
*/
|
*/
|
||||||
if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
|
if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
|
||||||
&& (num_opts == 0))
|
&& !opts)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
root_isec = backing_inode_security_novalidate(root);
|
root_isec = backing_inode_security_novalidate(root);
|
||||||
|
|
@ -689,68 +697,48 @@ static int selinux_set_mnt_opts(struct super_block *sb,
|
||||||
* also check if someone is trying to mount the same sb more
|
* also check if someone is trying to mount the same sb more
|
||||||
* than once with different security options.
|
* than once with different security options.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < num_opts; i++) {
|
if (opts) {
|
||||||
u32 sid;
|
if (opts->fscontext) {
|
||||||
|
rc = parse_sid(sb, opts->fscontext, &fscontext_sid);
|
||||||
if (flags[i] == SBLABEL_MNT)
|
if (rc)
|
||||||
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;
|
goto out;
|
||||||
}
|
|
||||||
switch (flags[i]) {
|
|
||||||
case FSCONTEXT_MNT:
|
|
||||||
fscontext_sid = sid;
|
|
||||||
|
|
||||||
if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
|
if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
|
||||||
fscontext_sid))
|
fscontext_sid))
|
||||||
goto out_double_mount;
|
goto out_double_mount;
|
||||||
|
|
||||||
sbsec->flags |= FSCONTEXT_MNT;
|
sbsec->flags |= FSCONTEXT_MNT;
|
||||||
break;
|
}
|
||||||
case CONTEXT_MNT:
|
if (opts->context) {
|
||||||
context_sid = sid;
|
rc = parse_sid(sb, opts->context, &context_sid);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
|
if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
|
||||||
context_sid))
|
context_sid))
|
||||||
goto out_double_mount;
|
goto out_double_mount;
|
||||||
|
|
||||||
sbsec->flags |= CONTEXT_MNT;
|
sbsec->flags |= CONTEXT_MNT;
|
||||||
break;
|
}
|
||||||
case ROOTCONTEXT_MNT:
|
if (opts->rootcontext) {
|
||||||
rootcontext_sid = sid;
|
rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
|
if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
|
||||||
rootcontext_sid))
|
rootcontext_sid))
|
||||||
goto out_double_mount;
|
goto out_double_mount;
|
||||||
|
|
||||||
sbsec->flags |= ROOTCONTEXT_MNT;
|
sbsec->flags |= ROOTCONTEXT_MNT;
|
||||||
|
}
|
||||||
break;
|
if (opts->defcontext) {
|
||||||
case DEFCONTEXT_MNT:
|
rc = parse_sid(sb, opts->defcontext, &defcontext_sid);
|
||||||
defcontext_sid = sid;
|
if (rc)
|
||||||
|
goto out;
|
||||||
if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
|
if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
|
||||||
defcontext_sid))
|
defcontext_sid))
|
||||||
goto out_double_mount;
|
goto out_double_mount;
|
||||||
|
|
||||||
sbsec->flags |= DEFCONTEXT_MNT;
|
sbsec->flags |= DEFCONTEXT_MNT;
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
rc = -EINVAL;
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sbsec->flags & SE_SBINITIALIZED) {
|
if (sbsec->flags & SE_SBINITIALIZED) {
|
||||||
/* previously mounted with options, but not on this attempt? */
|
/* previously mounted with options, but not on this attempt? */
|
||||||
if ((sbsec->flags & SE_MNTMASK) && !num_opts)
|
if ((sbsec->flags & SE_MNTMASK) && !opts)
|
||||||
goto out_double_mount;
|
goto out_double_mount;
|
||||||
rc = 0;
|
rc = 0;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -883,7 +871,8 @@ out:
|
||||||
out_double_mount:
|
out_double_mount:
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
pr_warn("SELinux: mount invalid. Same superblock, different "
|
pr_warn("SELinux: mount invalid. Same superblock, different "
|
||||||
"security settings for (dev %s, type %s)\n", sb->s_id, name);
|
"security settings for (dev %s, type %s)\n", sb->s_id,
|
||||||
|
sb->s_type->name);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -998,20 +987,9 @@ out:
|
||||||
static int selinux_parse_opts_str(char *options,
|
static int selinux_parse_opts_str(char *options,
|
||||||
void **mnt_opts)
|
void **mnt_opts)
|
||||||
{
|
{
|
||||||
|
struct selinux_mnt_opts *opts = *mnt_opts;
|
||||||
char *p;
|
char *p;
|
||||||
char *context = NULL, *defcontext = NULL;
|
int rc;
|
||||||
char *fscontext = NULL, *rootcontext = NULL;
|
|
||||||
int rc, num_mnt_opts = 0;
|
|
||||||
struct security_mnt_opts *opts = *mnt_opts;
|
|
||||||
|
|
||||||
if (!opts) {
|
|
||||||
opts = kzalloc(sizeof(struct security_mnt_opts), GFP_KERNEL);
|
|
||||||
*mnt_opts = opts;
|
|
||||||
if (!opts)
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
opts->num_mnt_opts = 0;
|
|
||||||
|
|
||||||
/* Standard string-based options. */
|
/* Standard string-based options. */
|
||||||
while ((p = strsep(&options, "|")) != NULL) {
|
while ((p = strsep(&options, "|")) != NULL) {
|
||||||
|
|
@ -1023,54 +1001,60 @@ static int selinux_parse_opts_str(char *options,
|
||||||
|
|
||||||
token = match_token(p, tokens, args);
|
token = match_token(p, tokens, args);
|
||||||
|
|
||||||
|
if (!opts) {
|
||||||
|
opts = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL);
|
||||||
|
if (!opts)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
switch (token) {
|
switch (token) {
|
||||||
case Opt_context:
|
case Opt_context:
|
||||||
if (context || defcontext) {
|
if (opts->context || opts->defcontext) {
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
pr_warn(SEL_MOUNT_FAIL_MSG);
|
pr_warn(SEL_MOUNT_FAIL_MSG);
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
context = match_strdup(&args[0]);
|
opts->context = match_strdup(&args[0]);
|
||||||
if (!context) {
|
if (!opts->context) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Opt_fscontext:
|
case Opt_fscontext:
|
||||||
if (fscontext) {
|
if (opts->fscontext) {
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
pr_warn(SEL_MOUNT_FAIL_MSG);
|
pr_warn(SEL_MOUNT_FAIL_MSG);
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
fscontext = match_strdup(&args[0]);
|
opts->fscontext = match_strdup(&args[0]);
|
||||||
if (!fscontext) {
|
if (!opts->fscontext) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Opt_rootcontext:
|
case Opt_rootcontext:
|
||||||
if (rootcontext) {
|
if (opts->rootcontext) {
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
pr_warn(SEL_MOUNT_FAIL_MSG);
|
pr_warn(SEL_MOUNT_FAIL_MSG);
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
rootcontext = match_strdup(&args[0]);
|
opts->rootcontext = match_strdup(&args[0]);
|
||||||
if (!rootcontext) {
|
if (!opts->rootcontext) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Opt_defcontext:
|
case Opt_defcontext:
|
||||||
if (context || defcontext) {
|
if (opts->context || opts->defcontext) {
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
pr_warn(SEL_MOUNT_FAIL_MSG);
|
pr_warn(SEL_MOUNT_FAIL_MSG);
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
defcontext = match_strdup(&args[0]);
|
opts->defcontext = match_strdup(&args[0]);
|
||||||
if (!defcontext) {
|
if (!opts->defcontext) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
|
|
@ -1084,43 +1068,12 @@ static int selinux_parse_opts_str(char *options,
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*mnt_opts = opts;
|
||||||
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;
|
return 0;
|
||||||
|
|
||||||
out_err:
|
out_err:
|
||||||
security_free_mnt_opts(mnt_opts);
|
if (opts)
|
||||||
kfree(context);
|
selinux_free_mnt_opts(opts);
|
||||||
kfree(defcontext);
|
|
||||||
kfree(fscontext);
|
|
||||||
kfree(rootcontext);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2752,10 +2705,10 @@ static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts)
|
||||||
|
|
||||||
static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
|
static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
|
||||||
{
|
{
|
||||||
struct security_mnt_opts *opts = mnt_opts;
|
struct selinux_mnt_opts *opts = mnt_opts;
|
||||||
int i, *flags;
|
|
||||||
char **mount_options;
|
|
||||||
struct superblock_security_struct *sbsec = sb->s_security;
|
struct superblock_security_struct *sbsec = sb->s_security;
|
||||||
|
u32 sid;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (!(sbsec->flags & SE_SBINITIALIZED))
|
if (!(sbsec->flags & SE_SBINITIALIZED))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -2763,48 +2716,35 @@ static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
|
||||||
if (!opts)
|
if (!opts)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
mount_options = opts->mnt_opts;
|
if (opts->fscontext) {
|
||||||
flags = opts->mnt_opts_flags;
|
rc = parse_sid(sb, opts->fscontext, &sid);
|
||||||
|
if (rc)
|
||||||
for (i = 0; i < opts->num_mnt_opts; i++) {
|
|
||||||
u32 sid;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (flags[i] == SBLABEL_MNT)
|
|
||||||
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);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
|
||||||
switch (flags[i]) {
|
|
||||||
case FSCONTEXT_MNT:
|
|
||||||
if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
|
if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
|
||||||
goto out_bad_option;
|
goto out_bad_option;
|
||||||
break;
|
}
|
||||||
case CONTEXT_MNT:
|
if (opts->context) {
|
||||||
|
rc = parse_sid(sb, opts->context, &sid);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
|
if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
|
||||||
goto out_bad_option;
|
goto out_bad_option;
|
||||||
break;
|
}
|
||||||
case ROOTCONTEXT_MNT: {
|
if (opts->rootcontext) {
|
||||||
struct inode_security_struct *root_isec;
|
struct inode_security_struct *root_isec;
|
||||||
root_isec = backing_inode_security(sb->s_root);
|
root_isec = backing_inode_security(sb->s_root);
|
||||||
|
rc = parse_sid(sb, opts->rootcontext, &sid);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
|
if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
|
||||||
goto out_bad_option;
|
goto out_bad_option;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case DEFCONTEXT_MNT:
|
if (opts->defcontext) {
|
||||||
|
rc = parse_sid(sb, opts->defcontext, &sid);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
|
if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
|
||||||
goto out_bad_option;
|
goto out_bad_option;
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue