Commit 84196390 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull selinux fixes from Paul Moore:
 "Three SELinux patches:

   - Fix a problem where a local variable is used outside its associated
     function. Thankfully this can only be triggered by reloading the
     SELinux policy, which is a restricted operation for other obvious
     reasons.

   - Fix some incorrect, and inconsistent, audit and printk messages
     when loading the SELinux policy.

  All three patches are relatively minor and have been through our
  testing with no failures"

* tag 'selinux-pr-20210322' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  selinuxfs: unify policy load error reporting
  selinux: fix variable scope issue in live sidtab conversion
  selinux: don't log MAC_POLICY_LOAD record on failed policy load
parents 0d02ec6b ee5de60a
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -219,14 +219,21 @@ static inline bool selinux_policycap_genfs_seclabel_symlinks(void)
	return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS]);
}

struct selinux_policy_convert_data;

struct selinux_load_state {
	struct selinux_policy *policy;
	struct selinux_policy_convert_data *convert_data;
};

int security_mls_enabled(struct selinux_state *state);
int security_load_policy(struct selinux_state *state,
			 void *data, size_t len,
			struct selinux_policy **newpolicyp);
			 struct selinux_load_state *load_state);
void selinux_policy_commit(struct selinux_state *state,
			struct selinux_policy *newpolicy);
			   struct selinux_load_state *load_state);
void selinux_policy_cancel(struct selinux_state *state,
			struct selinux_policy *policy);
			   struct selinux_load_state *load_state);
int security_read_policy(struct selinux_state *state,
			 void **data, size_t *len);
