diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2008-12-15 01:17:50 -0500 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2009-01-04 15:14:42 -0500 |
| commit | e45aa212ea81d39b38ba158df344dc3a500153e5 (patch) | |
| tree | c4d55cda9e8f976d15b6b01a775a3437f932db27 | |
| parent | 0590b9335a1c72a3f0defcc6231287f7817e07c8 (diff) | |
audit rules ordering, part 2
Fix the actual rule listing; add per-type lists _not_ used for matching,
with all exit,... sitting on one such list. Simplifies "do something
for all rules" logics, while we are at it...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| -rw-r--r-- | include/linux/audit.h | 1 | ||||
| -rw-r--r-- | kernel/audit_tree.c | 1 | ||||
| -rw-r--r-- | kernel/auditfilter.c | 95 |
3 files changed, 41 insertions, 56 deletions
diff --git a/include/linux/audit.h b/include/linux/audit.h index 5b47eeb00d53..cc71fdb56ae2 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h | |||
| @@ -373,6 +373,7 @@ struct audit_krule { | |||
| 373 | struct audit_watch *watch; /* associated watch */ | 373 | struct audit_watch *watch; /* associated watch */ |
| 374 | struct audit_tree *tree; /* associated watched tree */ | 374 | struct audit_tree *tree; /* associated watched tree */ |
| 375 | struct list_head rlist; /* entry in audit_{watch,tree}.rules list */ | 375 | struct list_head rlist; /* entry in audit_{watch,tree}.rules list */ |
| 376 | struct list_head list; /* for AUDIT_LIST* purposes only */ | ||
| 376 | u64 prio; | 377 | u64 prio; |
| 377 | }; | 378 | }; |
| 378 | 379 | ||
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index 8b509441f49a..48bddad2a3dc 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c | |||
| @@ -450,6 +450,7 @@ static void kill_rules(struct audit_tree *tree) | |||
| 450 | audit_log_end(ab); | 450 | audit_log_end(ab); |
| 451 | rule->tree = NULL; | 451 | rule->tree = NULL; |
| 452 | list_del_rcu(&entry->list); | 452 | list_del_rcu(&entry->list); |
| 453 | list_del(&entry->rule.list); | ||
| 453 | call_rcu(&entry->rcu, audit_free_rule_rcu); | 454 | call_rcu(&entry->rcu, audit_free_rule_rcu); |
| 454 | } | 455 | } |
| 455 | } | 456 | } |
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 995a2e86808d..5d4edc6f7a32 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c | |||
| @@ -86,6 +86,14 @@ struct list_head audit_filter_list[AUDIT_NR_FILTERS] = { | |||
| 86 | #error Fix audit_filter_list initialiser | 86 | #error Fix audit_filter_list initialiser |
| 87 | #endif | 87 | #endif |
| 88 | }; | 88 | }; |
| 89 | static struct list_head audit_rules_list[AUDIT_NR_FILTERS] = { | ||
| 90 | LIST_HEAD_INIT(audit_rules_list[0]), | ||
| 91 | LIST_HEAD_INIT(audit_rules_list[1]), | ||
| 92 | LIST_HEAD_INIT(audit_rules_list[2]), | ||
| 93 | LIST_HEAD_INIT(audit_rules_list[3]), | ||
| 94 | LIST_HEAD_INIT(audit_rules_list[4]), | ||
| 95 | LIST_HEAD_INIT(audit_rules_list[5]), | ||
| 96 | }; | ||
| 89 | 97 | ||
| 90 | DEFINE_MUTEX(audit_filter_mutex); | 98 | DEFINE_MUTEX(audit_filter_mutex); |
| 91 | 99 | ||
| @@ -1007,12 +1015,15 @@ static void audit_update_watch(struct audit_parent *parent, | |||
| 1007 | list_del_rcu(&oentry->list); | 1015 | list_del_rcu(&oentry->list); |
| 1008 | 1016 | ||
| 1009 | nentry = audit_dupe_rule(&oentry->rule, nwatch); | 1017 | nentry = audit_dupe_rule(&oentry->rule, nwatch); |
| 1010 | if (IS_ERR(nentry)) | 1018 | if (IS_ERR(nentry)) { |
| 1019 | list_del(&oentry->rule.list); | ||
| 1011 | audit_panic("error updating watch, removing"); | 1020 | audit_panic("error updating watch, removing"); |
| 1012 | else { | 1021 | } else { |
| 1013 | int h = audit_hash_ino((u32)ino); | 1022 | int h = audit_hash_ino((u32)ino); |
| 1014 | list_add(&nentry->rule.rlist, &nwatch->rules); | 1023 | list_add(&nentry->rule.rlist, &nwatch->rules); |
| 1015 | list_add_rcu(&nentry->list, &audit_inode_hash[h]); | 1024 | list_add_rcu(&nentry->list, &audit_inode_hash[h]); |
| 1025 | list_replace(&oentry->rule.list, | ||
| 1026 | &nentry->rule.list); | ||
| 1016 | } | 1027 | } |
| 1017 | 1028 | ||
| 1018 | call_rcu(&oentry->rcu, audit_free_rule_rcu); | 1029 | call_rcu(&oentry->rcu, audit_free_rule_rcu); |
| @@ -1077,6 +1088,7 @@ static void audit_remove_parent_watches(struct audit_parent *parent) | |||
| 1077 | audit_log_end(ab); | 1088 | audit_log_end(ab); |
| 1078 | } | 1089 | } |
| 1079 | list_del(&r->rlist); | 1090 | list_del(&r->rlist); |
| 1091 | list_del(&r->list); | ||
| 1080 | list_del_rcu(&e->list); | 1092 | list_del_rcu(&e->list); |
| 1081 | call_rcu(&e->rcu, audit_free_rule_rcu); | 1093 | call_rcu(&e->rcu, audit_free_rule_rcu); |
| 1082 | } | 1094 | } |
| @@ -1331,9 +1343,13 @@ static inline int audit_add_rule(struct audit_entry *entry, | |||
| 1331 | } | 1343 | } |
| 1332 | 1344 | ||
| 1333 | if (entry->rule.flags & AUDIT_FILTER_PREPEND) { | 1345 | if (entry->rule.flags & AUDIT_FILTER_PREPEND) { |
| 1346 | list_add(&entry->rule.list, | ||
| 1347 | &audit_rules_list[entry->rule.listnr]); | ||
| 1334 | list_add_rcu(&entry->list, list); | 1348 | list_add_rcu(&entry->list, list); |
| 1335 | entry->rule.flags &= ~AUDIT_FILTER_PREPEND; | 1349 | entry->rule.flags &= ~AUDIT_FILTER_PREPEND; |
| 1336 | } else { | 1350 | } else { |
| 1351 | list_add_tail(&entry->rule.list, | ||
| 1352 | &audit_rules_list[entry->rule.listnr]); | ||
| 1337 | list_add_tail_rcu(&entry->list, list); | 1353 | list_add_tail_rcu(&entry->list, list); |
| 1338 | } | 1354 | } |
| 1339 | #ifdef CONFIG_AUDITSYSCALL | 1355 | #ifdef CONFIG_AUDITSYSCALL |
| @@ -1415,6 +1431,7 @@ static inline int audit_del_rule(struct audit_entry *entry, | |||
| 1415 | audit_remove_tree_rule(&e->rule); | 1431 | audit_remove_tree_rule(&e->rule); |
| 1416 | 1432 | ||
| 1417 | list_del_rcu(&e->list); | 1433 | list_del_rcu(&e->list); |
| 1434 | list_del(&e->rule.list); | ||
| 1418 | call_rcu(&e->rcu, audit_free_rule_rcu); | 1435 | call_rcu(&e->rcu, audit_free_rule_rcu); |
| 1419 | 1436 | ||
| 1420 | #ifdef CONFIG_AUDITSYSCALL | 1437 | #ifdef CONFIG_AUDITSYSCALL |
| @@ -1443,30 +1460,16 @@ out: | |||
| 1443 | static void audit_list(int pid, int seq, struct sk_buff_head *q) | 1460 | static void audit_list(int pid, int seq, struct sk_buff_head *q) |
| 1444 | { | 1461 | { |
| 1445 | struct sk_buff *skb; | 1462 | struct sk_buff *skb; |
| 1446 | struct audit_entry *entry; | 1463 | struct audit_krule *r; |
| 1447 | int i; | 1464 | int i; |
| 1448 | 1465 | ||
| 1449 | /* This is a blocking read, so use audit_filter_mutex instead of rcu | 1466 | /* This is a blocking read, so use audit_filter_mutex instead of rcu |
| 1450 | * iterator to sync with list writers. */ | 1467 | * iterator to sync with list writers. */ |
| 1451 | for (i=0; i<AUDIT_NR_FILTERS; i++) { | 1468 | for (i=0; i<AUDIT_NR_FILTERS; i++) { |
| 1452 | list_for_each_entry(entry, &audit_filter_list[i], list) { | 1469 | list_for_each_entry(r, &audit_rules_list[i], list) { |
| 1453 | struct audit_rule *rule; | ||
| 1454 | |||
| 1455 | rule = audit_krule_to_rule(&entry->rule); | ||
| 1456 | if (unlikely(!rule)) | ||
| 1457 | break; | ||
| 1458 | skb = audit_make_reply(pid, seq, AUDIT_LIST, 0, 1, | ||
| 1459 | rule, sizeof(*rule)); | ||
| 1460 | if (skb) | ||
| 1461 | skb_queue_tail(q, skb); | ||
| 1462 | kfree(rule); | ||
| 1463 | } | ||
| 1464 | } | ||
| 1465 | for (i = 0; i < AUDIT_INODE_BUCKETS; i++) { | ||
| 1466 | list_for_each_entry(entry, &audit_inode_hash[i], list) { | ||
| 1467 | struct audit_rule *rule; | 1470 | struct audit_rule *rule; |
| 1468 | 1471 | ||
| 1469 | rule = audit_krule_to_rule(&entry->rule); | 1472 | rule = audit_krule_to_rule(r); |
| 1470 | if (unlikely(!rule)) | 1473 | if (unlikely(!rule)) |
| 1471 | break; | 1474 | break; |
| 1472 | skb = audit_make_reply(pid, seq, AUDIT_LIST, 0, 1, | 1475 | skb = audit_make_reply(pid, seq, AUDIT_LIST, 0, 1, |
| @@ -1485,30 +1488,16 @@ static void audit_list(int pid, int seq, struct sk_buff_head *q) | |||
| 1485 | static void audit_list_rules(int pid, int seq, struct sk_buff_head *q) | 1488 | static void audit_list_rules(int pid, int seq, struct sk_buff_head *q) |
| 1486 | { | 1489 | { |
| 1487 | struct sk_buff *skb; | 1490 | struct sk_buff *skb; |
| 1488 | struct audit_entry *e; | 1491 | struct audit_krule *r; |
| 1489 | int i; | 1492 | int i; |
| 1490 | 1493 | ||
| 1491 | /* This is a blocking read, so use audit_filter_mutex instead of rcu | 1494 | /* This is a blocking read, so use audit_filter_mutex instead of rcu |
| 1492 | * iterator to sync with list writers. */ | 1495 | * iterator to sync with list writers. */ |
| 1493 | for (i=0; i<AUDIT_NR_FILTERS; i++) { | 1496 | for (i=0; i<AUDIT_NR_FILTERS; i++) { |
| 1494 | list_for_each_entry(e, &audit_filter_list[i], list) { | 1497 | list_for_each_entry(r, &audit_rules_list[i], list) { |
| 1495 | struct audit_rule_data *data; | ||
| 1496 | |||
| 1497 | data = audit_krule_to_data(&e->rule); | ||
| 1498 | if (unlikely(!data)) | ||
| 1499 | break; | ||
| 1500 | skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 0, 1, | ||
| 1501 | data, sizeof(*data) + data->buflen); | ||
| 1502 | if (skb) | ||
| 1503 | skb_queue_tail(q, skb); | ||
| 1504 | kfree(data); | ||
| 1505 | } | ||
| 1506 | } | ||
| 1507 | for (i=0; i< AUDIT_INODE_BUCKETS; i++) { | ||
| 1508 | list_for_each_entry(e, &audit_inode_hash[i], list) { | ||
| 1509 | struct audit_rule_data *data; | 1498 | struct audit_rule_data *data; |
| 1510 | 1499 | ||
| 1511 | data = audit_krule_to_data(&e->rule); | 1500 | data = audit_krule_to_data(r); |
| 1512 | if (unlikely(!data)) | 1501 | if (unlikely(!data)) |
| 1513 | break; | 1502 | break; |
| 1514 | skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 0, 1, | 1503 | skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 0, 1, |
| @@ -1789,35 +1778,37 @@ unlock_and_return: | |||
| 1789 | return result; | 1778 | return result; |
| 1790 | } | 1779 | } |
| 1791 | 1780 | ||
| 1792 | static int update_lsm_rule(struct audit_entry *entry) | 1781 | static int update_lsm_rule(struct audit_krule *r) |
| 1793 | { | 1782 | { |
| 1783 | struct audit_entry *entry = container_of(r, struct audit_entry, rule); | ||
| 1794 | struct audit_entry *nentry; | 1784 | struct audit_entry *nentry; |
| 1795 | struct audit_watch *watch; | 1785 | struct audit_watch *watch; |
| 1796 | struct audit_tree *tree; | 1786 | struct audit_tree *tree; |
| 1797 | int err = 0; | 1787 | int err = 0; |
| 1798 | 1788 | ||
| 1799 | if (!security_audit_rule_known(&entry->rule)) | 1789 | if (!security_audit_rule_known(r)) |
| 1800 | return 0; | 1790 | return 0; |
| 1801 | 1791 | ||
| 1802 | watch = entry->rule.watch; | 1792 | watch = r->watch; |
| 1803 | tree = entry->rule.tree; | 1793 | tree = r->tree; |
| 1804 | nentry = audit_dupe_rule(&entry->rule, watch); | 1794 | nentry = audit_dupe_rule(r, watch); |
| 1805 | if (IS_ERR(nentry)) { | 1795 | if (IS_ERR(nentry)) { |
| 1806 | /* save the first error encountered for the | 1796 | /* save the first error encountered for the |
| 1807 | * return value */ | 1797 | * return value */ |
| 1808 | err = PTR_ERR(nentry); | 1798 | err = PTR_ERR(nentry); |
| 1809 | audit_panic("error updating LSM filters"); | 1799 | audit_panic("error updating LSM filters"); |
| 1810 | if (watch) | 1800 | if (watch) |
| 1811 | list_del(&entry->rule.rlist); | 1801 | list_del(&r->rlist); |
| 1812 | list_del_rcu(&entry->list); | 1802 | list_del_rcu(&entry->list); |
| 1803 | list_del(&r->list); | ||
| 1813 | } else { | 1804 | } else { |
| 1814 | if (watch) { | 1805 | if (watch) { |
| 1815 | list_add(&nentry->rule.rlist, &watch->rules); | 1806 | list_add(&nentry->rule.rlist, &watch->rules); |
| 1816 | list_del(&entry->rule.rlist); | 1807 | list_del(&r->rlist); |
| 1817 | } else if (tree) | 1808 | } else if (tree) |
| 1818 | list_replace_init(&entry->rule.rlist, | 1809 | list_replace_init(&r->rlist, &nentry->rule.rlist); |
| 1819 | &nentry->rule.rlist); | ||
| 1820 | list_replace_rcu(&entry->list, &nentry->list); | 1810 | list_replace_rcu(&entry->list, &nentry->list); |
| 1811 | list_replace(&r->list, &nentry->rule.list); | ||
| 1821 | } | 1812 | } |
| 1822 | call_rcu(&entry->rcu, audit_free_rule_rcu); | 1813 | call_rcu(&entry->rcu, audit_free_rule_rcu); |
| 1823 | 1814 | ||
| @@ -1831,27 +1822,19 @@ static int update_lsm_rule(struct audit_entry *entry) | |||
| 1831 | * updated rule. */ | 1822 | * updated rule. */ |
| 1832 | int audit_update_lsm_rules(void) | 1823 | int audit_update_lsm_rules(void) |
| 1833 | { | 1824 | { |
| 1834 | struct audit_entry *e, *n; | 1825 | struct audit_krule *r, *n; |
| 1835 | int i, err = 0; | 1826 | int i, err = 0; |
| 1836 | 1827 | ||
| 1837 | /* audit_filter_mutex synchronizes the writers */ | 1828 | /* audit_filter_mutex synchronizes the writers */ |
| 1838 | mutex_lock(&audit_filter_mutex); | 1829 | mutex_lock(&audit_filter_mutex); |
| 1839 | 1830 | ||
| 1840 | for (i = 0; i < AUDIT_NR_FILTERS; i++) { | 1831 | for (i = 0; i < AUDIT_NR_FILTERS; i++) { |
| 1841 | list_for_each_entry_safe(e, n, &audit_filter_list[i], list) { | 1832 | list_for_each_entry_safe(r, n, &audit_rules_list[i], list) { |
| 1842 | int res = update_lsm_rule(e); | 1833 | int res = update_lsm_rule(r); |
| 1843 | if (!err) | ||
| 1844 | err = res; | ||
| 1845 | } | ||
| 1846 | } | ||
| 1847 | for (i=0; i< AUDIT_INODE_BUCKETS; i++) { | ||
| 1848 | list_for_each_entry_safe(e, n, &audit_inode_hash[i], list) { | ||
| 1849 | int res = update_lsm_rule(e); | ||
| 1850 | if (!err) | 1834 | if (!err) |
| 1851 | err = res; | 1835 | err = res; |
| 1852 | } | 1836 | } |
| 1853 | } | 1837 | } |
| 1854 | |||
| 1855 | mutex_unlock(&audit_filter_mutex); | 1838 | mutex_unlock(&audit_filter_mutex); |
| 1856 | 1839 | ||
| 1857 | return err; | 1840 | return err; |
