diff --git a/fs/inode.c b/fs/inode.c index 86464332e590dfdc9cbf041515f038f0de1d846d..56d909d69bc88cda72bb70a528fbf0c70e877d0d 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -24,6 +24,7 @@ #include #include #include +#include /* * This is needed for the following functions: diff --git a/include/linux/fs.h b/include/linux/fs.h index 63d069bd80b702c392d4052bf2be937f90763692..01e3a0047fed244b2ee4e71712a562b035f99ee7 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -776,6 +776,10 @@ struct inode { unsigned int i_flags; +#ifdef CONFIG_IMA + /* protected by i_lock */ + unsigned int i_readcount; /* struct files open RO */ +#endif atomic_t i_writecount; #ifdef CONFIG_SECURITY void *i_security; diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index b546b90f5fa874a6be1bbfad9ef47f029735c053..27849e1656dc25ffc6391c903e7133e3c05794fe 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -70,6 +70,7 @@ int ima_init(void); void ima_cleanup(void); int ima_fs_init(void); void ima_fs_cleanup(void); +int ima_inode_alloc(struct inode *inode); int ima_add_template_entry(struct ima_template_entry *entry, int violation, const char *op, struct inode *inode); int ima_calc_hash(struct file *file, char *digest); @@ -106,8 +107,6 @@ struct ima_iint_cache { unsigned char flags; u8 digest[IMA_DIGEST_SIZE]; struct mutex mutex; /* protects: version, flags, digest */ - /* protected by inode->i_lock */ - unsigned int readcount; /* measured files readcount */ struct kref refcount; /* ima_iint_cache reference count */ }; diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 52015d098fdfd6d1823cf44ccfef1e754605884f..d3963de6003da423c26cc1028258fe70fd1cf1b3 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -116,7 +116,7 @@ int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode, { int must_measure; - if (iint->flags & IMA_MEASURED) + if (iint && iint->flags & IMA_MEASURED) return 1; must_measure = ima_match_policy(inode, function, mask); diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c index e68891f8d55afe1aadca81885e499c57643b469c..0936a7197e477b6eaaa5fb4ac87439009b686b62 100644 --- a/security/integrity/ima/ima_iint.c +++ b/security/integrity/ima/ima_iint.c @@ -124,11 +124,6 @@ void iint_free(struct kref *kref) refcount); iint->version = 0; iint->flags = 0UL; - if (iint->readcount != 0) { - printk(KERN_INFO "%s: readcount: %u\n", __func__, - iint->readcount); - iint->readcount = 0; - } kref_init(&iint->refcount); kmem_cache_free(iint_cache, iint); } @@ -143,6 +138,11 @@ void ima_inode_free(struct inode *inode) { struct ima_iint_cache *iint; + if (inode->i_readcount) + printk(KERN_INFO "%s: readcount: %u\n", __func__, inode->i_readcount); + + inode->i_readcount = 0; + spin_lock(&ima_iint_lock); iint = __ima_iint_find(inode); if (iint) @@ -160,7 +160,6 @@ static void init_once(void *foo) iint->version = 0; iint->flags = 0UL; mutex_init(&iint->mutex); - iint->readcount = 0; kref_init(&iint->refcount); } diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 24660bf3f82ab27a22de12a551961e84772738bc..2a77b14fee27cf11327aa8581112fa11a30a0bc0 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -85,17 +85,6 @@ static bool ima_limit_imbalance(struct file *file) return found; } -/* - * Update the counts given an fmode_t - */ -static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode) -{ - assert_spin_locked(&iint->inode->i_lock); - - if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) - iint->readcount++; -} - /* * ima_counts_get - increment file counts * @@ -112,27 +101,23 @@ void ima_counts_get(struct file *file) struct dentry *dentry = file->f_path.dentry; struct inode *inode = dentry->d_inode; fmode_t mode = file->f_mode; - struct ima_iint_cache *iint; int rc; bool send_tomtou = false, send_writers = false; - if (!iint_initialized || !S_ISREG(inode->i_mode)) + if (!S_ISREG(inode->i_mode)) return; - iint = ima_iint_find_get(inode); - if (!iint) - return; - mutex_lock(&iint->mutex); + spin_lock(&inode->i_lock); if (!ima_initialized) goto out; - rc = ima_must_measure(iint, inode, MAY_READ, FILE_CHECK); + rc = ima_must_measure(NULL, inode, MAY_READ, FILE_CHECK); if (rc < 0) goto out; if (mode & FMODE_WRITE) { - if (iint->readcount) + if (inode->i_readcount) send_tomtou = true; goto out; } @@ -140,10 +125,10 @@ void ima_counts_get(struct file *file) if (atomic_read(&inode->i_writecount) > 0) send_writers = true; out: - ima_inc_counts(iint, file->f_mode); + /* remember the vfs deals with i_writecount */ + if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) + inode->i_readcount++; spin_unlock(&inode->i_lock); - mutex_unlock(&iint->mutex); - kref_put(&iint->refcount, iint_free); if (send_tomtou) ima_add_violation(inode, dentry->d_name.name, "invalid_pcr", @@ -166,9 +151,9 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, assert_spin_locked(&inode->i_lock); if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { - if (unlikely(iint->readcount == 0)) + if (unlikely(inode->i_readcount == 0)) dump = true; - iint->readcount--; + inode->i_readcount--; } if (mode & FMODE_WRITE) { if (atomic_read(&inode->i_writecount) <= 0) @@ -180,7 +165,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, if (dump && !ima_limit_imbalance(file)) { printk(KERN_INFO "%s: open/free imbalance (r:%u)\n", - __func__, iint->readcount); + __func__, inode->i_readcount); dump_stack(); } }