int security_read_state_kernel(struct selinux_state *state,
+9 −13
Original line number Diff line number Diff line
@@ -563,17 +563,13 @@ static int sel_make_policy_nodes(struct selinux_fs_info *fsi,

	ret = sel_make_bools(newpolicy, tmp_bool_dir, &tmp_bool_num,
			     &tmp_bool_names, &tmp_bool_values);
	if (ret) {
		pr_err("SELinux: failed to load policy booleans\n");
	if (ret)
		goto out;
	}

	ret = sel_make_classes(newpolicy, tmp_class_dir,
			       &fsi->last_class_ino);
	if (ret) {
		pr_err("SELinux: failed to load policy classes\n");
	if (ret)
		goto out;
	}

	/* booleans */
	old_dentry = fsi->bool_dir;
@@ -616,7 +612,7 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,

{
	struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
	struct selinux_policy *newpolicy;
	struct selinux_load_state load_state;
	ssize_t length;
	void *data = NULL;

@@ -642,23 +638,23 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
	if (copy_from_user(data, buf, count) != 0)
		goto out;

	length = security_load_policy(fsi->state, data, count, &newpolicy);
	length = security_load_policy(fsi->state, data, count, &load_state);
	if (length) {
		pr_warn_ratelimited("SELinux: failed to load policy\n");
		goto out;
	}

	length = sel_make_policy_nodes(fsi, newpolicy);
	length = sel_make_policy_nodes(fsi, load_state.policy);
	if (length) {
		selinux_policy_cancel(fsi->state, newpolicy);
		goto out1;
		pr_warn_ratelimited("SELinux: failed to initialize selinuxfs\n");
		selinux_policy_cancel(fsi->state, &load_state);
		goto out;
	}

	selinux_policy_commit(fsi->state, newpolicy);
	selinux_policy_commit(fsi->state, &load_state);

	length = count;

out1:
	audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
		"auid=%u ses=%u lsm=selinux res=1",
		from_kuid(&init_user_ns, audit_get_loginuid(current)),
+39 −24
Original line number Diff line number Diff line
@@ -67,6 +67,17 @@
#include "policycap_names.h"
#include "ima.h"

struct convert_context_args {
	struct selinux_state *state;
	struct policydb *oldp;
	struct policydb *newp;
};

struct selinux_policy_convert_data {
	struct convert_context_args args;
	struct sidtab_convert_params sidtab_params;
};

/* Forward declaration. */
static int context_struct_to_string(struct policydb *policydb,
				    struct context *context,
@@ -1974,12 +1985,6 @@ static inline int convert_context_handle_invalid_context(
	return 0;
}

struct convert_context_args {
	struct selinux_state *state;
	struct policydb *oldp;
	struct policydb *newp;
};

/*
 * Convert the values in the security context
 * structure `oldc' from the values specified
@@ -2159,7 +2164,7 @@ static void selinux_policy_cond_free(struct selinux_policy *policy)
}

void selinux_policy_cancel(struct selinux_state *state,
			struct selinux_policy *policy)
			   struct selinux_load_state *load_state)
{
	struct selinux_policy *oldpolicy;

@@ -2167,7 +2172,8 @@ void selinux_policy_cancel(struct selinux_state *state,
					lockdep_is_held(&state->policy_mutex));

	sidtab_cancel_convert(oldpolicy->sidtab);
	selinux_policy_free(policy);
	selinux_policy_free(load_state->policy);
	kfree(load_state->convert_data);
}

static void selinux_notify_policy_change(struct selinux_state *state,
@@ -2183,9 +2189,9 @@ static void selinux_notify_policy_change(struct selinux_state *state,
}

void selinux_policy_commit(struct selinux_state *state,
			struct selinux_policy *newpolicy)
			   struct selinux_load_state *load_state)
{
	struct selinux_policy *oldpolicy;
	struct selinux_policy *oldpolicy, *newpolicy = load_state->policy;
	u32 seqno;

	oldpolicy = rcu_dereference_protected(state->policy,
@@ -2225,6 +2231,7 @@ void selinux_policy_commit(struct selinux_state *state,
	/* Free the old policy */
	synchronize_rcu();
	selinux_policy_free(oldpolicy);
	kfree(load_state->convert_data);

	/* Notify others of the policy change */
	selinux_notify_policy_change(state, seqno);
@@ -2241,11 +2248,10 @@ void selinux_policy_commit(struct selinux_state *state,
 * loading the new policy.
 */
int security_load_policy(struct selinux_state *state, void *data, size_t len,
			struct selinux_policy **newpolicyp)
			 struct selinux_load_state *load_state)
{
	struct selinux_policy *newpolicy, *oldpolicy;
	struct sidtab_convert_params convert_params;
	struct convert_context_args args;
	struct selinux_policy_convert_data *convert_data;
	int rc = 0;
	struct policy_file file = { data, len }, *fp = &file;

@@ -2275,10 +2281,10 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len,
		goto err_mapping;
	}


	if (!selinux_initialized(state)) {
		/* First policy load, so no need to preserve state from old policy */
		*newpolicyp = newpolicy;
		load_state->policy = newpolicy;
		load_state->convert_data = NULL;
		return 0;
	}

@@ -2292,29 +2298,38 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len,
		goto err_free_isids;
	}

	convert_data = kmalloc(sizeof(*convert_data), GFP_KERNEL);
	if (!convert_data) {
		rc = -ENOMEM;
		goto err_free_isids;
	}

	/*
	 * Convert the internal representations of contexts
	 * in the new SID table.
	 */
	args.state = state;
	args.oldp = &oldpolicy->policydb;
	args.newp = &newpolicy->policydb;
	convert_data->args.state = state;
	convert_data->args.oldp = &oldpolicy->policydb;
	convert_data->args.newp = &newpolicy->policydb;

	convert_params.func = convert_context;
	convert_params.args = &args;
	convert_params.target = newpolicy->sidtab;
	convert_data->sidtab_params.func = convert_context;
	convert_data->sidtab_params.args = &convert_data->args;
	convert_data->sidtab_params.target = newpolicy->sidtab;

	rc = sidtab_convert(oldpolicy->sidtab, &convert_params);
	rc = sidtab_convert(oldpolicy->sidtab, &convert_data->sidtab_params);
	if (rc) {
		pr_err("SELinux:  unable to convert the internal"
			" representation of contexts in the new SID"
			" table\n");
		goto err_free_isids;
		goto err_free_convert_data;
	}

	*newpolicyp = newpolicy;
	load_state->policy = newpolicy;
	load_state->convert_data = convert_data;
	return 0;

err_free_convert_data:
	kfree(convert_data);
err_free_isids:
	sidtab_destroy(newpolicy->sidtab);
err_mapping: