]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 3 Feb 2023 07:44:21 +0000 (08:44 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 3 Feb 2023 07:44:21 +0000 (08:44 +0100)
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

queue-4.19/ima-handle-estale-returned-by-ima_filter_rule_match.patch [new file with mode: 0644]
queue-4.19/ima-use-the-lsm-policy-update-notifier.patch [new file with mode: 0644]
queue-4.19/lsm-switch-to-blocking-policy-update-notifiers.patch [new file with mode: 0644]
queue-4.19/series

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 (file)
index 0000000..b561357
--- /dev/null
@@ -0,0 +1,107 @@
+From c7423dbdbc9ecef7fff5239d144cad4b9887f4de Mon Sep 17 00:00:00 2001
+From: GUO Zihua <guozihua@huawei.com>
+Date: Wed, 21 Sep 2022 20:58:04 +0800
+Subject: ima: Handle -ESTALE returned by ima_filter_rule_match()
+
+From: GUO Zihua <guozihua@huawei.com>
+
+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 <guozihua@huawei.com>
+Reviewed-by: Roberto Sassu <roberto.sassu@huawei.com>
+Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
+Signed-off-by: GUO Zihua <guozihua@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..3e2a751
--- /dev/null
@@ -0,0 +1,227 @@
+From b169424551930a9325f700f502802f4d515194e5 Mon Sep 17 00:00:00 2001
+From: Janne Karhunen <janne.karhunen@gmail.com>
+Date: Fri, 14 Jun 2019 15:20:15 +0300
+Subject: ima: use the lsm policy update notifier
+
+From: Janne Karhunen <janne.karhunen@gmail.com>
+
+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 <janne.karhunen@gmail.com>
+Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
+Signed-off-by: GUO Zihua <guozihua@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..4e8b0c7
--- /dev/null
@@ -0,0 +1,154 @@
+From 42df744c4166af6959eda2df1ee5cde744d4a1c3 Mon Sep 17 00:00:00 2001
+From: Janne Karhunen <janne.karhunen@gmail.com>
+Date: Fri, 14 Jun 2019 15:20:14 +0300
+Subject: LSM: switch to blocking policy update notifiers
+
+From: Janne Karhunen <janne.karhunen@gmail.com>
+
+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 <janne.karhunen@gmail.com>
+Acked-by: Paul Moore <paul@paul-moore.com>
+Acked-by: James Morris <jamorris@linux.microsoft.com>
+Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
+Signed-off-by: GUO Zihua <guozihua@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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:
index 1a3b8fae3cbb0c202481e93ad14bf6ac4fd7624d..81d7352de89fa1871d7830661395a564b3792977 100644 (file)
@@ -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