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) |
