Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bd323655 authored by Al Viro's avatar Al Viro
Browse files

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
Loading
Loading
Loading
Loading
+101 −161
Original line number Diff line number Diff line
@@ -433,16 +433,17 @@ static void superblock_free_security(struct super_block *sb)
	kfree(sbsec);
}

struct selinux_mnt_opts {
	const char *fscontext, *context, *rootcontext, *defcontext;
};

static void selinux_free_mnt_opts(void *mnt_opts)
{
	struct security_mnt_opts *opts = mnt_opts;
	int i;

	if (opts->mnt_opts)
		for (i = 0; i < opts->num_mnt_opts; i++)
			kfree(opts->mnt_opts[i]);
	kfree(opts->mnt_opts);
	kfree(opts->mnt_opts_flags);
	struct selinux_mnt_opts *opts = mnt_opts;
	kfree(opts->fscontext);
	kfree(opts->context);
	kfree(opts->rootcontext);
	kfree(opts->defcontext);
	kfree(opts);
}

@@ -624,6 +625,17 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
	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
 * labeling information.
@@ -634,22 +646,18 @@ static int selinux_set_mnt_opts(struct super_block *sb,
				unsigned long *set_kern_flags)
{
	const struct cred *cred = current_cred();
	int rc = 0, i;
	struct superblock_security_struct *sbsec = sb->s_security;
	const char *name = sb->s_type->name;
	struct dentry *root = sbsec->sb->s_root;
	struct selinux_mnt_opts *opts = mnt_opts;
	struct inode_security_struct *root_isec;
	u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
	u32 defcontext_sid = 0;
	struct security_mnt_opts *opts = mnt_opts;
	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;
	int rc = 0;

	mutex_lock(&sbsec->lock);

	if (!selinux_state.initialized) {
		if (!num_opts) {
		if (!opts) {
			/* Defer initialization until selinux_complete_init,
			   after the initial policy is loaded and the security
			   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)
	 */
	if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
	    && (num_opts == 0))
	    && !opts)
		goto out;

	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
	 * than once with different security options.
	 */
	for (i = 0; i < num_opts; i++) {
		u32 sid;

		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, name, rc);
	if (opts) {
		if (opts->fscontext) {
			rc = parse_sid(sb, opts->fscontext, &fscontext_sid);
			if (rc)
				goto out;
		}
		switch (flags[i]) {
		case FSCONTEXT_MNT:
			fscontext_sid = sid;

			if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
					fscontext_sid))
				goto out_double_mount;

			sbsec->flags |= FSCONTEXT_MNT;
			break;
		case CONTEXT_MNT:
			context_sid = sid;

		}
		if (opts->context) {
			rc = parse_sid(sb, opts->context, &context_sid);
			if (rc)
				goto out;
			if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
					context_sid))
				goto out_double_mount;

			sbsec->flags |= CONTEXT_MNT;
			break;
		case ROOTCONTEXT_MNT:
			rootcontext_sid = sid;

		}
		if (opts->rootcontext) {
			rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid);
			if (rc)
				goto out;
			if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
					rootcontext_sid))
				goto out_double_mount;

			sbsec->flags |= ROOTCONTEXT_MNT;

			break;
		case DEFCONTEXT_MNT:
			defcontext_sid = sid;

		}
		if (opts->defcontext) {
			rc = parse_sid(sb, opts->defcontext, &defcontext_sid);
			if (rc)
				goto out;
			if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
					defcontext_sid))
				goto out_double_mount;

			sbsec->flags |= DEFCONTEXT_MNT;

			break;
		default:
			rc = -EINVAL;
			goto out;
		}
	}

	if (sbsec->flags & SE_SBINITIALIZED) {
		/* 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;
		rc = 0;
		goto out;
@@ -883,7 +871,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
out_double_mount:
	rc = -EINVAL;
	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;
}

@@ -998,20 +987,9 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
static int selinux_parse_opts_str(char *options,
				  void **mnt_opts)
{
	struct selinux_mnt_opts *opts = *mnt_opts;
	char *p;
	char *context = NULL, *defcontext = NULL;
	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;
	int rc;

	/* Standard string-based options. */
	while ((p = strsep(&options, "|")) != NULL) {
@@ -1023,54 +1001,60 @@ static int selinux_parse_opts_str(char *options,

		token = match_token(p, tokens, args);

		if (!opts) {
			opts = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL);
			if (!opts)
				return -ENOMEM;
		}

		switch (token) {
		case Opt_context:
			if (context || defcontext) {
			if (opts->context || opts->defcontext) {
				rc = -EINVAL;
				pr_warn(SEL_MOUNT_FAIL_MSG);
				goto out_err;
			}
			context = match_strdup(&args[0]);
			if (!context) {
			opts->context = match_strdup(&args[0]);
			if (!opts->context) {
				rc = -ENOMEM;
				goto out_err;
			}
			break;

		case Opt_fscontext:
			if (fscontext) {
			if (opts->fscontext) {
				rc = -EINVAL;
				pr_warn(SEL_MOUNT_FAIL_MSG);
				goto out_err;
			}
			fscontext = match_strdup(&args[0]);
			if (!fscontext) {
			opts->fscontext = match_strdup(&args[0]);
			if (!opts->fscontext) {
				rc = -ENOMEM;
				goto out_err;
			}
			break;

		case Opt_rootcontext:
			if (rootcontext) {
			if (opts->rootcontext) {
				rc = -EINVAL;
				pr_warn(SEL_MOUNT_FAIL_MSG);
				goto out_err;
			}
			rootcontext = match_strdup(&args[0]);
			if (!rootcontext) {
			opts->rootcontext = match_strdup(&args[0]);
			if (!opts->rootcontext) {
				rc = -ENOMEM;
				goto out_err;
			}
			break;

		case Opt_defcontext:
			if (context || defcontext) {
			if (opts->context || opts->defcontext) {
				rc = -EINVAL;
				pr_warn(SEL_MOUNT_FAIL_MSG);
				goto out_err;
			}
			defcontext = match_strdup(&args[0]);
			if (!defcontext) {
			opts->defcontext = match_strdup(&args[0]);
			if (!opts->defcontext) {
				rc = -ENOMEM;
				goto out_err;
			}
@@ -1084,43 +1068,12 @@ static int selinux_parse_opts_str(char *options,

		}
	}

	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;
	*mnt_opts = opts;
	return 0;

out_err:
	security_free_mnt_opts(mnt_opts);
	kfree(context);
	kfree(defcontext);
	kfree(fscontext);
	kfree(rootcontext);
	if (opts)
		selinux_free_mnt_opts(opts);
	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)
{
	struct security_mnt_opts *opts = mnt_opts;
	int i, *flags;
	char **mount_options;
	struct selinux_mnt_opts *opts = mnt_opts;
	struct superblock_security_struct *sbsec = sb->s_security;
	u32 sid;
	int rc;

	if (!(sbsec->flags & SE_SBINITIALIZED))
		return 0;
@@ -2763,48 +2716,35 @@ static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
	if (!opts)
		return 0;

	mount_options = opts->mnt_opts;
	flags = opts->mnt_opts_flags;

	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);
	if (opts->fscontext) {
		rc = parse_sid(sb, opts->fscontext, &sid);
		if (rc)
			return rc;
		}
		switch (flags[i]) {
		case FSCONTEXT_MNT:
		if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
			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))
			goto out_bad_option;
			break;
		case ROOTCONTEXT_MNT: {
	}
	if (opts->rootcontext) {
		struct inode_security_struct *root_isec;
		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))
			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))
			goto out_bad_option;
			break;
		default:
			return -EINVAL;
		}
	}
	return 0;