diff options
author | Eric Paris <eparis@redhat.com> | 2009-06-11 14:31:34 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2009-06-23 23:50:36 -0400 |
commit | e85188f424c8eec7f311deed9a70bec57aeed741 (patch) | |
tree | 3456260b54bc8fd8d336d5e8865104480d5ac0fe | |
parent | b87ce6e4187c24b06483c8266822ce5e6b7fa7f3 (diff) |
Audit: dereferencing krule as if it were an audit_watch
audit_update_watch() runs all of the rules for a given watch and duplicates
them, attaches a new watch to them, and then when it finishes that process
and has called free on all of the old rules (ok maybe still inside the rcu
grace period) it proceeds to use the last element from list_for_each_entry_safe()
as if it were a krule rather than being the audit_watch which was anchoring
the list to output a message about audit rules changing.
This patch unfies the audit message from two different places into a helper
function and calls it from the correct location in audit_update_rules(). We
will now get an audit message about the config changing for each rule (with
each rules filterkey) rather than the previous garbage.
Signed-off-by: Eric Paris <eparis@redhat.com>
-rw-r--r-- | kernel/auditfilter.c | 58 |
1 files changed, 24 insertions, 34 deletions
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 19c0a0a2cede..e7466dd145c9 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c | |||
@@ -977,6 +977,27 @@ static struct audit_entry *audit_dupe_rule(struct audit_krule *old, | |||
977 | return entry; | 977 | return entry; |
978 | } | 978 | } |
979 | 979 | ||
980 | static void audit_watch_log_rule_change(struct audit_krule *r, struct audit_watch *w, char *op) | ||
981 | { | ||
982 | if (audit_enabled) { | ||
983 | struct audit_buffer *ab; | ||
984 | ab = audit_log_start(NULL, GFP_NOFS, AUDIT_CONFIG_CHANGE); | ||
985 | audit_log_format(ab, "auid=%u ses=%u op=", | ||
986 | audit_get_loginuid(current), | ||
987 | audit_get_sessionid(current)); | ||
988 | audit_log_string(ab, op); | ||
989 | audit_log_format(ab, " path="); | ||
990 | audit_log_untrustedstring(ab, w->path); | ||
991 | if (r->filterkey) { | ||
992 | audit_log_format(ab, " key="); | ||
993 | audit_log_untrustedstring(ab, r->filterkey); | ||
994 | } else | ||
995 | audit_log_format(ab, " key=(null)"); | ||
996 | audit_log_format(ab, " list=%d res=1", r->listnr); | ||
997 | audit_log_end(ab); | ||
998 | } | ||
999 | } | ||
1000 | |||
980 | /* Update inode info in audit rules based on filesystem event. */ | 1001 | /* Update inode info in audit rules based on filesystem event. */ |
981 | static void audit_update_watch(struct audit_parent *parent, | 1002 | static void audit_update_watch(struct audit_parent *parent, |
982 | const char *dname, dev_t dev, | 1003 | const char *dname, dev_t dev, |
@@ -1023,24 +1044,11 @@ static void audit_update_watch(struct audit_parent *parent, | |||
1023 | &nentry->rule.list); | 1044 | &nentry->rule.list); |
1024 | } | 1045 | } |
1025 | 1046 | ||
1047 | audit_watch_log_rule_change(r, owatch, "updated rules"); | ||
1048 | |||
1026 | call_rcu(&oentry->rcu, audit_free_rule_rcu); | 1049 | call_rcu(&oentry->rcu, audit_free_rule_rcu); |
1027 | } | 1050 | } |
1028 | 1051 | ||
1029 | if (audit_enabled) { | ||
1030 | struct audit_buffer *ab; | ||
1031 | ab = audit_log_start(NULL, GFP_NOFS, | ||
1032 | AUDIT_CONFIG_CHANGE); | ||
1033 | audit_log_format(ab, "auid=%u ses=%u", | ||
1034 | audit_get_loginuid(current), | ||
1035 | audit_get_sessionid(current)); | ||
1036 | audit_log_format(ab, | ||
1037 | " op=updated rules specifying path="); | ||
1038 | audit_log_untrustedstring(ab, owatch->path); | ||
1039 | audit_log_format(ab, " with dev=%u ino=%lu\n", | ||
1040 | dev, ino); | ||
1041 | audit_log_format(ab, " list=%d res=1", r->listnr); | ||
1042 | audit_log_end(ab); | ||
1043 | } | ||
1044 | audit_remove_watch(owatch); | 1052 | audit_remove_watch(owatch); |
1045 | goto add_watch_to_parent; /* event applies to a single watch */ | 1053 | goto add_watch_to_parent; /* event applies to a single watch */ |
1046 | } | 1054 | } |
@@ -1065,25 +1073,7 @@ static void audit_remove_parent_watches(struct audit_parent *parent) | |||
1065 | list_for_each_entry_safe(w, nextw, &parent->watches, wlist) { | 1073 | list_for_each_entry_safe(w, nextw, &parent->watches, wlist) { |
1066 | list_for_each_entry_safe(r, nextr, &w->rules, rlist) { | 1074 | list_for_each_entry_safe(r, nextr, &w->rules, rlist) { |
1067 | e = container_of(r, struct audit_entry, rule); | 1075 | e = container_of(r, struct audit_entry, rule); |
1068 | if (audit_enabled) { | 1076 | audit_watch_log_rule_change(r, w, "remove rule"); |
1069 | struct audit_buffer *ab; | ||
1070 | ab = audit_log_start(NULL, GFP_NOFS, | ||
1071 | AUDIT_CONFIG_CHANGE); | ||
1072 | audit_log_format(ab, "auid=%u ses=%u", | ||
1073 | audit_get_loginuid(current), | ||
1074 | audit_get_sessionid(current)); | ||
1075 | audit_log_format(ab, " op=remove rule path="); | ||
1076 | audit_log_untrustedstring(ab, w->path); | ||
1077 | if (r->filterkey) { | ||
1078 | audit_log_format(ab, " key="); | ||
1079 | audit_log_untrustedstring(ab, | ||
1080 | r->filterkey); | ||
1081 | } else | ||
1082 | audit_log_format(ab, " key=(null)"); | ||
1083 | audit_log_format(ab, " list=%d res=1", | ||
1084 | r->listnr); | ||
1085 | audit_log_end(ab); | ||
1086 | } | ||
1087 | list_del(&r->rlist); | 1077 | list_del(&r->rlist); |
1088 | list_del(&r->list); | 1078 | list_del(&r->list); |
1089 | list_del_rcu(&e->list); | 1079 | list_del_rcu(&e->list); |