diff options
-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; |