diff options
author | Dmitry Kasatkin <d.kasatkin@samsung.com> | 2014-10-03 07:40:21 -0400 |
---|---|---|
committer | Mimi Zohar <zohar@linux.vnet.ibm.com> | 2014-10-11 23:33:02 -0400 |
commit | 0716abbb58e3c47e04354c2502083854f49c34e5 (patch) | |
tree | a4c5c40884a7bcb9cdf12d6e7184fe19699b1894 /security/integrity | |
parent | 7178784f0a94e2e6c668f587665fde41d405a23c (diff) |
ima: use atomic bit operations to protect policy update interface
The current implementation uses an atomic counter to provide exclusive
access to the sysfs 'policy' entry to update the IMA policy. While it is
highly unlikely, the usage of a counter might potentially allow another
process to overflow the counter, open the interface and insert additional
rules into the policy being loaded.
This patch replaces using an atomic counter with atomic bit operations
which is more reliable and a widely used method to provide exclusive access.
As bit operation keep the interface locked after successful update, it makes
it unnecessary to verify if the default policy was set or not during parsing
and interface closing. This patch also removes that code.
Changes in v3:
* move audit log message to ima_relead_policy() to report successful and
unsuccessful result
* unnecessary comment removed
Changes in v2:
* keep interface locked after successful policy load as in original design
* remove sysfs entry as in original design
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Diffstat (limited to 'security/integrity')
-rw-r--r-- | security/integrity/ima/ima_fs.c | 23 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 23 |
2 files changed, 18 insertions, 28 deletions
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 16d85273d408..973b5683a92e 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c | |||
@@ -288,7 +288,12 @@ static struct dentry *runtime_measurements_count; | |||
288 | static struct dentry *violations; | 288 | static struct dentry *violations; |
289 | static struct dentry *ima_policy; | 289 | static struct dentry *ima_policy; |
290 | 290 | ||
291 | static atomic_t policy_opencount = ATOMIC_INIT(1); | 291 | enum ima_fs_flags { |
292 | IMA_FS_BUSY, | ||
293 | }; | ||
294 | |||
295 | static unsigned long ima_fs_flags; | ||
296 | |||
292 | /* | 297 | /* |
293 | * ima_open_policy: sequentialize access to the policy file | 298 | * ima_open_policy: sequentialize access to the policy file |
294 | */ | 299 | */ |
@@ -297,9 +302,9 @@ static int ima_open_policy(struct inode *inode, struct file *filp) | |||
297 | /* No point in being allowed to open it if you aren't going to write */ | 302 | /* No point in being allowed to open it if you aren't going to write */ |
298 | if (!(filp->f_flags & O_WRONLY)) | 303 | if (!(filp->f_flags & O_WRONLY)) |
299 | return -EACCES; | 304 | return -EACCES; |
300 | if (atomic_dec_and_test(&policy_opencount)) | 305 | if (test_and_set_bit(IMA_FS_BUSY, &ima_fs_flags)) |
301 | return 0; | 306 | return -EBUSY; |
302 | return -EBUSY; | 307 | return 0; |
303 | } | 308 | } |
304 | 309 | ||
305 | /* | 310 | /* |
@@ -311,12 +316,16 @@ static int ima_open_policy(struct inode *inode, struct file *filp) | |||
311 | */ | 316 | */ |
312 | static int ima_release_policy(struct inode *inode, struct file *file) | 317 | static int ima_release_policy(struct inode *inode, struct file *file) |
313 | { | 318 | { |
314 | pr_info("IMA: policy update %s\n", | 319 | const char *cause = valid_policy ? "completed" : "failed"; |
315 | valid_policy ? "completed" : "failed"); | 320 | |
321 | pr_info("IMA: policy update %s\n", cause); | ||
322 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, | ||
323 | "policy_update", cause, !valid_policy, 0); | ||
324 | |||
316 | if (!valid_policy) { | 325 | if (!valid_policy) { |
317 | ima_delete_rules(); | 326 | ima_delete_rules(); |
318 | valid_policy = 1; | 327 | valid_policy = 1; |
319 | atomic_set(&policy_opencount, 1); | 328 | clear_bit(IMA_FS_BUSY, &ima_fs_flags); |
320 | return 0; | 329 | return 0; |
321 | } | 330 | } |
322 | ima_update_policy(); | 331 | ima_update_policy(); |
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index d2c47d4df7b7..0d14d2591805 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
@@ -356,19 +356,8 @@ void __init ima_init_policy(void) | |||
356 | */ | 356 | */ |
357 | void ima_update_policy(void) | 357 | void ima_update_policy(void) |
358 | { | 358 | { |
359 | static const char op[] = "policy_update"; | 359 | ima_rules = &ima_policy_rules; |
360 | const char *cause = "already-exists"; | 360 | ima_update_policy_flag(); |
361 | int result = 1; | ||
362 | int audit_info = 0; | ||
363 | |||
364 | if (ima_rules == &ima_default_rules) { | ||
365 | ima_rules = &ima_policy_rules; | ||
366 | ima_update_policy_flag(); | ||
367 | cause = "complete"; | ||
368 | result = 0; | ||
369 | } | ||
370 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | ||
371 | NULL, op, cause, result, audit_info); | ||
372 | } | 361 | } |
373 | 362 | ||
374 | enum { | 363 | enum { |
@@ -686,14 +675,6 @@ ssize_t ima_parse_add_rule(char *rule) | |||
686 | ssize_t result, len; | 675 | ssize_t result, len; |
687 | int audit_info = 0; | 676 | int audit_info = 0; |
688 | 677 | ||
689 | /* Prevent installed policy from changing */ | ||
690 | if (ima_rules != &ima_default_rules) { | ||
691 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | ||
692 | NULL, op, "already-exists", | ||
693 | -EACCES, audit_info); | ||
694 | return -EACCES; | ||
695 | } | ||
696 | |||
697 | p = strsep(&rule, "\n"); | 678 | p = strsep(&rule, "\n"); |
698 | len = strlen(p) + 1; | 679 | len = strlen(p) + 1; |
699 | p += strspn(p, " \t"); | 680 | p += strspn(p, " \t"); |