From: Greg Kroah-Hartman Date: Fri, 3 Feb 2023 07:44:21 +0000 (+0100) Subject: 4.19-stable patches X-Git-Tag: v4.14.305~24 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ca5e5bbf0e44be076e9bf48f2baedce79c73349d;p=thirdparty%2Fkernel%2Fstable-queue.git 4.19-stable patches added patches: ima-handle-estale-returned-by-ima_filter_rule_match.patch ima-use-the-lsm-policy-update-notifier.patch lsm-switch-to-blocking-policy-update-notifiers.patch --- diff --git a/queue-4.19/ima-handle-estale-returned-by-ima_filter_rule_match.patch b/queue-4.19/ima-handle-estale-returned-by-ima_filter_rule_match.patch new file mode 100644 index 00000000000..b561357a29f --- /dev/null +++ b/queue-4.19/ima-handle-estale-returned-by-ima_filter_rule_match.patch @@ -0,0 +1,107 @@ +From c7423dbdbc9ecef7fff5239d144cad4b9887f4de Mon Sep 17 00:00:00 2001 +From: GUO Zihua +Date: Wed, 21 Sep 2022 20:58:04 +0800 +Subject: ima: Handle -ESTALE returned by ima_filter_rule_match() + +From: GUO Zihua + +commit c7423dbdbc9ecef7fff5239d144cad4b9887f4de upstream. + +IMA relies on the blocking LSM policy notifier callback to update the +LSM based IMA policy rules. + +When SELinux update its policies, IMA would be notified and starts +updating all its lsm rules one-by-one. During this time, -ESTALE would +be returned by ima_filter_rule_match() if it is called with a LSM rule +that has not yet been updated. In ima_match_rules(), -ESTALE is not +handled, and the LSM rule is considered a match, causing extra files +to be measured by IMA. + +Fix it by re-initializing a temporary rule if -ESTALE is returned by +ima_filter_rule_match(). The origin rule in the rule list would be +updated by the LSM policy notifier callback. + +Fixes: b16942455193 ("ima: use the lsm policy update notifier") +Signed-off-by: GUO Zihua +Reviewed-by: Roberto Sassu +Signed-off-by: Mimi Zohar +Signed-off-by: GUO Zihua +Signed-off-by: Greg Kroah-Hartman +--- + security/integrity/ima/ima_policy.c | 37 ++++++++++++++++++++++++++++-------- + 1 file changed, 29 insertions(+), 8 deletions(-) + +--- a/security/integrity/ima/ima_policy.c ++++ b/security/integrity/ima/ima_policy.c +@@ -375,6 +375,9 @@ static bool ima_match_rules(struct ima_r + enum ima_hooks func, int mask) + { + int i; ++ bool result = false; ++ struct ima_rule_entry *lsm_rule = rule; ++ bool rule_reinitialized = false; + + if ((rule->flags & IMA_FUNC) && + (rule->func != func && func != POST_SETATTR)) +@@ -413,35 +416,53 @@ static bool ima_match_rules(struct ima_r + int rc = 0; + u32 osid; + +- if (!rule->lsm[i].rule) ++ if (!lsm_rule->lsm[i].rule) + continue; + ++retry: + switch (i) { + case LSM_OBJ_USER: + case LSM_OBJ_ROLE: + case LSM_OBJ_TYPE: + security_inode_getsecid(inode, &osid); + rc = security_filter_rule_match(osid, +- rule->lsm[i].type, ++ lsm_rule->lsm[i].type, + Audit_equal, +- rule->lsm[i].rule, ++ lsm_rule->lsm[i].rule, + NULL); + break; + case LSM_SUBJ_USER: + case LSM_SUBJ_ROLE: + case LSM_SUBJ_TYPE: + rc = security_filter_rule_match(secid, +- rule->lsm[i].type, ++ lsm_rule->lsm[i].type, + Audit_equal, +- rule->lsm[i].rule, ++ lsm_rule->lsm[i].rule, + NULL); + default: + break; + } +- if (!rc) +- return false; ++ ++ if (rc == -ESTALE && !rule_reinitialized) { ++ lsm_rule = ima_lsm_copy_rule(rule); ++ if (lsm_rule) { ++ rule_reinitialized = true; ++ goto retry; ++ } ++ } ++ if (!rc) { ++ result = false; ++ goto out; ++ } ++ } ++ result = true; ++ ++out: ++ if (rule_reinitialized) { ++ ima_lsm_free_rule(lsm_rule); ++ kfree(lsm_rule); + } +- return true; ++ return result; + } + + /* diff --git a/queue-4.19/ima-use-the-lsm-policy-update-notifier.patch b/queue-4.19/ima-use-the-lsm-policy-update-notifier.patch new file mode 100644 index 00000000000..3e2a751cad4 --- /dev/null +++ b/queue-4.19/ima-use-the-lsm-policy-update-notifier.patch @@ -0,0 +1,227 @@ +From b169424551930a9325f700f502802f4d515194e5 Mon Sep 17 00:00:00 2001 +From: Janne Karhunen +Date: Fri, 14 Jun 2019 15:20:15 +0300 +Subject: ima: use the lsm policy update notifier + +From: Janne Karhunen + +commit b169424551930a9325f700f502802f4d515194e5 upstream. + +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 +Signed-off-by: Mimi Zohar +Signed-off-by: GUO Zihua +Signed-off-by: Greg Kroah-Hartman +--- + security/integrity/ima/ima.h | 2 + security/integrity/ima/ima_main.c | 8 ++ + security/integrity/ima/ima_policy.c | 118 ++++++++++++++++++++++++++++-------- + 3 files changed, 105 insertions(+), 23 deletions(-) + +--- a/security/integrity/ima/ima.h ++++ b/security/integrity/ima/ima.h +@@ -154,6 +154,8 @@ int ima_measurements_show(struct seq_fil + unsigned long ima_get_binary_runtime_size(void); + int ima_init_template(void); + void ima_init_template_list(void); ++int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event, ++ void *lsm_data); + + /* + * used to protect h_table and sha_table +--- a/security/integrity/ima/ima_main.c ++++ b/security/integrity/ima/ima_main.c +@@ -41,6 +41,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(); +@@ -553,6 +557,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(); + +--- a/security/integrity/ima/ima_policy.c ++++ b/security/integrity/ima/ima_policy.c +@@ -241,46 +241,124 @@ static int __init default_appraise_polic + } + __setup("ima_appraise_tcb", default_appraise_policy_setup); + +-static void ima_free_rule(struct ima_rule_entry *entry) ++static void ima_lsm_free_rule(struct ima_rule_entry *entry) + { + int i; + ++ for (i = 0; i < MAX_LSM_RULES; i++) { ++ security_filter_rule_free(entry->lsm[i].rule); ++ kfree(entry->lsm[i].args_p); ++ } ++} ++ ++static void ima_free_rule(struct ima_rule_entry *entry) ++{ + if (!entry) + return; + + kfree(entry->fsname); ++ ima_lsm_free_rule(entry); ++ 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++) { +- security_filter_rule_free(entry->lsm[i].rule); +- kfree(entry->lsm[i].args_p); ++ 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); ++ kfree(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); + kfree(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 +@@ -334,11 +412,10 @@ static bool ima_match_rules(struct ima_r + 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: +@@ -361,11 +438,6 @@ retry: + default: + break; + } +- if ((rc < 0) && (!retried)) { +- retried = 1; +- ima_lsm_update_rules(); +- goto retry; +- } + if (!rc) + return false; + } diff --git a/queue-4.19/lsm-switch-to-blocking-policy-update-notifiers.patch b/queue-4.19/lsm-switch-to-blocking-policy-update-notifiers.patch new file mode 100644 index 00000000000..4e8b0c7fcc0 --- /dev/null +++ b/queue-4.19/lsm-switch-to-blocking-policy-update-notifiers.patch @@ -0,0 +1,154 @@ +From 42df744c4166af6959eda2df1ee5cde744d4a1c3 Mon Sep 17 00:00:00 2001 +From: Janne Karhunen +Date: Fri, 14 Jun 2019 15:20:14 +0300 +Subject: LSM: switch to blocking policy update notifiers + +From: Janne Karhunen + +commit 42df744c4166af6959eda2df1ee5cde744d4a1c3 upstream. + +Atomic policy updaters are not very useful as they cannot +usually perform the policy updates on their own. Since it +seems that there is no strict need for the atomicity, +switch to the blocking variant. While doing so, rename +the functions accordingly. + +Signed-off-by: Janne Karhunen +Acked-by: Paul Moore +Acked-by: James Morris +Signed-off-by: Mimi Zohar +Signed-off-by: GUO Zihua +Signed-off-by: Greg Kroah-Hartman +--- + drivers/infiniband/core/device.c | 4 ++-- + include/linux/security.h | 12 ++++++------ + security/security.c | 23 +++++++++++++---------- + security/selinux/hooks.c | 2 +- + security/selinux/selinuxfs.c | 2 +- + 5 files changed, 23 insertions(+), 20 deletions(-) + +--- a/drivers/infiniband/core/device.c ++++ b/drivers/infiniband/core/device.c +@@ -1207,7 +1207,7 @@ static int __init ib_core_init(void) + goto err_mad; + } + +- ret = register_lsm_notifier(&ibdev_lsm_nb); ++ ret = register_blocking_lsm_notifier(&ibdev_lsm_nb); + if (ret) { + pr_warn("Couldn't register LSM notifier. ret %d\n", ret); + goto err_sa; +@@ -1243,7 +1243,7 @@ static void __exit ib_core_cleanup(void) + roce_gid_mgmt_cleanup(); + nldev_exit(); + rdma_nl_unregister(RDMA_NL_LS); +- unregister_lsm_notifier(&ibdev_lsm_nb); ++ unregister_blocking_lsm_notifier(&ibdev_lsm_nb); + ib_sa_cleanup(); + ib_mad_cleanup(); + addr_cleanup(); +--- a/include/linux/security.h ++++ b/include/linux/security.h +@@ -191,9 +191,9 @@ struct security_mnt_opts { + int num_mnt_opts; + }; + +-int call_lsm_notifier(enum lsm_event event, void *data); +-int register_lsm_notifier(struct notifier_block *nb); +-int unregister_lsm_notifier(struct notifier_block *nb); ++int call_blocking_lsm_notifier(enum lsm_event event, void *data); ++int register_blocking_lsm_notifier(struct notifier_block *nb); ++int unregister_blocking_lsm_notifier(struct notifier_block *nb); + + static inline void security_init_mnt_opts(struct security_mnt_opts *opts) + { +@@ -409,17 +409,17 @@ int security_inode_getsecctx(struct inod + struct security_mnt_opts { + }; + +-static inline int call_lsm_notifier(enum lsm_event event, void *data) ++static inline int call_blocking_lsm_notifier(enum lsm_event event, void *data) + { + return 0; + } + +-static inline int register_lsm_notifier(struct notifier_block *nb) ++static inline int register_blocking_lsm_notifier(struct notifier_block *nb) + { + return 0; + } + +-static inline int unregister_lsm_notifier(struct notifier_block *nb) ++static inline int unregister_blocking_lsm_notifier(struct notifier_block *nb) + { + return 0; + } +--- a/security/security.c ++++ b/security/security.c +@@ -38,7 +38,7 @@ + #define SECURITY_NAME_MAX 10 + + struct security_hook_heads security_hook_heads __lsm_ro_after_init; +-static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain); ++static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain); + + char *lsm_names; + /* Boot-time LSM user choice */ +@@ -180,23 +180,26 @@ void __init security_add_hooks(struct se + panic("%s - Cannot get early memory.\n", __func__); + } + +-int call_lsm_notifier(enum lsm_event event, void *data) ++int call_blocking_lsm_notifier(enum lsm_event event, void *data) + { +- return atomic_notifier_call_chain(&lsm_notifier_chain, event, data); ++ return blocking_notifier_call_chain(&blocking_lsm_notifier_chain, ++ event, data); + } +-EXPORT_SYMBOL(call_lsm_notifier); ++EXPORT_SYMBOL(call_blocking_lsm_notifier); + +-int register_lsm_notifier(struct notifier_block *nb) ++int register_blocking_lsm_notifier(struct notifier_block *nb) + { +- return atomic_notifier_chain_register(&lsm_notifier_chain, nb); ++ return blocking_notifier_chain_register(&blocking_lsm_notifier_chain, ++ nb); + } +-EXPORT_SYMBOL(register_lsm_notifier); ++EXPORT_SYMBOL(register_blocking_lsm_notifier); + +-int unregister_lsm_notifier(struct notifier_block *nb) ++int unregister_blocking_lsm_notifier(struct notifier_block *nb) + { +- return atomic_notifier_chain_unregister(&lsm_notifier_chain, nb); ++ return blocking_notifier_chain_unregister(&blocking_lsm_notifier_chain, ++ nb); + } +-EXPORT_SYMBOL(unregister_lsm_notifier); ++EXPORT_SYMBOL(unregister_blocking_lsm_notifier); + + /* + * Hook list operation macros. +--- a/security/selinux/hooks.c ++++ b/security/selinux/hooks.c +@@ -199,7 +199,7 @@ static int selinux_lsm_notifier_avc_call + { + if (event == AVC_CALLBACK_RESET) { + sel_ib_pkey_flush(); +- call_lsm_notifier(LSM_POLICY_CHANGE, NULL); ++ call_blocking_lsm_notifier(LSM_POLICY_CHANGE, NULL); + } + + return 0; +--- a/security/selinux/selinuxfs.c ++++ b/security/selinux/selinuxfs.c +@@ -180,7 +180,7 @@ static ssize_t sel_write_enforce(struct + selnl_notify_setenforce(new_value); + selinux_status_update_setenforce(state, new_value); + if (!new_value) +- call_lsm_notifier(LSM_POLICY_CHANGE, NULL); ++ call_blocking_lsm_notifier(LSM_POLICY_CHANGE, NULL); + } + length = count; + out: diff --git a/queue-4.19/series b/queue-4.19/series index 1a3b8fae3cb..81d7352de89 100644 --- a/queue-4.19/series +++ b/queue-4.19/series @@ -66,3 +66,6 @@ x86-asm-fix-an-assembler-warning-with-current-binutils.patch x86-entry-64-add-instruction-suffix-to-sysret.patch arm-dts-imx-fix-pca9547-i2c-mux-node-name.patch dmaengine-imx-sdma-fix-a-possible-memory-leak-in-sdm.patch +lsm-switch-to-blocking-policy-update-notifiers.patch +ima-use-the-lsm-policy-update-notifier.patch +ima-handle-estale-returned-by-ima_filter_rule_match.patch