From: Janne Karhunen janne.karhunen@gmail.com
mainline inclusion from mainline-v5.6-rc1 commit 483ec26eed42bf050931d9a5c5f9f0b5f2ad5f3b category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I692HU CVE: NA
--------------------------------
Keep the ima policy rules around from the beginning even if they appear invalid at the time of loading, as they may become active after an lsm policy load. However, loading a custom IMA policy with unknown LSM labels is only safe after we have transitioned from the "built-in" policy rules to a custom IMA policy.
Patch also fixes the rule re-use during the lsm policy reload and makes some prints a bit more human readable.
Changelog: v4: - Do not allow the initial policy load refer to non-existing lsm rules. v3: - Fix too wide policy rule matching for non-initialized LSMs v2: - Fix log prints
Fixes: b16942455193 ("ima: use the lsm policy update notifier") Cc: Casey Schaufler casey@schaufler-ca.com Reported-by: Mimi Zohar zohar@linux.ibm.com Signed-off-by: Janne Karhunen janne.karhunen@gmail.com Signed-off-by: Konsta Karsisto konsta.karsisto@gmail.com Signed-off-by: Mimi Zohar zohar@linux.ibm.com Conflicts: security/integrity/ima/ima_policy.c Signed-off-by: GUO Zihua guozihua@huawei.com Reviewed-by: Xiu Jianfeng xiujianfeng@huawei.com Signed-off-by: Yongqiang Liu liuyongqiang13@huawei.com --- security/integrity/ima/ima_policy.c | 45 +++++++++++++++++------------ 1 file changed, 27 insertions(+), 18 deletions(-)
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index b3ce17203db9..2aff6f9ef0e9 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -264,7 +264,7 @@ static void ima_free_rule(struct ima_rule_entry *entry) static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry) { struct ima_rule_entry *nentry; - int i, result; + int i;
nentry = kmalloc(sizeof(*nentry), GFP_KERNEL); if (!nentry) @@ -278,7 +278,7 @@ static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry) memset(nentry->lsm, 0, FIELD_SIZEOF(struct ima_rule_entry, lsm));
for (i = 0; i < MAX_LSM_RULES; i++) { - if (!entry->lsm[i].rule) + if (!entry->lsm[i].args_p) continue;
nentry->lsm[i].type = entry->lsm[i].type; @@ -287,13 +287,13 @@ static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry) 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); + security_filter_rule_init(nentry->lsm[i].type, + Audit_equal, + nentry->lsm[i].args_p, + &nentry->lsm[i].rule); + if (!nentry->lsm[i].rule) + pr_warn("rule for LSM '%s' is undefined\n", + (char *)entry->lsm[i].args_p); } return nentry;
@@ -332,7 +332,7 @@ static void ima_lsm_update_rules(void) 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].args_p) { needs_update = 1; break; } @@ -342,8 +342,7 @@ static void ima_lsm_update_rules(void)
result = ima_lsm_update_rule(entry); if (result) { - pr_err("ima: lsm rule update error %d\n", - result); + pr_err("lsm rule update error %d\n", result); return; } } @@ -360,7 +359,7 @@ int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event, }
/** - * ima_match_rules - determine whether an inode matches the measure rule. + * ima_match_rules - determine whether an inode matches the policy rule. * @rule: a pointer to a rule * @inode: a pointer to an inode * @cred: a pointer to a credentials structure for user validation @@ -416,8 +415,12 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode, int rc = 0; u32 osid;
- if (!lsm_rule->lsm[i].rule) - continue; + if (!lsm_rule->lsm[i].rule) { + if (!lsm_rule->lsm[i].args_p) + continue; + else + return false; + }
retry: switch (i) { @@ -755,9 +758,15 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry, entry->lsm[lsm_rule].args_p, &entry->lsm[lsm_rule].rule); if (!entry->lsm[lsm_rule].rule) { - kfree(entry->lsm[lsm_rule].args_p); - entry->lsm[lsm_rule].args_p = NULL; - return -EINVAL; + pr_warn("rule for LSM '%s' is undefined\n", + (char *)entry->lsm[lsm_rule].args_p); + + if (ima_rules == &ima_default_rules) { + kfree(entry->lsm[lsm_rule].args_p); + entry->lsm[lsm_rule].args_p = NULL; + result = -EINVAL; + } else + result = 0; }
return result;