diff options
| author | Eric Paris <eparis@redhat.com> | 2010-10-25 14:41:45 -0400 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-26 14:37:18 -0400 | 
| commit | ad16ad00c34d3f320a5876b3d711ef6bc81362e1 (patch) | |
| tree | 7cf3b755567fde2850d2ea7f4a186a0dcea6b80f | |
| parent | 15aac676778f206b42c4d7782b08f89246680485 (diff) | |
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>
| -rw-r--r-- | security/integrity/ima/ima.h | 1 | ||||
| -rw-r--r-- | security/integrity/ima/ima_main.c | 57 | 
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 { | |||
| 106 | unsigned char flags; | 106 | unsigned char flags; | 
| 107 | u8 digest[IMA_DIGEST_SIZE]; | 107 | u8 digest[IMA_DIGEST_SIZE]; | 
| 108 | struct mutex mutex; /* protects: version, flags, digest */ | 108 | struct mutex mutex; /* protects: version, flags, digest */ | 
| 109 | /* protected by inode->i_lock */ | ||
| 109 | unsigned int readcount; /* measured files readcount */ | 110 | unsigned int readcount; /* measured files readcount */ | 
| 110 | unsigned int writecount;/* measured files writecount */ | 111 | unsigned int writecount;/* measured files writecount */ | 
| 111 | struct kref refcount; /* ima_iint_cache reference count */ | 112 | 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: | |||
| 85 | return found; | 85 | return found; | 
| 86 | } | 86 | } | 
| 87 | 87 | ||
| 88 | /* ima_read_write_check - reflect possible reading/writing errors in the PCR. | ||
| 89 | * | ||
| 90 | * When opening a file for read, if the file is already open for write, | ||
| 91 | * the file could change, resulting in a file measurement error. | ||
| 92 | * | ||
| 93 | * Opening a file for write, if the file is already open for read, results | ||
| 94 | * in a time of measure, time of use (ToMToU) error. | ||
| 95 | * | ||
| 96 | * In either case invalidate the PCR. | ||
| 97 | */ | ||
| 98 | enum iint_pcr_error { TOMTOU, OPEN_WRITERS }; | ||
| 99 | static void ima_read_write_check(enum iint_pcr_error error, | ||
| 100 | struct ima_iint_cache *iint, | ||
| 101 | struct inode *inode, | ||
| 102 | const unsigned char *filename) | ||
| 103 | { | ||
| 104 | switch (error) { | ||
| 105 | case TOMTOU: | ||
| 106 | if (iint->readcount > 0) | ||
| 107 | ima_add_violation(inode, filename, "invalid_pcr", | ||
| 108 | "ToMToU"); | ||
| 109 | break; | ||
| 110 | case OPEN_WRITERS: | ||
| 111 | if (iint->writecount > 0) | ||
| 112 | ima_add_violation(inode, filename, "invalid_pcr", | ||
| 113 | "open_writers"); | ||
| 114 | break; | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | /* | 88 | /* | 
| 119 | * Update the counts given an fmode_t | 89 | * Update the counts given an fmode_t | 
| 120 | */ | 90 | */ | 
| 121 | static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode) | 91 | static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode) | 
| 122 | { | 92 | { | 
| 123 | BUG_ON(!mutex_is_locked(&iint->mutex)); | 93 | assert_spin_locked(&iint->inode->i_lock); | 
| 124 | 94 | ||
| 125 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) | 95 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) | 
| 126 | iint->readcount++; | 96 | iint->readcount++; | 
| @@ -146,6 +116,7 @@ void ima_counts_get(struct file *file) | |||
| 146 | fmode_t mode = file->f_mode; | 116 | fmode_t mode = file->f_mode; | 
| 147 | struct ima_iint_cache *iint; | 117 | struct ima_iint_cache *iint; | 
| 148 | int rc; | 118 | int rc; | 
| 119 | bool send_tomtou = false, send_writers = false; | ||
| 149 | 120 | ||
| 150 | if (!iint_initialized || !S_ISREG(inode->i_mode)) | 121 | if (!iint_initialized || !S_ISREG(inode->i_mode)) | 
| 151 | return; | 122 | return; | 
| @@ -153,22 +124,35 @@ void ima_counts_get(struct file *file) | |||
| 153 | if (!iint) | 124 | if (!iint) | 
| 154 | return; | 125 | return; | 
| 155 | mutex_lock(&iint->mutex); | 126 | mutex_lock(&iint->mutex); | 
| 127 | spin_lock(&inode->i_lock); | ||
| 128 | |||
| 156 | if (!ima_initialized) | 129 | if (!ima_initialized) | 
| 157 | goto out; | 130 | goto out; | 
| 131 | |||
| 158 | rc = ima_must_measure(iint, inode, MAY_READ, FILE_CHECK); | 132 | rc = ima_must_measure(iint, inode, MAY_READ, FILE_CHECK); | 
| 159 | if (rc < 0) | 133 | if (rc < 0) | 
| 160 | goto out; | 134 | goto out; | 
| 161 | 135 | ||
| 162 | if (mode & FMODE_WRITE) { | 136 | if (mode & FMODE_WRITE) { | 
| 163 | ima_read_write_check(TOMTOU, iint, inode, dentry->d_name.name); | 137 | if (iint->readcount) | 
| 138 | send_tomtou = true; | ||
| 164 | goto out; | 139 | goto out; | 
| 165 | } | 140 | } | 
| 166 | ima_read_write_check(OPEN_WRITERS, iint, inode, dentry->d_name.name); | 141 | |
| 142 | if (atomic_read(&inode->i_writecount) > 0) | ||
| 143 | send_writers = true; | ||
| 167 | out: | 144 | out: | 
| 168 | ima_inc_counts(iint, file->f_mode); | 145 | ima_inc_counts(iint, file->f_mode); | 
| 146 | spin_unlock(&inode->i_lock); | ||
| 169 | mutex_unlock(&iint->mutex); | 147 | mutex_unlock(&iint->mutex); | 
| 170 | |||
| 171 | kref_put(&iint->refcount, iint_free); | 148 | kref_put(&iint->refcount, iint_free); | 
| 149 | |||
| 150 | if (send_tomtou) | ||
| 151 | ima_add_violation(inode, dentry->d_name.name, "invalid_pcr", | ||
| 152 | "ToMToU"); | ||
| 153 | if (send_writers) | ||
| 154 | ima_add_violation(inode, dentry->d_name.name, "invalid_pcr", | ||
| 155 | "open_writers"); | ||
| 172 | } | 156 | } | 
| 173 | 157 | ||
| 174 | /* | 158 | /* | 
| @@ -181,6 +165,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, | |||
| 181 | bool dump = false; | 165 | bool dump = false; | 
| 182 | 166 | ||
| 183 | BUG_ON(!mutex_is_locked(&iint->mutex)); | 167 | BUG_ON(!mutex_is_locked(&iint->mutex)); | 
| 168 | assert_spin_locked(&inode->i_lock); | ||
| 184 | 169 | ||
| 185 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { | 170 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { | 
| 186 | if (unlikely(iint->readcount == 0)) | 171 | if (unlikely(iint->readcount == 0)) | 
| @@ -223,7 +208,11 @@ void ima_file_free(struct file *file) | |||
| 223 | return; | 208 | return; | 
| 224 | 209 | ||
| 225 | mutex_lock(&iint->mutex); | 210 | mutex_lock(&iint->mutex); | 
| 211 | spin_lock(&inode->i_lock); | ||
| 212 | |||
| 226 | ima_dec_counts(iint, inode, file); | 213 | ima_dec_counts(iint, inode, file); | 
| 214 | |||
| 215 | spin_unlock(&inode->i_lock); | ||
| 227 | mutex_unlock(&iint->mutex); | 216 | mutex_unlock(&iint->mutex); | 
| 228 | kref_put(&iint->refcount, iint_free); | 217 | kref_put(&iint->refcount, iint_free); | 
| 229 | } | 218 | } | 
