Commit e45aa212ea81d39b38ba158df344dc3a500153e5
1 parent
0590b9335a
Exists in
master
and in
4 other branches
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>
Showing 3 changed files with 41 additions and 56 deletions Side-by-side Diff
include/linux/audit.h
... | ... | @@ -373,6 +373,7 @@ |
373 | 373 | struct audit_watch *watch; /* associated watch */ |
374 | 374 | struct audit_tree *tree; /* associated watched tree */ |
375 | 375 | struct list_head rlist; /* entry in audit_{watch,tree}.rules list */ |
376 | + struct list_head list; /* for AUDIT_LIST* purposes only */ | |
376 | 377 | u64 prio; |
377 | 378 | }; |
378 | 379 |
kernel/audit_tree.c
kernel/auditfilter.c
... | ... | @@ -86,6 +86,14 @@ |
86 | 86 | #error Fix audit_filter_list initialiser |
87 | 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 | 98 | DEFINE_MUTEX(audit_filter_mutex); |
91 | 99 | |
92 | 100 | |
93 | 101 | |
... | ... | @@ -1007,12 +1015,15 @@ |
1007 | 1015 | list_del_rcu(&oentry->list); |
1008 | 1016 | |
1009 | 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 | 1020 | audit_panic("error updating watch, removing"); |
1012 | - else { | |
1021 | + } else { | |
1013 | 1022 | int h = audit_hash_ino((u32)ino); |
1014 | 1023 | list_add(&nentry->rule.rlist, &nwatch->rules); |
1015 | 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 | 1029 | call_rcu(&oentry->rcu, audit_free_rule_rcu); |
... | ... | @@ -1077,6 +1088,7 @@ |
1077 | 1088 | audit_log_end(ab); |
1078 | 1089 | } |
1079 | 1090 | list_del(&r->rlist); |
1091 | + list_del(&r->list); | |
1080 | 1092 | list_del_rcu(&e->list); |
1081 | 1093 | call_rcu(&e->rcu, audit_free_rule_rcu); |
1082 | 1094 | } |
1083 | 1095 | |
... | ... | @@ -1331,9 +1343,13 @@ |
1331 | 1343 | } |
1332 | 1344 | |
1333 | 1345 | if (entry->rule.flags & AUDIT_FILTER_PREPEND) { |
1346 | + list_add(&entry->rule.list, | |
1347 | + &audit_rules_list[entry->rule.listnr]); | |
1334 | 1348 | list_add_rcu(&entry->list, list); |
1335 | 1349 | entry->rule.flags &= ~AUDIT_FILTER_PREPEND; |
1336 | 1350 | } else { |
1351 | + list_add_tail(&entry->rule.list, | |
1352 | + &audit_rules_list[entry->rule.listnr]); | |
1337 | 1353 | list_add_tail_rcu(&entry->list, list); |
1338 | 1354 | } |
1339 | 1355 | #ifdef CONFIG_AUDITSYSCALL |
... | ... | @@ -1415,6 +1431,7 @@ |
1415 | 1431 | audit_remove_tree_rule(&e->rule); |
1416 | 1432 | |
1417 | 1433 | list_del_rcu(&e->list); |
1434 | + list_del(&e->rule.list); | |
1418 | 1435 | call_rcu(&e->rcu, audit_free_rule_rcu); |
1419 | 1436 | |
1420 | 1437 | #ifdef CONFIG_AUDITSYSCALL |
1421 | 1438 | |
1422 | 1439 | |
... | ... | @@ -1443,16 +1460,16 @@ |
1443 | 1460 | static void audit_list(int pid, int seq, struct sk_buff_head *q) |
1444 | 1461 | { |
1445 | 1462 | struct sk_buff *skb; |
1446 | - struct audit_entry *entry; | |
1463 | + struct audit_krule *r; | |
1447 | 1464 | int i; |
1448 | 1465 | |
1449 | 1466 | /* This is a blocking read, so use audit_filter_mutex instead of rcu |
1450 | 1467 | * iterator to sync with list writers. */ |
1451 | 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 | 1470 | struct audit_rule *rule; |
1454 | 1471 | |
1455 | - rule = audit_krule_to_rule(&entry->rule); | |
1472 | + rule = audit_krule_to_rule(r); | |
1456 | 1473 | if (unlikely(!rule)) |
1457 | 1474 | break; |
1458 | 1475 | skb = audit_make_reply(pid, seq, AUDIT_LIST, 0, 1, |
... | ... | @@ -1462,20 +1479,6 @@ |
1462 | 1479 | kfree(rule); |
1463 | 1480 | } |
1464 | 1481 | } |
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; | |
1468 | - | |
1469 | - rule = audit_krule_to_rule(&entry->rule); | |
1470 | - if (unlikely(!rule)) | |
1471 | - break; | |
1472 | - skb = audit_make_reply(pid, seq, AUDIT_LIST, 0, 1, | |
1473 | - rule, sizeof(*rule)); | |
1474 | - if (skb) | |
1475 | - skb_queue_tail(q, skb); | |
1476 | - kfree(rule); | |
1477 | - } | |
1478 | - } | |
1479 | 1482 | skb = audit_make_reply(pid, seq, AUDIT_LIST, 1, 1, NULL, 0); |
1480 | 1483 | if (skb) |
1481 | 1484 | skb_queue_tail(q, skb); |
1482 | 1485 | |
1483 | 1486 | |
... | ... | @@ -1485,16 +1488,16 @@ |
1485 | 1488 | static void audit_list_rules(int pid, int seq, struct sk_buff_head *q) |
1486 | 1489 | { |
1487 | 1490 | struct sk_buff *skb; |
1488 | - struct audit_entry *e; | |
1491 | + struct audit_krule *r; | |
1489 | 1492 | int i; |
1490 | 1493 | |
1491 | 1494 | /* This is a blocking read, so use audit_filter_mutex instead of rcu |
1492 | 1495 | * iterator to sync with list writers. */ |
1493 | 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 | 1498 | struct audit_rule_data *data; |
1496 | 1499 | |
1497 | - data = audit_krule_to_data(&e->rule); | |
1500 | + data = audit_krule_to_data(r); | |
1498 | 1501 | if (unlikely(!data)) |
1499 | 1502 | break; |
1500 | 1503 | skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 0, 1, |
... | ... | @@ -1504,20 +1507,6 @@ |
1504 | 1507 | kfree(data); |
1505 | 1508 | } |
1506 | 1509 | } |
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; | |
1510 | - | |
1511 | - data = audit_krule_to_data(&e->rule); | |
1512 | - if (unlikely(!data)) | |
1513 | - break; | |
1514 | - skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 0, 1, | |
1515 | - data, sizeof(*data) + data->buflen); | |
1516 | - if (skb) | |
1517 | - skb_queue_tail(q, skb); | |
1518 | - kfree(data); | |
1519 | - } | |
1520 | - } | |
1521 | 1510 | skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 1, 1, NULL, 0); |
1522 | 1511 | if (skb) |
1523 | 1512 | skb_queue_tail(q, skb); |
1524 | 1513 | |
1525 | 1514 | |
1526 | 1515 | |
1527 | 1516 | |
1528 | 1517 | |
1529 | 1518 | |
1530 | 1519 | |
1531 | 1520 | |
... | ... | @@ -1789,35 +1778,37 @@ |
1789 | 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 | 1784 | struct audit_entry *nentry; |
1795 | 1785 | struct audit_watch *watch; |
1796 | 1786 | struct audit_tree *tree; |
1797 | 1787 | int err = 0; |
1798 | 1788 | |
1799 | - if (!security_audit_rule_known(&entry->rule)) | |
1789 | + if (!security_audit_rule_known(r)) | |
1800 | 1790 | return 0; |
1801 | 1791 | |
1802 | - watch = entry->rule.watch; | |
1803 | - tree = entry->rule.tree; | |
1804 | - nentry = audit_dupe_rule(&entry->rule, watch); | |
1792 | + watch = r->watch; | |
1793 | + tree = r->tree; | |
1794 | + nentry = audit_dupe_rule(r, watch); | |
1805 | 1795 | if (IS_ERR(nentry)) { |
1806 | 1796 | /* save the first error encountered for the |
1807 | 1797 | * return value */ |
1808 | 1798 | err = PTR_ERR(nentry); |
1809 | 1799 | audit_panic("error updating LSM filters"); |
1810 | 1800 | if (watch) |
1811 | - list_del(&entry->rule.rlist); | |
1801 | + list_del(&r->rlist); | |
1812 | 1802 | list_del_rcu(&entry->list); |
1803 | + list_del(&r->list); | |
1813 | 1804 | } else { |
1814 | 1805 | if (watch) { |
1815 | 1806 | list_add(&nentry->rule.rlist, &watch->rules); |
1816 | - list_del(&entry->rule.rlist); | |
1807 | + list_del(&r->rlist); | |
1817 | 1808 | } else if (tree) |
1818 | - list_replace_init(&entry->rule.rlist, | |
1819 | - &nentry->rule.rlist); | |
1809 | + list_replace_init(&r->rlist, &nentry->rule.rlist); | |
1820 | 1810 | list_replace_rcu(&entry->list, &nentry->list); |
1811 | + list_replace(&r->list, &nentry->rule.list); | |
1821 | 1812 | } |
1822 | 1813 | call_rcu(&entry->rcu, audit_free_rule_rcu); |
1823 | 1814 | |
1824 | 1815 | |
1825 | 1816 | |
... | ... | @@ -1831,27 +1822,19 @@ |
1831 | 1822 | * updated rule. */ |
1832 | 1823 | int audit_update_lsm_rules(void) |
1833 | 1824 | { |
1834 | - struct audit_entry *e, *n; | |
1825 | + struct audit_krule *r, *n; | |
1835 | 1826 | int i, err = 0; |
1836 | 1827 | |
1837 | 1828 | /* audit_filter_mutex synchronizes the writers */ |
1838 | 1829 | mutex_lock(&audit_filter_mutex); |
1839 | 1830 | |
1840 | 1831 | for (i = 0; i < AUDIT_NR_FILTERS; i++) { |
1841 | - list_for_each_entry_safe(e, n, &audit_filter_list[i], list) { | |
1842 | - int res = update_lsm_rule(e); | |
1832 | + list_for_each_entry_safe(r, n, &audit_rules_list[i], list) { | |
1833 | + int res = update_lsm_rule(r); | |
1843 | 1834 | if (!err) |
1844 | 1835 | err = res; |
1845 | 1836 | } |
1846 | 1837 | } |
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) | |
1851 | - err = res; | |
1852 | - } | |
1853 | - } | |
1854 | - | |
1855 | 1838 | mutex_unlock(&audit_filter_mutex); |
1856 | 1839 | |
1857 | 1840 | return err; |