mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-03 10:10:33 +02:00 
			
		
		
		
	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: Janne Karhunen <janne.karhunen@gmail.com>
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
			
			
This commit is contained in:
		
							parent
							
								
									42df744c41
								
							
						
					
					
						commit
						b169424551
					
				
					 3 changed files with 106 additions and 20 deletions
				
			
		| 
						 | 
					@ -154,6 +154,8 @@ unsigned long ima_get_binary_runtime_size(void);
 | 
				
			||||||
int ima_init_template(void);
 | 
					int ima_init_template(void);
 | 
				
			||||||
void ima_init_template_list(void);
 | 
					void ima_init_template_list(void);
 | 
				
			||||||
int __init ima_init_digests(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
 | 
					 * used to protect h_table and sha_table
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,6 +43,10 @@ int ima_appraise;
 | 
				
			||||||
int ima_hash_algo = HASH_ALGO_SHA1;
 | 
					int ima_hash_algo = HASH_ALGO_SHA1;
 | 
				
			||||||
static int hash_setup_done;
 | 
					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)
 | 
					static int __init hash_setup(char *str)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ima_template_desc *template_desc = ima_template_desc_current();
 | 
						struct ima_template_desc *template_desc = ima_template_desc_current();
 | 
				
			||||||
| 
						 | 
					@ -621,6 +625,10 @@ static int __init init_ima(void)
 | 
				
			||||||
		error = ima_init();
 | 
							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)
 | 
						if (!error)
 | 
				
			||||||
		ima_update_policy_flag();
 | 
							ima_update_policy_flag();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -249,31 +249,113 @@ static int __init default_appraise_policy_setup(char *str)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
__setup("ima_appraise_tcb", default_appraise_policy_setup);
 | 
					__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
 | 
					 * 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
 | 
					 * 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
 | 
					 * the reloaded LSM policy.
 | 
				
			||||||
 * they don't.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void ima_lsm_update_rules(void)
 | 
					static void ima_lsm_update_rules(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ima_rule_entry *entry;
 | 
						struct ima_rule_entry *entry, *e;
 | 
				
			||||||
	int result;
 | 
						int i, result, needs_update;
 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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++) {
 | 
							for (i = 0; i < MAX_LSM_RULES; i++) {
 | 
				
			||||||
			if (!entry->lsm[i].rule)
 | 
								if (entry->lsm[i].rule) {
 | 
				
			||||||
				continue;
 | 
									needs_update = 1;
 | 
				
			||||||
			result = security_filter_rule_init(entry->lsm[i].type,
 | 
									break;
 | 
				
			||||||
							   Audit_equal,
 | 
								}
 | 
				
			||||||
							   entry->lsm[i].args_p,
 | 
							}
 | 
				
			||||||
							   &entry->lsm[i].rule);
 | 
							if (!needs_update)
 | 
				
			||||||
			BUG_ON(!entry->lsm[i].rule);
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * ima_match_rules - determine whether an inode matches the measure rule.
 | 
					 * ima_match_rules - determine whether an inode matches the measure rule.
 | 
				
			||||||
 * @rule: a pointer to a rule
 | 
					 * @rule: a pointer to a rule
 | 
				
			||||||
| 
						 | 
					@ -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++) {
 | 
						for (i = 0; i < MAX_LSM_RULES; i++) {
 | 
				
			||||||
		int rc = 0;
 | 
							int rc = 0;
 | 
				
			||||||
		u32 osid;
 | 
							u32 osid;
 | 
				
			||||||
		int retried = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!rule->lsm[i].rule)
 | 
							if (!rule->lsm[i].rule)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
retry:
 | 
					
 | 
				
			||||||
		switch (i) {
 | 
							switch (i) {
 | 
				
			||||||
		case LSM_OBJ_USER:
 | 
							case LSM_OBJ_USER:
 | 
				
			||||||
		case LSM_OBJ_ROLE:
 | 
							case LSM_OBJ_ROLE:
 | 
				
			||||||
| 
						 | 
					@ -352,11 +433,6 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if ((rc < 0) && (!retried)) {
 | 
					 | 
				
			||||||
			retried = 1;
 | 
					 | 
				
			||||||
			ima_lsm_update_rules();
 | 
					 | 
				
			||||||
			goto retry;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (!rc)
 | 
							if (!rc)
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue