diff options
-rw-r--r-- | security/integrity/ima/ima_main.c | 94 | ||||
-rw-r--r-- | security/security.c | 10 |
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 | */ |
144 | static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, | 144 | static 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)) { | 163 | static 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 | |||
178 | static 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 | |||
193 | static 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 | */ |
180 | void ima_file_free(struct file *file) | 209 | void 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 | ||
201 | static int process_measurement(struct file *file, const unsigned char *filename, | 225 | static 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; | ||
238 | retry: | ||
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 | ||
334 | int security_inode_alloc(struct inode *inode) | 334 | int 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 | ||
348 | void security_inode_free(struct inode *inode) | 340 | void security_inode_free(struct inode *inode) |