From a68a27b6f2354273bacc39c3dd06456edb202230 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Tue, 2 Nov 2010 10:10:56 -0400 Subject: IMA: convert i_readcount to atomic Convert the inode's i_readcount from an unsigned int to atomic. Signed-off-by: Mimi Zohar Acked-by: Eric Paris --- security/integrity/ima/ima_iint.c | 7 ++++--- security/integrity/ima/ima_main.c | 11 ++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'security/integrity/ima') diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c index c442e47b6785..f0053552fd58 100644 --- a/security/integrity/ima/ima_iint.c +++ b/security/integrity/ima/ima_iint.c @@ -137,10 +137,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); + if (atomic_read(&inode->i_readcount)) + printk(KERN_INFO "%s: readcount: %u\n", __func__, + atomic_read(&inode->i_readcount)); - inode->i_readcount = 0; + atomic_set(&inode->i_readcount, 0); if (!IS_IMA(inode)) return; diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 203de979d305..6e8cb931b8f1 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -113,7 +113,7 @@ void ima_counts_get(struct file *file) goto out; if (mode & FMODE_WRITE) { - if (inode->i_readcount && IS_IMA(inode)) + if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) send_tomtou = true; goto out; } @@ -127,7 +127,7 @@ void ima_counts_get(struct file *file) out: /* remember the vfs deals with i_writecount */ if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) - inode->i_readcount++; + atomic_inc(&inode->i_readcount); spin_unlock(&inode->i_lock); @@ -149,15 +149,16 @@ static void ima_dec_counts(struct inode *inode, struct file *file) assert_spin_locked(&inode->i_lock); if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { - if (unlikely(inode->i_readcount == 0)) { + if (unlikely(atomic_read(&inode->i_readcount) == 0)) { if (!ima_limit_imbalance(file)) { printk(KERN_INFO "%s: open/free imbalance (r:%u)\n", - __func__, inode->i_readcount); + __func__, + atomic_read(&inode->i_readcount)); dump_stack(); } return; } - inode->i_readcount--; + atomic_dec(&inode->i_readcount); } } -- cgit v1.2.1 From 890275b5eb79e9933d12290473eab9ac38da0051 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Tue, 2 Nov 2010 10:13:07 -0400 Subject: IMA: maintain i_readcount in the VFS layer ima_counts_get() updated the readcount and invalidated the PCR, as necessary. Only update the i_readcount in the VFS layer. Move the PCR invalidation checks to ima_file_check(), where it belongs. Maintaining the i_readcount in the VFS layer, will allow other subsystems to use i_readcount. Signed-off-by: Mimi Zohar Acked-by: Eric Paris --- security/integrity/ima/ima_iint.c | 2 -- security/integrity/ima/ima_main.c | 25 ++++++++----------------- 2 files changed, 8 insertions(+), 19 deletions(-) (limited to 'security/integrity/ima') diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c index f0053552fd58..68efe3b8d993 100644 --- a/security/integrity/ima/ima_iint.c +++ b/security/integrity/ima/ima_iint.c @@ -141,8 +141,6 @@ void ima_inode_free(struct inode *inode) printk(KERN_INFO "%s: readcount: %u\n", __func__, atomic_read(&inode->i_readcount)); - atomic_set(&inode->i_readcount, 0); - if (!IS_IMA(inode)) return; diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 6e8cb931b8f1..69b4856af4da 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -86,17 +86,16 @@ out: } /* - * ima_counts_get - increment file counts + * ima_rdwr_violation_check * - * Maintain read/write counters for all files, but only - * invalidate the PCR for measured files: + * Only invalidate the PCR for measured files: * - Opening a file for write when already open for read, * results in a time of measure, time of use (ToMToU) error. * - Opening a file for read when already open for write, * could result in a file measurement error. * */ -void ima_counts_get(struct file *file) +static void ima_rdwr_violation_check(struct file *file) { struct dentry *dentry = file->f_path.dentry; struct inode *inode = dentry->d_inode; @@ -104,13 +103,10 @@ void ima_counts_get(struct file *file) int rc; bool send_tomtou = false, send_writers = false; - if (!S_ISREG(inode->i_mode)) + if (!S_ISREG(inode->i_mode) || !ima_initialized) return; - spin_lock(&inode->i_lock); - - if (!ima_initialized) - goto out; + mutex_lock(&inode->i_mutex); /* file metadata: permissions, xattr */ if (mode & FMODE_WRITE) { if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) @@ -125,11 +121,7 @@ void ima_counts_get(struct file *file) if (atomic_read(&inode->i_writecount) > 0) send_writers = true; out: - /* remember the vfs deals with i_writecount */ - if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) - atomic_inc(&inode->i_readcount); - - spin_unlock(&inode->i_lock); + mutex_unlock(&inode->i_mutex); if (send_tomtou) ima_add_violation(inode, dentry->d_name.name, "invalid_pcr", @@ -158,7 +150,6 @@ static void ima_dec_counts(struct inode *inode, struct file *file) } return; } - atomic_dec(&inode->i_readcount); } } @@ -203,8 +194,7 @@ static void ima_file_free_noiint(struct inode *inode, struct file *file) * ima_file_free - called on __fput() * @file: pointer to file structure being freed * - * Flag files that changed, based on i_version; - * and decrement the i_readcount. + * Flag files that changed, based on i_version */ void ima_file_free(struct file *file) { @@ -318,6 +308,7 @@ int ima_file_check(struct file *file, int mask) { int rc; + ima_rdwr_violation_check(file); rc = process_measurement(file, file->f_dentry->d_name.name, mask & (MAY_READ | MAY_WRITE | MAY_EXEC), FILE_CHECK); -- cgit v1.2.1 From 854fdd55bfdd56cfc61bd30f2062a9268fcebba6 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Tue, 2 Nov 2010 10:14:22 -0400 Subject: IMA: remove IMA imbalance checking Now that i_readcount is maintained by the VFS layer, remove the imbalance checking in IMA. Cleans up the IMA code nicely. Signed-off-by: Mimi Zohar Acked-by: Eric Paris --- security/integrity/ima/ima_iint.c | 4 -- security/integrity/ima/ima_main.c | 104 ++------------------------------------ 2 files changed, 4 insertions(+), 104 deletions(-) (limited to 'security/integrity/ima') diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c index 68efe3b8d993..4ae73040ab7b 100644 --- a/security/integrity/ima/ima_iint.c +++ b/security/integrity/ima/ima_iint.c @@ -137,10 +137,6 @@ void ima_inode_free(struct inode *inode) { struct ima_iint_cache *iint; - if (atomic_read(&inode->i_readcount)) - printk(KERN_INFO "%s: readcount: %u\n", __func__, - atomic_read(&inode->i_readcount)); - if (!IS_IMA(inode)) return; diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 69b4856af4da..2df902151193 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -36,55 +36,6 @@ static int __init hash_setup(char *str) } __setup("ima_hash=", hash_setup); -struct ima_imbalance { - struct hlist_node node; - unsigned long fsmagic; -}; - -/* - * ima_limit_imbalance - emit one imbalance message per filesystem type - * - * Maintain list of filesystem types that do not measure files properly. - * Return false if unknown, true if known. - */ -static bool ima_limit_imbalance(struct file *file) -{ - static DEFINE_SPINLOCK(ima_imbalance_lock); - static HLIST_HEAD(ima_imbalance_list); - - struct super_block *sb = file->f_dentry->d_sb; - struct ima_imbalance *entry; - struct hlist_node *node; - bool found = false; - - rcu_read_lock(); - hlist_for_each_entry_rcu(entry, node, &ima_imbalance_list, node) { - if (entry->fsmagic == sb->s_magic) { - found = true; - break; - } - } - rcu_read_unlock(); - if (found) - goto out; - - entry = kmalloc(sizeof(*entry), GFP_NOFS); - if (!entry) - goto out; - entry->fsmagic = sb->s_magic; - spin_lock(&ima_imbalance_lock); - /* - * we could have raced and something else might have added this fs - * to the list, but we don't really care - */ - hlist_add_head_rcu(&entry->node, &ima_imbalance_list); - spin_unlock(&ima_imbalance_lock); - printk(KERN_INFO "IMA: unmeasured files on fsmagic: %lX\n", - entry->fsmagic); -out: - return found; -} - /* * ima_rdwr_violation_check * @@ -131,65 +82,20 @@ out: "open_writers"); } -/* - * Decrement ima counts - */ -static void ima_dec_counts(struct inode *inode, struct file *file) -{ - mode_t mode = file->f_mode; - - assert_spin_locked(&inode->i_lock); - - if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { - if (unlikely(atomic_read(&inode->i_readcount) == 0)) { - if (!ima_limit_imbalance(file)) { - printk(KERN_INFO "%s: open/free imbalance (r:%u)\n", - __func__, - atomic_read(&inode->i_readcount)); - dump_stack(); - } - return; - } - } -} - static void ima_check_last_writer(struct ima_iint_cache *iint, struct inode *inode, struct file *file) { mode_t mode = file->f_mode; - BUG_ON(!mutex_is_locked(&iint->mutex)); - assert_spin_locked(&inode->i_lock); - + mutex_lock(&iint->mutex); if (mode & FMODE_WRITE && atomic_read(&inode->i_writecount) == 1 && iint->version != inode->i_version) iint->flags &= ~IMA_MEASURED; -} - -static void ima_file_free_iint(struct ima_iint_cache *iint, struct inode *inode, - struct file *file) -{ - mutex_lock(&iint->mutex); - spin_lock(&inode->i_lock); - - ima_dec_counts(inode, file); - ima_check_last_writer(iint, inode, file); - - spin_unlock(&inode->i_lock); mutex_unlock(&iint->mutex); } -static void ima_file_free_noiint(struct inode *inode, struct file *file) -{ - spin_lock(&inode->i_lock); - - ima_dec_counts(inode, file); - - spin_unlock(&inode->i_lock); -} - /** * ima_file_free - called on __fput() * @file: pointer to file structure being freed @@ -205,12 +111,10 @@ void ima_file_free(struct file *file) return; iint = ima_iint_find(inode); + if (!iint) + return; - if (iint) - ima_file_free_iint(iint, inode, file); - else - ima_file_free_noiint(inode, file); - + ima_check_last_writer(iint, inode, file); } static int process_measurement(struct file *file, const unsigned char *filename, -- cgit v1.2.1 From 1adace9bb04a5f4a4dea9e642089102661bb0ceb Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Tue, 22 Feb 2011 10:19:43 -0500 Subject: ima: remove unnecessary call to ima_must_measure The original ima_must_measure() function based its results on cached iint information, which required an iint be allocated for all files. Currently, an iint is allocated only for files in policy. As a result, for those files in policy, ima_must_measure() is now called twice: once to determine if the inode is in the measurement policy and, the second time, to determine if it needs to be measured/re-measured. The second call to ima_must_measure() unnecessarily checks to see if the file is in policy. As we already know the file is in policy, this patch removes the second unnecessary call to ima_must_measure(), removes the vestige iint parameter, and just checks the iint directly to determine if the inode has been measured or needs to be measured/re-measured. Signed-off-by: Mimi Zohar Acked-by: Eric Paris --- security/integrity/ima/ima.h | 3 +-- security/integrity/ima/ima_api.c | 13 +++---------- security/integrity/ima/ima_main.c | 6 +++--- 3 files changed, 7 insertions(+), 15 deletions(-) (limited to 'security/integrity/ima') diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index ac79032bdf23..08408bd71462 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -110,8 +110,7 @@ struct ima_iint_cache { }; /* LIM API function definitions */ -int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode, - int mask, int function); +int ima_must_measure(struct inode *inode, int mask, int function); int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file); void ima_store_measurement(struct ima_iint_cache *iint, struct file *file, const unsigned char *filename); diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index d3963de6003d..da36d2c085a4 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -105,20 +105,13 @@ err_out: * mask: contains the permission mask * fsmagic: hex value * - * Must be called with iint->mutex held. - * - * Return 0 to measure. Return 1 if already measured. - * For matching a DONT_MEASURE policy, no policy, or other - * error, return an error code. + * Return 0 to measure. For matching a DONT_MEASURE policy, no policy, + * or other error, return an error code. */ -int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode, - int mask, int function) +int ima_must_measure(struct inode *inode, int mask, int function) { int must_measure; - if (iint && iint->flags & IMA_MEASURED) - return 1; - must_measure = ima_match_policy(inode, function, mask); return must_measure ? 0 : -EACCES; } diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 2df902151193..39d66dc2b8e9 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -65,7 +65,7 @@ static void ima_rdwr_violation_check(struct file *file) goto out; } - rc = ima_must_measure(NULL, inode, MAY_READ, FILE_CHECK); + rc = ima_must_measure(inode, MAY_READ, FILE_CHECK); if (rc < 0) goto out; @@ -127,7 +127,7 @@ static int process_measurement(struct file *file, const unsigned char *filename, if (!ima_initialized || !S_ISREG(inode->i_mode)) return 0; - rc = ima_must_measure(NULL, inode, mask, function); + rc = ima_must_measure(inode, mask, function); if (rc != 0) return rc; retry: @@ -141,7 +141,7 @@ retry: mutex_lock(&iint->mutex); - rc = ima_must_measure(iint, inode, mask, function); + rc = iint->flags & IMA_MEASURED ? 1 : 0; if (rc != 0) goto out; -- cgit v1.2.1