]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - security/integrity/ima/ima_main.c
IMA: use i_writecount rather than a private counter
[net-next-2.6.git] / security / integrity / ima / ima_main.c
index e662b89d407944103dc121b9ccb37f7e68ac62e1..24660bf3f82ab27a22de12a551961e84772738bc 100644 (file)
@@ -85,48 +85,15 @@ 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);
 
-       iint->opencount++;
        if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
                iint->readcount++;
-       if (mode & FMODE_WRITE)
-               iint->writecount++;
 }
 
 /*
@@ -147,6 +114,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;
@@ -154,22 +122,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");
 }
 
 /*
@@ -179,26 +160,27 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
                           struct file *file)
 {
        mode_t mode = file->f_mode;
+       bool dump = false;
+
        BUG_ON(!mutex_is_locked(&iint->mutex));
+       assert_spin_locked(&inode->i_lock);
 
-       iint->opencount--;
-       if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
+       if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
+               if (unlikely(iint->readcount == 0))
+                       dump = true;
                iint->readcount--;
+       }
        if (mode & FMODE_WRITE) {
-               iint->writecount--;
-               if (iint->writecount == 0) {
-                       if (iint->version != inode->i_version)
-                               iint->flags &= ~IMA_MEASURED;
-               }
+               if (atomic_read(&inode->i_writecount) <= 0)
+                       dump = true;
+               if (atomic_read(&inode->i_writecount) == 1 &&
+                   iint->version != inode->i_version)
+                       iint->flags &= ~IMA_MEASURED;
        }
 
-       if (((iint->opencount < 0) ||
-            (iint->readcount < 0) ||
-            (iint->writecount < 0)) &&
-           !ima_limit_imbalance(file)) {
-               printk(KERN_INFO "%s: open/free imbalance (r:%ld w:%ld o:%ld)\n",
-                      __func__, iint->readcount, iint->writecount,
-                      iint->opencount);
+       if (dump && !ima_limit_imbalance(file)) {
+               printk(KERN_INFO "%s: open/free imbalance (r:%u)\n",
+                      __func__, iint->readcount);
                dump_stack();
        }
 }
@@ -222,7 +204,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);
 }