Commit bd323655 authored by Al Viro's avatar Al Viro

selinux: switch to private struct selinux_mnt_opts

none of the convolutions needed, just 4 strings, TYVM...
Reviewed-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 204cc0cc
...@@ -433,16 +433,17 @@ static void superblock_free_security(struct super_block *sb) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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; goto out;
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;
}
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 @@ static int selinux_set_mnt_opts(struct super_block *sb, ...@@ -883,7 +871,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
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 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, ...@@ -998,20 +987,9 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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;
} if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
switch (flags[i]) { goto out_bad_option;
case FSCONTEXT_MNT: }
if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid)) if (opts->context) {
goto out_bad_option; rc = parse_sid(sb, opts->context, &sid);
break; if (rc)
case CONTEXT_MNT: 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 (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid)) if (rc)
goto out_bad_option; return rc;
break; if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
} goto out_bad_option;
case DEFCONTEXT_MNT: }
if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid)) if (opts->defcontext) {
goto out_bad_option; rc = parse_sid(sb, opts->defcontext, &sid);
break; if (rc)
default: return rc;
return -EINVAL; if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
} goto out_bad_option;
} }
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment