summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2010-10-25 14:41:45 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-10-26 11:37:18 -0700
commitad16ad00c34d3f320a5876b3d711ef6bc81362e1 (patch)
tree7cf3b755567fde2850d2ea7f4a186a0dcea6b80f /security
parent15aac676778f206b42c4d7782b08f89246680485 (diff)
downloadlwn-ad16ad00c34d3f320a5876b3d711ef6bc81362e1.tar.gz
lwn-ad16ad00c34d3f320a5876b3d711ef6bc81362e1.zip
IMA: use inode->i_lock to protect read and write counters
Currently IMA used the iint->mutex to protect the i_readcount and i_writecount. This patch uses the inode->i_lock since we are going to start using in inode objects and that is the most appropriate lock. Signed-off-by: Eric Paris <eparis@redhat.com> Acked-by: Mimi Zohar <zohar@linux.vnet.ibm.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'security')
-rw-r--r--security/integrity/ima/ima.h1
-rw-r--r--security/integrity/ima/ima_main.c57
2 files changed, 24 insertions, 34 deletions
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index f7af0110bcde..80aca3d2cb71 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -106,6 +106,7 @@ 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 */
unsigned int writecount;/* measured files writecount */
struct kref refcount; /* ima_iint_cache reference count */
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 5a1bf3df11f8..2f9b5d50424e 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -85,42 +85,12 @@ out:
return found;
}
-/* ima_read_write_check - reflect possible reading/writing errors in the PCR.
- *
- * When opening a file for read, if the file is already open for write,
- * the file could change, resulting in a file measurement error.
- *
- * Opening a file for write, if the file is already open for read, results
- * in a time of measure, time of use (ToMToU) error.
- *
- * In either case invalidate the PCR.
- */
-enum iint_pcr_error { TOMTOU, OPEN_WRITERS };
-static void ima_read_write_check(enum iint_pcr_error error,
- struct ima_iint_cache *iint,
- struct inode *inode,
- const unsigned char *filename)
-{
- switch (error) {
- case TOMTOU:
- if (iint->readcount > 0)
- ima_add_violation(inode, filename, "invalid_pcr",
- "ToMToU");
- break;
- case OPEN_WRITERS:
- if (iint->writecount > 0)
- ima_add_violation(inode, filename, "invalid_pcr",
- "open_writers");
- break;
- }
-}
-
/*
* Update the counts given an fmode_t
*/
static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode)
{
- BUG_ON(!mutex_is_locked(&iint->mutex));
+ assert_spin_locked(&iint->inode->i_lock);
if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
iint->readcount++;
@@ -146,6 +116,7 @@ void ima_counts_get(struct file *file)
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))
return;
@@ -153,22 +124,35 @@ void ima_counts_get(struct file *file)
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);
if (rc < 0)
goto out;
if (mode & FMODE_WRITE) {
- ima_read_write_check(TOMTOU, iint, inode, dentry->d_name.name);
+ if (iint->readcount)
+ send_tomtou = true;
goto out;
}
- ima_read_write_check(OPEN_WRITERS, iint, inode, dentry->d_name.name);
+
+ if (atomic_read(&inode->i_writecount) > 0)
+ send_writers = true;
out:
ima_inc_counts(iint, file->f_mode);
+ 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",
+ "ToMToU");
+ if (send_writers)
+ ima_add_violation(inode, dentry->d_name.name, "invalid_pcr",
+ "open_writers");
}
/*
@@ -181,6 +165,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
bool dump = false;
BUG_ON(!mutex_is_locked(&iint->mutex));
+ assert_spin_locked(&inode->i_lock);
if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
if (unlikely(iint->readcount == 0))
@@ -223,7 +208,11 @@ void ima_file_free(struct file *file)
return;
mutex_lock(&iint->mutex);
+ spin_lock(&inode->i_lock);
+
ima_dec_counts(iint, inode, file);
+
+ spin_unlock(&inode->i_lock);
mutex_unlock(&iint->mutex);
kref_put(&iint->refcount, iint_free);
}