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

Commit b1694245 authored by Janne Karhunen's avatar Janne Karhunen Committed by Mimi Zohar
Browse files

ima: use the lsm policy update notifier



Don't do lazy policy updates while running the rule matching,
run the updates as they happen.

Depends on commit f242064c5df3 ("LSM: switch to blocking policy update notifiers")

Signed-off-by: default avatarJanne Karhunen <janne.karhunen@gmail.com>
Signed-off-by: default avatarMimi Zohar <zohar@linux.ibm.com>
parent 42df744c
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -154,6 +154,8 @@ unsigned long ima_get_binary_runtime_size(void);
int ima_init_template(void);
void ima_init_template_list(void);
int __init ima_init_digests(void);
int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event,
			  void *lsm_data);

/*
 * used to protect h_table and sha_table
+8 −0
Original line number Diff line number Diff line
@@ -43,6 +43,10 @@ int ima_appraise;
int ima_hash_algo = HASH_ALGO_SHA1;
static int hash_setup_done;

static struct notifier_block ima_lsm_policy_notifier = {
	.notifier_call = ima_lsm_policy_change,
};

static int __init hash_setup(char *str)
{
	struct ima_template_desc *template_desc = ima_template_desc_current();
@@ -621,6 +625,10 @@ static int __init init_ima(void)
		error = ima_init();
	}

	error = register_blocking_lsm_notifier(&ima_lsm_policy_notifier);
	if (error)
		pr_warn("Couldn't register LSM notifier, error %d\n", error);

	if (!error)
		ima_update_policy_flag();

+96 −20
Original line number Diff line number Diff line
@@ -249,29 +249,111 @@ static int __init default_appraise_policy_setup(char *str)
}
__setup("ima_appraise_tcb", default_appraise_policy_setup);

static void ima_lsm_free_rule(struct ima_rule_entry *entry)
{
	int i;

	for (i = 0; i < MAX_LSM_RULES; i++) {
		kfree(entry->lsm[i].rule);
		kfree(entry->lsm[i].args_p);
	}
	kfree(entry);
}

static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry)
{
	struct ima_rule_entry *nentry;
	int i, result;

	nentry = kmalloc(sizeof(*nentry), GFP_KERNEL);
	if (!nentry)
		return NULL;

	/*
	 * Immutable elements are copied over as pointers and data; only
	 * lsm rules can change
	 */
	memcpy(nentry, entry, sizeof(*nentry));
	memset(nentry->lsm, 0, FIELD_SIZEOF(struct ima_rule_entry, lsm));

	for (i = 0; i < MAX_LSM_RULES; i++) {
		if (!entry->lsm[i].rule)
			continue;

		nentry->lsm[i].type = entry->lsm[i].type;
		nentry->lsm[i].args_p = kstrdup(entry->lsm[i].args_p,
						GFP_KERNEL);
		if (!nentry->lsm[i].args_p)
			goto out_err;

		result = security_filter_rule_init(nentry->lsm[i].type,
						   Audit_equal,
						   nentry->lsm[i].args_p,
						   &nentry->lsm[i].rule);
		if (result == -EINVAL)
			pr_warn("ima: rule for LSM \'%d\' is undefined\n",
				entry->lsm[i].type);
	}
	return nentry;

out_err:
	ima_lsm_free_rule(nentry);
	return NULL;
}

static int ima_lsm_update_rule(struct ima_rule_entry *entry)
{
	struct ima_rule_entry *nentry;

	nentry = ima_lsm_copy_rule(entry);
	if (!nentry)
		return -ENOMEM;

	list_replace_rcu(&entry->list, &nentry->list);
	synchronize_rcu();
	ima_lsm_free_rule(entry);

	return 0;
}

/*
 * The LSM policy can be reloaded, leaving the IMA LSM based rules referring
 * to the old, stale LSM policy.  Update the IMA LSM based rules to reflect
 * the reloaded LSM policy.  We assume the rules still exist; and BUG_ON() if
 * they don't.
 * the reloaded LSM policy.
 */
static void ima_lsm_update_rules(void)
{
	struct ima_rule_entry *entry;
	int result;
	int i;
	struct ima_rule_entry *entry, *e;
	int i, result, needs_update;

	list_for_each_entry(entry, &ima_policy_rules, list) {
	list_for_each_entry_safe(entry, e, &ima_policy_rules, list) {
		needs_update = 0;
		for (i = 0; i < MAX_LSM_RULES; i++) {
			if (!entry->lsm[i].rule)
			if (entry->lsm[i].rule) {
				needs_update = 1;
				break;
			}
		}
		if (!needs_update)
			continue;
			result = security_filter_rule_init(entry->lsm[i].type,
							   Audit_equal,
							   entry->lsm[i].args_p,
							   &entry->lsm[i].rule);
			BUG_ON(!entry->lsm[i].rule);

		result = ima_lsm_update_rule(entry);
		if (result) {
			pr_err("ima: lsm rule update error %d\n",
				result);
			return;
		}
	}
}

int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event,
			  void *lsm_data)
{
	if (event != LSM_POLICY_CHANGE)
		return NOTIFY_DONE;

	ima_lsm_update_rules();
	return NOTIFY_OK;
}

/**
@@ -327,11 +409,10 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
	for (i = 0; i < MAX_LSM_RULES; i++) {
		int rc = 0;
		u32 osid;
		int retried = 0;

		if (!rule->lsm[i].rule)
			continue;
retry:

		switch (i) {
		case LSM_OBJ_USER:
		case LSM_OBJ_ROLE:
@@ -352,11 +433,6 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
		default:
			break;
		}
		if ((rc < 0) && (!retried)) {
			retried = 1;
			ima_lsm_update_rules();
			goto retry;
		}
		if (!rc)
			return false;
	}