mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 03:36:19 +00:00
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>
This commit is contained in:
parent
0590b9335a
commit
e45aa212ea
3 changed files with 41 additions and 56 deletions
|
@ -373,6 +373,7 @@ struct audit_krule {
|
||||||
struct audit_watch *watch; /* associated watch */
|
struct audit_watch *watch; /* associated watch */
|
||||||
struct audit_tree *tree; /* associated watched tree */
|
struct audit_tree *tree; /* associated watched tree */
|
||||||
struct list_head rlist; /* entry in audit_{watch,tree}.rules list */
|
struct list_head rlist; /* entry in audit_{watch,tree}.rules list */
|
||||||
|
struct list_head list; /* for AUDIT_LIST* purposes only */
|
||||||
u64 prio;
|
u64 prio;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -450,6 +450,7 @@ static void kill_rules(struct audit_tree *tree)
|
||||||
audit_log_end(ab);
|
audit_log_end(ab);
|
||||||
rule->tree = NULL;
|
rule->tree = NULL;
|
||||||
list_del_rcu(&entry->list);
|
list_del_rcu(&entry->list);
|
||||||
|
list_del(&entry->rule.list);
|
||||||
call_rcu(&entry->rcu, audit_free_rule_rcu);
|
call_rcu(&entry->rcu, audit_free_rule_rcu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,14 @@ struct list_head audit_filter_list[AUDIT_NR_FILTERS] = {
|
||||||
#error Fix audit_filter_list initialiser
|
#error Fix audit_filter_list initialiser
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
static struct list_head audit_rules_list[AUDIT_NR_FILTERS] = {
|
||||||
|
LIST_HEAD_INIT(audit_rules_list[0]),
|
||||||
|
LIST_HEAD_INIT(audit_rules_list[1]),
|
||||||
|
LIST_HEAD_INIT(audit_rules_list[2]),
|
||||||
|
LIST_HEAD_INIT(audit_rules_list[3]),
|
||||||
|
LIST_HEAD_INIT(audit_rules_list[4]),
|
||||||
|
LIST_HEAD_INIT(audit_rules_list[5]),
|
||||||
|
};
|
||||||
|
|
||||||
DEFINE_MUTEX(audit_filter_mutex);
|
DEFINE_MUTEX(audit_filter_mutex);
|
||||||
|
|
||||||
|
@ -1007,12 +1015,15 @@ static void audit_update_watch(struct audit_parent *parent,
|
||||||
list_del_rcu(&oentry->list);
|
list_del_rcu(&oentry->list);
|
||||||
|
|
||||||
nentry = audit_dupe_rule(&oentry->rule, nwatch);
|
nentry = audit_dupe_rule(&oentry->rule, nwatch);
|
||||||
if (IS_ERR(nentry))
|
if (IS_ERR(nentry)) {
|
||||||
|
list_del(&oentry->rule.list);
|
||||||
audit_panic("error updating watch, removing");
|
audit_panic("error updating watch, removing");
|
||||||
else {
|
} else {
|
||||||
int h = audit_hash_ino((u32)ino);
|
int h = audit_hash_ino((u32)ino);
|
||||||
list_add(&nentry->rule.rlist, &nwatch->rules);
|
list_add(&nentry->rule.rlist, &nwatch->rules);
|
||||||
list_add_rcu(&nentry->list, &audit_inode_hash[h]);
|
list_add_rcu(&nentry->list, &audit_inode_hash[h]);
|
||||||
|
list_replace(&oentry->rule.list,
|
||||||
|
&nentry->rule.list);
|
||||||
}
|
}
|
||||||
|
|
||||||
call_rcu(&oentry->rcu, audit_free_rule_rcu);
|
call_rcu(&oentry->rcu, audit_free_rule_rcu);
|
||||||
|
@ -1077,6 +1088,7 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
|
||||||
audit_log_end(ab);
|
audit_log_end(ab);
|
||||||
}
|
}
|
||||||
list_del(&r->rlist);
|
list_del(&r->rlist);
|
||||||
|
list_del(&r->list);
|
||||||
list_del_rcu(&e->list);
|
list_del_rcu(&e->list);
|
||||||
call_rcu(&e->rcu, audit_free_rule_rcu);
|
call_rcu(&e->rcu, audit_free_rule_rcu);
|
||||||
}
|
}
|
||||||
|
@ -1331,9 +1343,13 @@ static inline int audit_add_rule(struct audit_entry *entry,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
|
if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
|
||||||
|
list_add(&entry->rule.list,
|
||||||
|
&audit_rules_list[entry->rule.listnr]);
|
||||||
list_add_rcu(&entry->list, list);
|
list_add_rcu(&entry->list, list);
|
||||||
entry->rule.flags &= ~AUDIT_FILTER_PREPEND;
|
entry->rule.flags &= ~AUDIT_FILTER_PREPEND;
|
||||||
} else {
|
} else {
|
||||||
|
list_add_tail(&entry->rule.list,
|
||||||
|
&audit_rules_list[entry->rule.listnr]);
|
||||||
list_add_tail_rcu(&entry->list, list);
|
list_add_tail_rcu(&entry->list, list);
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_AUDITSYSCALL
|
#ifdef CONFIG_AUDITSYSCALL
|
||||||
|
@ -1415,6 +1431,7 @@ static inline int audit_del_rule(struct audit_entry *entry,
|
||||||
audit_remove_tree_rule(&e->rule);
|
audit_remove_tree_rule(&e->rule);
|
||||||
|
|
||||||
list_del_rcu(&e->list);
|
list_del_rcu(&e->list);
|
||||||
|
list_del(&e->rule.list);
|
||||||
call_rcu(&e->rcu, audit_free_rule_rcu);
|
call_rcu(&e->rcu, audit_free_rule_rcu);
|
||||||
|
|
||||||
#ifdef CONFIG_AUDITSYSCALL
|
#ifdef CONFIG_AUDITSYSCALL
|
||||||
|
@ -1443,30 +1460,16 @@ out:
|
||||||
static void audit_list(int pid, int seq, struct sk_buff_head *q)
|
static void audit_list(int pid, int seq, struct sk_buff_head *q)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct audit_entry *entry;
|
struct audit_krule *r;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* This is a blocking read, so use audit_filter_mutex instead of rcu
|
/* This is a blocking read, so use audit_filter_mutex instead of rcu
|
||||||
* iterator to sync with list writers. */
|
* iterator to sync with list writers. */
|
||||||
for (i=0; i<AUDIT_NR_FILTERS; i++) {
|
for (i=0; i<AUDIT_NR_FILTERS; i++) {
|
||||||
list_for_each_entry(entry, &audit_filter_list[i], list) {
|
list_for_each_entry(r, &audit_rules_list[i], list) {
|
||||||
struct audit_rule *rule;
|
struct audit_rule *rule;
|
||||||
|
|
||||||
rule = audit_krule_to_rule(&entry->rule);
|
rule = audit_krule_to_rule(r);
|
||||||
if (unlikely(!rule))
|
|
||||||
break;
|
|
||||||
skb = audit_make_reply(pid, seq, AUDIT_LIST, 0, 1,
|
|
||||||
rule, sizeof(*rule));
|
|
||||||
if (skb)
|
|
||||||
skb_queue_tail(q, skb);
|
|
||||||
kfree(rule);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i = 0; i < AUDIT_INODE_BUCKETS; i++) {
|
|
||||||
list_for_each_entry(entry, &audit_inode_hash[i], list) {
|
|
||||||
struct audit_rule *rule;
|
|
||||||
|
|
||||||
rule = audit_krule_to_rule(&entry->rule);
|
|
||||||
if (unlikely(!rule))
|
if (unlikely(!rule))
|
||||||
break;
|
break;
|
||||||
skb = audit_make_reply(pid, seq, AUDIT_LIST, 0, 1,
|
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)
|
||||||
static void audit_list_rules(int pid, int seq, struct sk_buff_head *q)
|
static void audit_list_rules(int pid, int seq, struct sk_buff_head *q)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct audit_entry *e;
|
struct audit_krule *r;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* This is a blocking read, so use audit_filter_mutex instead of rcu
|
/* This is a blocking read, so use audit_filter_mutex instead of rcu
|
||||||
* iterator to sync with list writers. */
|
* iterator to sync with list writers. */
|
||||||
for (i=0; i<AUDIT_NR_FILTERS; i++) {
|
for (i=0; i<AUDIT_NR_FILTERS; i++) {
|
||||||
list_for_each_entry(e, &audit_filter_list[i], list) {
|
list_for_each_entry(r, &audit_rules_list[i], list) {
|
||||||
struct audit_rule_data *data;
|
struct audit_rule_data *data;
|
||||||
|
|
||||||
data = audit_krule_to_data(&e->rule);
|
data = audit_krule_to_data(r);
|
||||||
if (unlikely(!data))
|
|
||||||
break;
|
|
||||||
skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 0, 1,
|
|
||||||
data, sizeof(*data) + data->buflen);
|
|
||||||
if (skb)
|
|
||||||
skb_queue_tail(q, skb);
|
|
||||||
kfree(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i=0; i< AUDIT_INODE_BUCKETS; i++) {
|
|
||||||
list_for_each_entry(e, &audit_inode_hash[i], list) {
|
|
||||||
struct audit_rule_data *data;
|
|
||||||
|
|
||||||
data = audit_krule_to_data(&e->rule);
|
|
||||||
if (unlikely(!data))
|
if (unlikely(!data))
|
||||||
break;
|
break;
|
||||||
skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 0, 1,
|
skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 0, 1,
|
||||||
|
@ -1789,35 +1778,37 @@ unlock_and_return:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int update_lsm_rule(struct audit_entry *entry)
|
static int update_lsm_rule(struct audit_krule *r)
|
||||||
{
|
{
|
||||||
|
struct audit_entry *entry = container_of(r, struct audit_entry, rule);
|
||||||
struct audit_entry *nentry;
|
struct audit_entry *nentry;
|
||||||
struct audit_watch *watch;
|
struct audit_watch *watch;
|
||||||
struct audit_tree *tree;
|
struct audit_tree *tree;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (!security_audit_rule_known(&entry->rule))
|
if (!security_audit_rule_known(r))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
watch = entry->rule.watch;
|
watch = r->watch;
|
||||||
tree = entry->rule.tree;
|
tree = r->tree;
|
||||||
nentry = audit_dupe_rule(&entry->rule, watch);
|
nentry = audit_dupe_rule(r, watch);
|
||||||
if (IS_ERR(nentry)) {
|
if (IS_ERR(nentry)) {
|
||||||
/* save the first error encountered for the
|
/* save the first error encountered for the
|
||||||
* return value */
|
* return value */
|
||||||
err = PTR_ERR(nentry);
|
err = PTR_ERR(nentry);
|
||||||
audit_panic("error updating LSM filters");
|
audit_panic("error updating LSM filters");
|
||||||
if (watch)
|
if (watch)
|
||||||
list_del(&entry->rule.rlist);
|
list_del(&r->rlist);
|
||||||
list_del_rcu(&entry->list);
|
list_del_rcu(&entry->list);
|
||||||
|
list_del(&r->list);
|
||||||
} else {
|
} else {
|
||||||
if (watch) {
|
if (watch) {
|
||||||
list_add(&nentry->rule.rlist, &watch->rules);
|
list_add(&nentry->rule.rlist, &watch->rules);
|
||||||
list_del(&entry->rule.rlist);
|
list_del(&r->rlist);
|
||||||
} else if (tree)
|
} else if (tree)
|
||||||
list_replace_init(&entry->rule.rlist,
|
list_replace_init(&r->rlist, &nentry->rule.rlist);
|
||||||
&nentry->rule.rlist);
|
|
||||||
list_replace_rcu(&entry->list, &nentry->list);
|
list_replace_rcu(&entry->list, &nentry->list);
|
||||||
|
list_replace(&r->list, &nentry->rule.list);
|
||||||
}
|
}
|
||||||
call_rcu(&entry->rcu, audit_free_rule_rcu);
|
call_rcu(&entry->rcu, audit_free_rule_rcu);
|
||||||
|
|
||||||
|
@ -1831,27 +1822,19 @@ static int update_lsm_rule(struct audit_entry *entry)
|
||||||
* updated rule. */
|
* updated rule. */
|
||||||
int audit_update_lsm_rules(void)
|
int audit_update_lsm_rules(void)
|
||||||
{
|
{
|
||||||
struct audit_entry *e, *n;
|
struct audit_krule *r, *n;
|
||||||
int i, err = 0;
|
int i, err = 0;
|
||||||
|
|
||||||
/* audit_filter_mutex synchronizes the writers */
|
/* audit_filter_mutex synchronizes the writers */
|
||||||
mutex_lock(&audit_filter_mutex);
|
mutex_lock(&audit_filter_mutex);
|
||||||
|
|
||||||
for (i = 0; i < AUDIT_NR_FILTERS; i++) {
|
for (i = 0; i < AUDIT_NR_FILTERS; i++) {
|
||||||
list_for_each_entry_safe(e, n, &audit_filter_list[i], list) {
|
list_for_each_entry_safe(r, n, &audit_rules_list[i], list) {
|
||||||
int res = update_lsm_rule(e);
|
int res = update_lsm_rule(r);
|
||||||
if (!err)
|
if (!err)
|
||||||
err = res;
|
err = res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i=0; i< AUDIT_INODE_BUCKETS; i++) {
|
|
||||||
list_for_each_entry_safe(e, n, &audit_inode_hash[i], list) {
|
|
||||||
int res = update_lsm_rule(e);
|
|
||||||
if (!err)
|
|
||||||
err = res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&audit_filter_mutex);
|
mutex_unlock(&audit_filter_mutex);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
Loading…
Reference in a new issue