selinux: new helper - selinux_add_opt()

the guts of the loop in selinux_parse_opts_str() - takes one
(already recognized) option and adds it to growing selinux_mnt_opts.

Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2018-12-14 20:28:15 -05:00
parent 84d8c4a5ef
commit ba64186233

View file

@ -984,97 +984,77 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
return rc;
}
static int selinux_add_opt(int token, const char *s, void **mnt_opts)
{
struct selinux_mnt_opts *opts = *mnt_opts;
if (!opts) {
opts = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL);
if (!opts)
return -ENOMEM;
*mnt_opts = opts;
}
if (!s)
return -ENOMEM;
switch (token) {
case Opt_context:
if (opts->context || opts->defcontext)
goto Einval;
opts->context = s;
break;
case Opt_fscontext:
if (opts->fscontext)
goto Einval;
opts->fscontext = s;
break;
case Opt_rootcontext:
if (opts->rootcontext)
goto Einval;
opts->rootcontext = s;
break;
case Opt_defcontext:
if (opts->context || opts->defcontext)
goto Einval;
opts->defcontext = s;
break;
}
return 0;
Einval:
pr_warn(SEL_MOUNT_FAIL_MSG);
kfree(s);
return -EINVAL;
}
static int selinux_parse_opts_str(char *options,
void **mnt_opts)
{
struct selinux_mnt_opts *opts = *mnt_opts;
char *p;
int rc;
/* Standard string-based options. */
while ((p = strsep(&options, "|")) != NULL) {
int token;
int token, rc;
substring_t args[MAX_OPT_ARGS];
const char *arg;
if (!*p)
continue;
token = match_token(p, tokens, args);
if (!opts) {
opts = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL);
if (!opts)
return -ENOMEM;
if (token == Opt_labelsupport) /* eaten and completely ignored */
continue;
arg = match_strdup(&args[0]);
rc = selinux_add_opt(token, arg, mnt_opts);
if (unlikely(rc)) {
kfree(arg);
if (*mnt_opts) {
selinux_free_mnt_opts(*mnt_opts);
*mnt_opts = NULL;
}
switch (token) {
case Opt_context:
if (opts->context || opts->defcontext) {
rc = -EINVAL;
pr_warn(SEL_MOUNT_FAIL_MSG);
goto out_err;
}
opts->context = match_strdup(&args[0]);
if (!opts->context) {
rc = -ENOMEM;
goto out_err;
}
break;
case Opt_fscontext:
if (opts->fscontext) {
rc = -EINVAL;
pr_warn(SEL_MOUNT_FAIL_MSG);
goto out_err;
}
opts->fscontext = match_strdup(&args[0]);
if (!opts->fscontext) {
rc = -ENOMEM;
goto out_err;
}
break;
case Opt_rootcontext:
if (opts->rootcontext) {
rc = -EINVAL;
pr_warn(SEL_MOUNT_FAIL_MSG);
goto out_err;
}
opts->rootcontext = match_strdup(&args[0]);
if (!opts->rootcontext) {
rc = -ENOMEM;
goto out_err;
}
break;
case Opt_defcontext:
if (opts->context || opts->defcontext) {
rc = -EINVAL;
pr_warn(SEL_MOUNT_FAIL_MSG);
goto out_err;
}
opts->defcontext = match_strdup(&args[0]);
if (!opts->defcontext) {
rc = -ENOMEM;
goto out_err;
}
break;
case Opt_labelsupport:
break;
default:
rc = -EINVAL;
pr_warn("SELinux: unknown mount option\n");
goto out_err;
}
}
*mnt_opts = opts;
return 0;
out_err:
if (opts)
selinux_free_mnt_opts(opts);
return rc;
}
}
return 0;
}
static int show_sid(struct seq_file *m, u32 sid)