Align integrity_inode_attrs_changed() to ima_check_last_writer()'s
semantics when detecting changes.

For IMA, stacked file systems that do not set kstat.change_cookie,
integrity_inode_attrs_changed() will compare zero to zero, thus no
change detected. This is not dissimilar to what
ima_check_last_writer() does.

No logical change intended for EVM.

Signed-off-by: Frederick Lawler <[email protected]>
---
 include/linux/integrity.h         | 28 ++++++++++++++++++++++++----
 security/integrity/evm/evm_main.c |  5 ++---
 security/integrity/ima/ima_main.c |  5 ++---
 3 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/include/linux/integrity.h b/include/linux/integrity.h
index 
beb9ab19fa6257e79266b58bcb5f55b0c5445828..382c783f0fa3ae4a938cdf9559291ba1903a378e
 100644
--- a/include/linux/integrity.h
+++ b/include/linux/integrity.h
@@ -9,6 +9,7 @@
 
 #include <linux/fs.h>
 #include <linux/iversion.h>
+#include <linux/kernel.h>
 
 enum integrity_status {
        INTEGRITY_PASS = 0,
@@ -62,14 +63,33 @@ integrity_inode_attrs_stat_changed
 
 /*
  * On stacked filesystems detect whether the inode or its content has changed.
+ *
+ * Must be called in process context.
  */
 static inline bool
 integrity_inode_attrs_changed(const struct integrity_inode_attributes *attrs,
-                             const struct inode *inode)
+                             struct file *file, struct inode *inode)
 {
-       return (inode->i_sb->s_dev != attrs->dev ||
-               inode->i_ino != attrs->ino ||
-               !inode_eq_iversion(inode, attrs->version));
+       struct kstat stat;
+
+       might_sleep();
+
+       if (inode->i_sb->s_dev != attrs->dev || inode->i_ino != attrs->ino)
+               return true;
+
+       /*
+        * EVM currently relies on backing inode i_version. While IS_I_VERSION
+        * is not a good indicator of i_version support, this still retains
+        * the logic such that a re-evaluation should still occur for EVM, and
+        * only for IMA if vfs_getattr_nosec() fails.
+        */
+       if (!file || vfs_getattr_nosec(&file->f_path, &stat,
+                                      STATX_CHANGE_COOKIE,
+                                      AT_STATX_SYNC_AS_STAT))
+               return !IS_I_VERSION(inode) ||
+                      !inode_eq_iversion(inode, attrs->version);
+
+       return integrity_inode_attrs_stat_changed(attrs, &stat);
 }
 
 
diff --git a/security/integrity/evm/evm_main.c 
b/security/integrity/evm/evm_main.c
index 
73d500a375cb37a54f295b0e1e93fd6e5d9ecddc..6a4e0e246005246d5700b1db590c1759242b9cb6
 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -752,9 +752,8 @@ bool evm_metadata_changed(struct inode *inode, struct inode 
*metadata_inode)
        bool ret = false;
 
        if (iint) {
-               ret = (!IS_I_VERSION(metadata_inode) ||
-                      integrity_inode_attrs_changed(&iint->metadata_inode,
-                                                    metadata_inode));
+               ret = integrity_inode_attrs_changed(&iint->metadata_inode,
+                                                   NULL, metadata_inode);
                if (ret)
                        iint->evm_status = INTEGRITY_UNKNOWN;
        }
diff --git a/security/integrity/ima/ima_main.c 
b/security/integrity/ima/ima_main.c
index 
6570ad10887b9ea1172c78274cf62482350e87ff..8cb17c9d446caaa5a98f5ec8f027c17ba7babca8
 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -328,9 +328,8 @@ static int process_measurement(struct file *file, const 
struct cred *cred,
        real_inode = d_real_inode(file_dentry(file));
        if (real_inode != inode &&
            (action & IMA_DO_MASK) && (iint->flags & IMA_DONE_MASK)) {
-               if (!IS_I_VERSION(real_inode) ||
-                   integrity_inode_attrs_changed(&iint->real_inode,
-                                                 real_inode)) {
+               if (integrity_inode_attrs_changed(&iint->real_inode,
+                                                 file, real_inode)) {
                        iint->flags &= ~IMA_DONE_MASK;
                        iint->measured_pcrs = 0;
                }

-- 
2.43.0


Reply via email to