aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--security/integrity/ima/ima_main.c94
-rw-r--r--security/security.c10
2 files changed, 65 insertions, 39 deletions
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 2a77b14fee27..5e3229c797fc 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -141,33 +141,62 @@ out:
141/* 141/*
142 * Decrement ima counts 142 * Decrement ima counts
143 */ 143 */
144static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, 144static void ima_dec_counts(struct inode *inode, struct file *file)
145 struct file *file)
146{ 145{
147 mode_t mode = file->f_mode; 146 mode_t mode = file->f_mode;
148 bool dump = false;
149 147
150 BUG_ON(!mutex_is_locked(&iint->mutex));
151 assert_spin_locked(&inode->i_lock); 148 assert_spin_locked(&inode->i_lock);
152 149
153 if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { 150 if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
154 if (unlikely(inode->i_readcount == 0)) 151 if (unlikely(inode->i_readcount == 0)) {
155 dump = true; 152 if (!ima_limit_imbalance(file)) {
153 printk(KERN_INFO "%s: open/free imbalance (r:%u)\n",
154 __func__, inode->i_readcount);
155 dump_stack();
156 }
157 return;
158 }
156 inode->i_readcount--; 159 inode->i_readcount--;
157 } 160 }
158 if (mode & FMODE_WRITE) { 161}
159 if (atomic_read(&inode->i_writecount) <= 0)
160 dump = true;
161 if (atomic_read(&inode->i_writecount) == 1 &&
162 iint->version != inode->i_version)
163 iint->flags &= ~IMA_MEASURED;
164 }
165 162
166 if (dump && !ima_limit_imbalance(file)) { 163static void ima_check_last_writer(struct ima_iint_cache *iint,
167 printk(KERN_INFO "%s: open/free imbalance (r:%u)\n", 164 struct inode *inode,
168 __func__, inode->i_readcount); 165 struct file *file)
169 dump_stack(); 166{
170 } 167 mode_t mode = file->f_mode;
168
169 BUG_ON(!mutex_is_locked(&iint->mutex));
170 assert_spin_locked(&inode->i_lock);
171
172 if (mode & FMODE_WRITE &&
173 atomic_read(&inode->i_writecount) == 1 &&
174 iint->version != inode->i_version)
175 iint->flags &= ~IMA_MEASURED;
176}
177
178static void ima_file_free_iint(struct ima_iint_cache *iint, struct inode *inode,
179 struct file *file)
180{
181 mutex_lock(&iint->mutex);
182 spin_lock(&inode->i_lock);
183
184 ima_dec_counts(inode, file);
185 ima_check_last_writer(iint, inode, file);
186
187 spin_unlock(&inode->i_lock);
188 mutex_unlock(&iint->mutex);
189
190 kref_put(&iint->refcount, iint_free);
191}
192
193static void ima_file_free_noiint(struct inode *inode, struct file *file)
194{
195 spin_lock(&inode->i_lock);
196
197 ima_dec_counts(inode, file);
198
199 spin_unlock(&inode->i_lock);
171} 200}
172 201
173/** 202/**
@@ -175,7 +204,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
175 * @file: pointer to file structure being freed 204 * @file: pointer to file structure being freed
176 * 205 *
177 * Flag files that changed, based on i_version; 206 * Flag files that changed, based on i_version;
178 * and decrement the iint readcount/writecount. 207 * and decrement the i_readcount.
179 */ 208 */
180void ima_file_free(struct file *file) 209void ima_file_free(struct file *file)
181{ 210{
@@ -185,17 +214,12 @@ void ima_file_free(struct file *file)
185 if (!iint_initialized || !S_ISREG(inode->i_mode)) 214 if (!iint_initialized || !S_ISREG(inode->i_mode))
186 return; 215 return;
187 iint = ima_iint_find_get(inode); 216 iint = ima_iint_find_get(inode);
188 if (!iint)
189 return;
190 217
191 mutex_lock(&iint->mutex); 218 if (iint)
192 spin_lock(&inode->i_lock); 219 ima_file_free_iint(iint, inode, file);
193 220 else
194 ima_dec_counts(iint, inode, file); 221 ima_file_free_noiint(inode, file);
195 222
196 spin_unlock(&inode->i_lock);
197 mutex_unlock(&iint->mutex);
198 kref_put(&iint->refcount, iint_free);
199} 223}
200 224
201static int process_measurement(struct file *file, const unsigned char *filename, 225static int process_measurement(struct file *file, const unsigned char *filename,
@@ -207,11 +231,21 @@ static int process_measurement(struct file *file, const unsigned char *filename,
207 231
208 if (!ima_initialized || !S_ISREG(inode->i_mode)) 232 if (!ima_initialized || !S_ISREG(inode->i_mode))
209 return 0; 233 return 0;
234
235 rc = ima_must_measure(NULL, inode, mask, function);
236 if (rc != 0)
237 return rc;
238retry:
210 iint = ima_iint_find_get(inode); 239 iint = ima_iint_find_get(inode);
211 if (!iint) 240 if (!iint) {
212 return -ENOMEM; 241 rc = ima_inode_alloc(inode);
242 if (!rc || rc == -EEXIST)
243 goto retry;
244 return rc;
245 }
213 246
214 mutex_lock(&iint->mutex); 247 mutex_lock(&iint->mutex);
248
215 rc = ima_must_measure(iint, inode, mask, function); 249 rc = ima_must_measure(iint, inode, mask, function);
216 if (rc != 0) 250 if (rc != 0)
217 goto out; 251 goto out;
diff --git a/security/security.c b/security/security.c
index c53949f17d9e..a3b47feccae9 100644
--- a/security/security.c
+++ b/security/security.c
@@ -333,16 +333,8 @@ EXPORT_SYMBOL(security_sb_parse_opts_str);
333 333
334int security_inode_alloc(struct inode *inode) 334int security_inode_alloc(struct inode *inode)
335{ 335{
336 int ret;
337
338 inode->i_security = NULL; 336 inode->i_security = NULL;
339 ret = security_ops->inode_alloc_security(inode); 337 return security_ops->inode_alloc_security(inode);
340 if (ret)
341 return ret;
342 ret = ima_inode_alloc(inode);
343 if (ret)
344 security_inode_free(inode);
345 return ret;
346} 338}
347 339
348void security_inode_free(struct inode *inode) 340void security_inode_free(struct inode *inode)