aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorPetko Manolov <petkan@mip-labs.com>2015-12-02 10:47:54 -0500
committerMimi Zohar <zohar@linux.vnet.ibm.com>2015-12-15 10:01:43 -0500
commit38d859f991f3a05b352a06f82af0baa1acf33e02 (patch)
tree05100d5f61490abf1a180d2f51b8b0960bba5123 /security
parent05d3884b1ee66d83ad70ffa658c7b363797e2b0c (diff)
IMA: policy can now be updated multiple times
The new rules get appended to the original policy, forming a queue. The new rules are first added to a temporary list, which on error get released without disturbing the normal IMA operations. On success both lists (the current policy and the new rules) are spliced. IMA policy reads are many orders of magnitude more numerous compared to writes, the match code is RCU protected. The updater side also does list splice in RCU manner. Signed-off-by: Petko Manolov <petkan@mip-labs.com> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Diffstat (limited to 'security')
-rw-r--r--security/integrity/ima/Kconfig11
-rw-r--r--security/integrity/ima/ima_fs.c13
-rw-r--r--security/integrity/ima/ima_policy.c79
3 files changed, 75 insertions, 28 deletions
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index a292b881c16f..e74d66cbfe87 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -107,6 +107,17 @@ config IMA_DEFAULT_HASH
107 default "sha512" if IMA_DEFAULT_HASH_SHA512 107 default "sha512" if IMA_DEFAULT_HASH_SHA512
108 default "wp512" if IMA_DEFAULT_HASH_WP512 108 default "wp512" if IMA_DEFAULT_HASH_WP512
109 109
110config IMA_WRITE_POLICY
111 bool "Enable multiple writes to the IMA policy"
112 depends on IMA
113 default n
114 help
115 IMA policy can now be updated multiple times. The new rules get
116 appended to the original policy. Have in mind that the rules are
117 scanned in FIFO order so be careful when you design and add new ones.
118
119 If unsure, say N.
120
110config IMA_APPRAISE 121config IMA_APPRAISE
111 bool "Appraise integrity measurements" 122 bool "Appraise integrity measurements"
112 depends on IMA 123 depends on IMA
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 816d175da79a..a3cf5c0ab501 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -25,6 +25,8 @@
25 25
26#include "ima.h" 26#include "ima.h"
27 27
28static DEFINE_MUTEX(ima_write_mutex);
29
28static int valid_policy = 1; 30static int valid_policy = 1;
29#define TMPBUFLEN 12 31#define TMPBUFLEN 12
30static ssize_t ima_show_htable_value(char __user *buf, size_t count, 32static ssize_t ima_show_htable_value(char __user *buf, size_t count,
@@ -261,6 +263,11 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
261{ 263{
262 char *data = NULL; 264 char *data = NULL;
263 ssize_t result; 265 ssize_t result;
266 int res;
267
268 res = mutex_lock_interruptible(&ima_write_mutex);
269 if (res)
270 return res;
264 271
265 if (datalen >= PAGE_SIZE) 272 if (datalen >= PAGE_SIZE)
266 datalen = PAGE_SIZE - 1; 273 datalen = PAGE_SIZE - 1;
@@ -286,6 +293,8 @@ out:
286 if (result < 0) 293 if (result < 0)
287 valid_policy = 0; 294 valid_policy = 0;
288 kfree(data); 295 kfree(data);
296 mutex_unlock(&ima_write_mutex);
297
289 return result; 298 return result;
290} 299}
291 300
@@ -337,8 +346,12 @@ static int ima_release_policy(struct inode *inode, struct file *file)
337 return 0; 346 return 0;
338 } 347 }
339 ima_update_policy(); 348 ima_update_policy();
349#ifndef CONFIG_IMA_WRITE_POLICY
340 securityfs_remove(ima_policy); 350 securityfs_remove(ima_policy);
341 ima_policy = NULL; 351 ima_policy = NULL;
352#else
353 clear_bit(IMA_FS_BUSY, &ima_fs_flags);
354#endif
342 return 0; 355 return 0;
343} 356}
344 357
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 3997e206f82d..10a0a9b9e22d 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -16,6 +16,7 @@
16#include <linux/magic.h> 16#include <linux/magic.h>
17#include <linux/parser.h> 17#include <linux/parser.h>
18#include <linux/slab.h> 18#include <linux/slab.h>
19#include <linux/rculist.h>
19#include <linux/genhd.h> 20#include <linux/genhd.h>
20 21
21#include "ima.h" 22#include "ima.h"
@@ -135,11 +136,11 @@ static struct ima_rule_entry default_appraise_rules[] = {
135 136
136static LIST_HEAD(ima_default_rules); 137static LIST_HEAD(ima_default_rules);
137static LIST_HEAD(ima_policy_rules); 138static LIST_HEAD(ima_policy_rules);
139static LIST_HEAD(ima_temp_rules);
138static struct list_head *ima_rules; 140static struct list_head *ima_rules;
139 141
140static DEFINE_MUTEX(ima_rules_mutex);
141
142static int ima_policy __initdata; 142static int ima_policy __initdata;
143
143static int __init default_measure_policy_setup(char *str) 144static int __init default_measure_policy_setup(char *str)
144{ 145{
145 if (ima_policy) 146 if (ima_policy)
@@ -171,21 +172,18 @@ static int __init default_appraise_policy_setup(char *str)
171__setup("ima_appraise_tcb", default_appraise_policy_setup); 172__setup("ima_appraise_tcb", default_appraise_policy_setup);
172 173
173/* 174/*
174 * Although the IMA policy does not change, the LSM policy can be 175 * The LSM policy can be reloaded, leaving the IMA LSM based rules referring
175 * reloaded, leaving the IMA LSM based rules referring to the old, 176 * to the old, stale LSM policy. Update the IMA LSM based rules to reflect
176 * stale LSM policy. 177 * the reloaded LSM policy. We assume the rules still exist; and BUG_ON() if
177 * 178 * they don't.
178 * Update the IMA LSM based rules to reflect the reloaded LSM policy.
179 * We assume the rules still exist; and BUG_ON() if they don't.
180 */ 179 */
181static void ima_lsm_update_rules(void) 180static void ima_lsm_update_rules(void)
182{ 181{
183 struct ima_rule_entry *entry, *tmp; 182 struct ima_rule_entry *entry;
184 int result; 183 int result;
185 int i; 184 int i;
186 185
187 mutex_lock(&ima_rules_mutex); 186 list_for_each_entry(entry, &ima_policy_rules, list) {
188 list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) {
189 for (i = 0; i < MAX_LSM_RULES; i++) { 187 for (i = 0; i < MAX_LSM_RULES; i++) {
190 if (!entry->lsm[i].rule) 188 if (!entry->lsm[i].rule)
191 continue; 189 continue;
@@ -196,7 +194,6 @@ static void ima_lsm_update_rules(void)
196 BUG_ON(!entry->lsm[i].rule); 194 BUG_ON(!entry->lsm[i].rule);
197 } 195 }
198 } 196 }
199 mutex_unlock(&ima_rules_mutex);
200} 197}
201 198
202/** 199/**
@@ -319,9 +316,9 @@ static int get_subaction(struct ima_rule_entry *rule, int func)
319 * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type) 316 * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
320 * conditions. 317 * conditions.
321 * 318 *
322 * (There is no need for locking when walking the policy list, 319 * Since the IMA policy may be updated multiple times we need to lock the
323 * as elements in the list are never deleted, nor does the list 320 * list when walking it. Reads are many orders of magnitude more numerous
324 * change.) 321 * than writes so ima_match_policy() is classical RCU candidate.
325 */ 322 */
326int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, 323int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
327 int flags) 324 int flags)
@@ -329,7 +326,8 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
329 struct ima_rule_entry *entry; 326 struct ima_rule_entry *entry;
330 int action = 0, actmask = flags | (flags << 1); 327 int action = 0, actmask = flags | (flags << 1);
331 328
332 list_for_each_entry(entry, ima_rules, list) { 329 rcu_read_lock();
330 list_for_each_entry_rcu(entry, ima_rules, list) {
333 331
334 if (!(entry->action & actmask)) 332 if (!(entry->action & actmask))
335 continue; 333 continue;
@@ -351,6 +349,7 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
351 if (!actmask) 349 if (!actmask)
352 break; 350 break;
353 } 351 }
352 rcu_read_unlock();
354 353
355 return action; 354 return action;
356} 355}
@@ -365,7 +364,6 @@ void ima_update_policy_flag(void)
365{ 364{
366 struct ima_rule_entry *entry; 365 struct ima_rule_entry *entry;
367 366
368 ima_policy_flag = 0;
369 list_for_each_entry(entry, ima_rules, list) { 367 list_for_each_entry(entry, ima_rules, list) {
370 if (entry->action & IMA_DO_MASK) 368 if (entry->action & IMA_DO_MASK)
371 ima_policy_flag |= entry->action; 369 ima_policy_flag |= entry->action;
@@ -419,12 +417,36 @@ void __init ima_init_policy(void)
419 * ima_update_policy - update default_rules with new measure rules 417 * ima_update_policy - update default_rules with new measure rules
420 * 418 *
421 * Called on file .release to update the default rules with a complete new 419 * Called on file .release to update the default rules with a complete new
422 * policy. Once updated, the policy is locked, no additional rules can be 420 * policy. What we do here is to splice ima_policy_rules and ima_temp_rules so
423 * added to the policy. 421 * they make a queue. The policy may be updated multiple times and this is the
422 * RCU updater.
423 *
424 * Policy rules are never deleted so ima_policy_flag gets zeroed only once when
425 * we switch from the default policy to user defined.
424 */ 426 */
425void ima_update_policy(void) 427void ima_update_policy(void)
426{ 428{
427 ima_rules = &ima_policy_rules; 429 struct list_head *first, *last, *policy;
430
431 /* append current policy with the new rules */
432 first = (&ima_temp_rules)->next;
433 last = (&ima_temp_rules)->prev;
434 policy = &ima_policy_rules;
435
436 synchronize_rcu();
437
438 last->next = policy;
439 rcu_assign_pointer(list_next_rcu(policy->prev), first);
440 first->prev = policy->prev;
441 policy->prev = last;
442
443 /* prepare for the next policy rules addition */
444 INIT_LIST_HEAD(&ima_temp_rules);
445
446 if (ima_rules != policy) {
447 ima_policy_flag = 0;
448 ima_rules = policy;
449 }
428 ima_update_policy_flag(); 450 ima_update_policy_flag();
429} 451}
430 452
@@ -746,7 +768,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
746 * ima_parse_add_rule - add a rule to ima_policy_rules 768 * ima_parse_add_rule - add a rule to ima_policy_rules
747 * @rule - ima measurement policy rule 769 * @rule - ima measurement policy rule
748 * 770 *
749 * Uses a mutex to protect the policy list from multiple concurrent writers. 771 * Avoid locking by allowing just one writer at a time in ima_write_policy()
750 * Returns the length of the rule parsed, an error code on failure 772 * Returns the length of the rule parsed, an error code on failure
751 */ 773 */
752ssize_t ima_parse_add_rule(char *rule) 774ssize_t ima_parse_add_rule(char *rule)
@@ -782,26 +804,27 @@ ssize_t ima_parse_add_rule(char *rule)
782 return result; 804 return result;
783 } 805 }
784 806
785 mutex_lock(&ima_rules_mutex); 807 list_add_tail(&entry->list, &ima_temp_rules);
786 list_add_tail(&entry->list, &ima_policy_rules);
787 mutex_unlock(&ima_rules_mutex);
788 808
789 return len; 809 return len;
790} 810}
791 811
792/* ima_delete_rules called to cleanup invalid policy */ 812/**
813 * ima_delete_rules() called to cleanup invalid in-flight policy.
814 * We don't need locking as we operate on the temp list, which is
815 * different from the active one. There is also only one user of
816 * ima_delete_rules() at a time.
817 */
793void ima_delete_rules(void) 818void ima_delete_rules(void)
794{ 819{
795 struct ima_rule_entry *entry, *tmp; 820 struct ima_rule_entry *entry, *tmp;
796 int i; 821 int i;
797 822
798 mutex_lock(&ima_rules_mutex); 823 list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) {
799 list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) {
800 for (i = 0; i < MAX_LSM_RULES; i++) 824 for (i = 0; i < MAX_LSM_RULES; i++)
801 kfree(entry->lsm[i].args_p); 825 kfree(entry->lsm[i].args_p);
802 826
803 list_del(&entry->list); 827 list_del(&entry->list);
804 kfree(entry); 828 kfree(entry);
805 } 829 }
806 mutex_unlock(&ima_rules_mutex);
807} 830}