forked from mirrors/linux
		
	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); | ||||
| 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 | ||||
|  |  | |||
|  | @ -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(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -249,31 +249,113 @@ 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) | ||||
| 				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); | ||||
| 			if (entry->lsm[i].rule) { | ||||
| 				needs_update = 1; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		if (!needs_update) | ||||
| 			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. | ||||
|  * @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++) { | ||||
| 		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; | ||||
| 	} | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Janne Karhunen
						Janne Karhunen