aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2009-12-17 20:12:04 -0500
committerEric Paris <eparis@redhat.com>2010-07-28 09:58:16 -0400
commitae7b8f4108bcffb42173f867ce845268c7202d48 (patch)
tree049d357dcbffe597c77c534ea211c3efd26680e3
parentb7ba83715317007962ee318587de92f14e9c3aaa (diff)
Audit: clean up the audit_watch split
No real changes, just cleanup to the audit_watch split patch which we done with minimal code changes for easy review. Now fix interfaces to make things work better. Signed-off-by: Eric Paris <eparis@redhat.com>
-rw-r--r--kernel/audit.c1
-rw-r--r--kernel/audit.h13
-rw-r--r--kernel/audit_watch.c67
-rw-r--r--kernel/auditfilter.c41
-rw-r--r--kernel/auditsc.c5
5 files changed, 60 insertions, 67 deletions
diff --git a/kernel/audit.c b/kernel/audit.c
index c71bd26631a2..05a32f0d87dc 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -56,7 +56,6 @@
56#include <net/netlink.h> 56#include <net/netlink.h>
57#include <linux/skbuff.h> 57#include <linux/skbuff.h>
58#include <linux/netlink.h> 58#include <linux/netlink.h>
59#include <linux/inotify.h>
60#include <linux/freezer.h> 59#include <linux/freezer.h>
61#include <linux/tty.h> 60#include <linux/tty.h>
62 61
diff --git a/kernel/audit.h b/kernel/audit.h
index 208687be4f30..82c8a09099f4 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -104,20 +104,15 @@ extern void audit_free_rule_rcu(struct rcu_head *);
104extern struct list_head audit_filter_list[]; 104extern struct list_head audit_filter_list[];
105 105
106/* audit watch functions */ 106/* audit watch functions */
107extern unsigned long audit_watch_inode(struct audit_watch *watch);
108extern dev_t audit_watch_dev(struct audit_watch *watch);
109extern void audit_put_watch(struct audit_watch *watch); 107extern void audit_put_watch(struct audit_watch *watch);
110extern void audit_get_watch(struct audit_watch *watch); 108extern void audit_get_watch(struct audit_watch *watch);
111extern int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op); 109extern int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op);
112extern int audit_add_watch(struct audit_krule *krule); 110extern int audit_add_watch(struct audit_krule *krule, struct list_head **list);
113extern void audit_remove_watch(struct audit_watch *watch);
114extern void audit_remove_watch_rule(struct audit_krule *krule, struct list_head *list); 111extern void audit_remove_watch_rule(struct audit_krule *krule, struct list_head *list);
115extern void audit_inotify_unregister(struct list_head *in_list); 112extern void audit_watch_inotify_unregister(struct list_head *in_list);
116extern char *audit_watch_path(struct audit_watch *watch); 113extern char *audit_watch_path(struct audit_watch *watch);
117extern struct list_head *audit_watch_rules(struct audit_watch *watch); 114extern int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev);
118 115extern struct audit_entry *audit_dupe_rule(struct audit_krule *old);
119extern struct audit_entry *audit_dupe_rule(struct audit_krule *old,
120 struct audit_watch *watch);
121 116
122#ifdef CONFIG_AUDIT_TREE 117#ifdef CONFIG_AUDIT_TREE
123extern struct audit_chunk *audit_tree_lookup(const struct inode *); 118extern struct audit_chunk *audit_tree_lookup(const struct inode *);
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 8df43696f4ba..c2ca7168bfd1 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -51,12 +51,12 @@ struct audit_watch {
51 unsigned long ino; /* associated inode number */ 51 unsigned long ino; /* associated inode number */
52 struct audit_parent *parent; /* associated parent */ 52 struct audit_parent *parent; /* associated parent */
53 struct list_head wlist; /* entry in parent->watches list */ 53 struct list_head wlist; /* entry in parent->watches list */
54 struct list_head rules; /* associated rules */ 54 struct list_head rules; /* anchor for krule->rlist */
55}; 55};
56 56
57struct audit_parent { 57struct audit_parent {
58 struct list_head ilist; /* entry in inotify registration list */ 58 struct list_head ilist; /* tmp list used to free parents */
59 struct list_head watches; /* associated watches */ 59 struct list_head watches; /* anchor for audit_watch->wlist */
60 struct inotify_watch wdata; /* inotify watch data */ 60 struct inotify_watch wdata; /* inotify watch data */
61 unsigned flags; /* status flags */ 61 unsigned flags; /* status flags */
62}; 62};
@@ -78,13 +78,18 @@ struct inotify_handle *audit_ih;
78/* Inotify events we care about. */ 78/* Inotify events we care about. */
79#define AUDIT_IN_WATCH IN_MOVE|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELF 79#define AUDIT_IN_WATCH IN_MOVE|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELF
80 80
81static void audit_free_parent(struct inotify_watch *i_watch) 81static void audit_free_parent(struct audit_parent *parent)
82{
83 WARN_ON(!list_empty(&parent->watches));
84 kfree(parent);
85}
86
87static void audit_destroy_watch(struct inotify_watch *i_watch)
82{ 88{
83 struct audit_parent *parent; 89 struct audit_parent *parent;
84 90
85 parent = container_of(i_watch, struct audit_parent, wdata); 91 parent = container_of(i_watch, struct audit_parent, wdata);
86 WARN_ON(!list_empty(&parent->watches)); 92 audit_free_parent(parent);
87 kfree(parent);
88} 93}
89 94
90void audit_get_watch(struct audit_watch *watch) 95void audit_get_watch(struct audit_watch *watch)
@@ -115,19 +120,11 @@ char *audit_watch_path(struct audit_watch *watch)
115 return watch->path; 120 return watch->path;
116} 121}
117 122
118struct list_head *audit_watch_rules(struct audit_watch *watch) 123int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
119{ 124{
120 return &watch->rules; 125 return (watch->ino != (unsigned long)-1) &&
121} 126 (watch->ino == ino) &&
122 127 (watch->dev == dev);
123unsigned long audit_watch_inode(struct audit_watch *watch)
124{
125 return watch->ino;
126}
127
128dev_t audit_watch_dev(struct audit_watch *watch)
129{
130 return watch->dev;
131} 128}
132 129
133/* Initialize a parent watch entry. */ 130/* Initialize a parent watch entry. */
@@ -149,7 +146,7 @@ static struct audit_parent *audit_init_parent(struct nameidata *ndp)
149 wd = inotify_add_watch(audit_ih, &parent->wdata, 146 wd = inotify_add_watch(audit_ih, &parent->wdata,
150 ndp->path.dentry->d_inode, AUDIT_IN_WATCH); 147 ndp->path.dentry->d_inode, AUDIT_IN_WATCH);
151 if (wd < 0) { 148 if (wd < 0) {
152 audit_free_parent(&parent->wdata); 149 audit_free_parent(parent);
153 return ERR_PTR(wd); 150 return ERR_PTR(wd);
154 } 151 }
155 152
@@ -251,15 +248,19 @@ static void audit_update_watch(struct audit_parent *parent,
251 struct audit_entry *oentry, *nentry; 248 struct audit_entry *oentry, *nentry;
252 249
253 mutex_lock(&audit_filter_mutex); 250 mutex_lock(&audit_filter_mutex);
251 /* Run all of the watches on this parent looking for the one that
252 * matches the given dname */
254 list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) { 253 list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
255 if (audit_compare_dname_path(dname, owatch->path, NULL)) 254 if (audit_compare_dname_path(dname, owatch->path, NULL))
256 continue; 255 continue;
257 256
258 /* If the update involves invalidating rules, do the inode-based 257 /* If the update involves invalidating rules, do the inode-based
259 * filtering now, so we don't omit records. */ 258 * filtering now, so we don't omit records. */
260 if (invalidating && current->audit_context) 259 if (invalidating && !audit_dummy_context())
261 audit_filter_inodes(current, current->audit_context); 260 audit_filter_inodes(current, current->audit_context);
262 261
262 /* updating ino will likely change which audit_hash_list we
263 * are on so we need a new watch for the new list */
263 nwatch = audit_dupe_watch(owatch); 264 nwatch = audit_dupe_watch(owatch);
264 if (IS_ERR(nwatch)) { 265 if (IS_ERR(nwatch)) {
265 mutex_unlock(&audit_filter_mutex); 266 mutex_unlock(&audit_filter_mutex);
@@ -275,12 +276,21 @@ static void audit_update_watch(struct audit_parent *parent,
275 list_del(&oentry->rule.rlist); 276 list_del(&oentry->rule.rlist);
276 list_del_rcu(&oentry->list); 277 list_del_rcu(&oentry->list);
277 278
278 nentry = audit_dupe_rule(&oentry->rule, nwatch); 279 nentry = audit_dupe_rule(&oentry->rule);
279 if (IS_ERR(nentry)) { 280 if (IS_ERR(nentry)) {
280 list_del(&oentry->rule.list); 281 list_del(&oentry->rule.list);
281 audit_panic("error updating watch, removing"); 282 audit_panic("error updating watch, removing");
282 } else { 283 } else {
283 int h = audit_hash_ino((u32)ino); 284 int h = audit_hash_ino((u32)ino);
285
286 /*
287 * nentry->rule.watch == oentry->rule.watch so
288 * we must drop that reference and set it to our
289 * new watch.
290 */
291 audit_put_watch(nentry->rule.watch);
292 audit_get_watch(nwatch);
293 nentry->rule.watch = nwatch;
284 list_add(&nentry->rule.rlist, &nwatch->rules); 294 list_add(&nentry->rule.rlist, &nwatch->rules);
285 list_add_rcu(&nentry->list, &audit_inode_hash[h]); 295 list_add_rcu(&nentry->list, &audit_inode_hash[h]);
286 list_replace(&oentry->rule.list, 296 list_replace(&oentry->rule.list,
@@ -329,14 +339,14 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
329 339
330/* Unregister inotify watches for parents on in_list. 340/* Unregister inotify watches for parents on in_list.
331 * Generates an IN_IGNORED event. */ 341 * Generates an IN_IGNORED event. */
332void audit_inotify_unregister(struct list_head *in_list) 342void audit_watch_inotify_unregister(struct list_head *in_list)
333{ 343{
334 struct audit_parent *p, *n; 344 struct audit_parent *p, *n;
335 345
336 list_for_each_entry_safe(p, n, in_list, ilist) { 346 list_for_each_entry_safe(p, n, in_list, ilist) {
337 list_del(&p->ilist); 347 list_del(&p->ilist);
338 inotify_rm_watch(audit_ih, &p->wdata); 348 inotify_rm_watch(audit_ih, &p->wdata);
339 /* the unpin matching the pin in audit_do_del_rule() */ 349 /* the unpin matching the pin in audit_remove_watch_rule() */
340 unpin_inotify_watch(&p->wdata); 350 unpin_inotify_watch(&p->wdata);
341 } 351 }
342} 352}
@@ -423,13 +433,13 @@ static void audit_add_to_parent(struct audit_krule *krule,
423 433
424/* Find a matching watch entry, or add this one. 434/* Find a matching watch entry, or add this one.
425 * Caller must hold audit_filter_mutex. */ 435 * Caller must hold audit_filter_mutex. */
426int audit_add_watch(struct audit_krule *krule) 436int audit_add_watch(struct audit_krule *krule, struct list_head **list)
427{ 437{
428 struct audit_watch *watch = krule->watch; 438 struct audit_watch *watch = krule->watch;
429 struct inotify_watch *i_watch; 439 struct inotify_watch *i_watch;
430 struct audit_parent *parent; 440 struct audit_parent *parent;
431 struct nameidata *ndp = NULL, *ndw = NULL; 441 struct nameidata *ndp = NULL, *ndw = NULL;
432 int ret = 0; 442 int h, ret = 0;
433 443
434 mutex_unlock(&audit_filter_mutex); 444 mutex_unlock(&audit_filter_mutex);
435 445
@@ -475,6 +485,8 @@ int audit_add_watch(struct audit_krule *krule)
475 /* match get in audit_init_parent or inotify_find_watch */ 485 /* match get in audit_init_parent or inotify_find_watch */
476 put_inotify_watch(&parent->wdata); 486 put_inotify_watch(&parent->wdata);
477 487
488 h = audit_hash_ino((u32)watch->ino);
489 *list = &audit_inode_hash[h];
478error: 490error:
479 audit_put_nd(ndp, ndw); /* NULL args OK */ 491 audit_put_nd(ndp, ndw); /* NULL args OK */
480 return ret; 492 return ret;
@@ -514,8 +526,7 @@ static void audit_handle_ievent(struct inotify_watch *i_watch, u32 wd, u32 mask,
514 parent = container_of(i_watch, struct audit_parent, wdata); 526 parent = container_of(i_watch, struct audit_parent, wdata);
515 527
516 if (mask & (IN_CREATE|IN_MOVED_TO) && inode) 528 if (mask & (IN_CREATE|IN_MOVED_TO) && inode)
517 audit_update_watch(parent, dname, inode->i_sb->s_dev, 529 audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0);
518 inode->i_ino, 0);
519 else if (mask & (IN_DELETE|IN_MOVED_FROM)) 530 else if (mask & (IN_DELETE|IN_MOVED_FROM))
520 audit_update_watch(parent, dname, (dev_t)-1, (unsigned long)-1, 1); 531 audit_update_watch(parent, dname, (dev_t)-1, (unsigned long)-1, 1);
521 /* inotify automatically removes the watch and sends IN_IGNORED */ 532 /* inotify automatically removes the watch and sends IN_IGNORED */
@@ -531,7 +542,7 @@ static void audit_handle_ievent(struct inotify_watch *i_watch, u32 wd, u32 mask,
531 542
532static const struct inotify_operations audit_inotify_ops = { 543static const struct inotify_operations audit_inotify_ops = {
533 .handle_event = audit_handle_ievent, 544 .handle_event = audit_handle_ievent,
534 .destroy_watch = audit_free_parent, 545 .destroy_watch = audit_destroy_watch,
535}; 546};
536 547
537static int __init audit_watch_init(void) 548static int __init audit_watch_init(void)
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index ce08041f578d..ac87577f36b5 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -71,6 +71,7 @@ static inline void audit_free_rule(struct audit_entry *e)
71{ 71{
72 int i; 72 int i;
73 struct audit_krule *erule = &e->rule; 73 struct audit_krule *erule = &e->rule;
74
74 /* some rules don't have associated watches */ 75 /* some rules don't have associated watches */
75 if (erule->watch) 76 if (erule->watch)
76 audit_put_watch(erule->watch); 77 audit_put_watch(erule->watch);
@@ -746,8 +747,7 @@ static inline int audit_dupe_lsm_field(struct audit_field *df,
746 * rule with the new rule in the filterlist, then free the old rule. 747 * rule with the new rule in the filterlist, then free the old rule.
747 * The rlist element is undefined; list manipulations are handled apart from 748 * The rlist element is undefined; list manipulations are handled apart from
748 * the initial copy. */ 749 * the initial copy. */
749struct audit_entry *audit_dupe_rule(struct audit_krule *old, 750struct audit_entry *audit_dupe_rule(struct audit_krule *old)
750 struct audit_watch *watch)
751{ 751{
752 u32 fcount = old->field_count; 752 u32 fcount = old->field_count;
753 struct audit_entry *entry; 753 struct audit_entry *entry;
@@ -769,8 +769,8 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old,
769 new->prio = old->prio; 769 new->prio = old->prio;
770 new->buflen = old->buflen; 770 new->buflen = old->buflen;
771 new->inode_f = old->inode_f; 771 new->inode_f = old->inode_f;
772 new->watch = NULL;
773 new->field_count = old->field_count; 772 new->field_count = old->field_count;
773
774 /* 774 /*
775 * note that we are OK with not refcounting here; audit_match_tree() 775 * note that we are OK with not refcounting here; audit_match_tree()
776 * never dereferences tree and we can't get false positives there 776 * never dereferences tree and we can't get false positives there
@@ -811,9 +811,9 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old,
811 } 811 }
812 } 812 }
813 813
814 if (watch) { 814 if (old->watch) {
815 audit_get_watch(watch); 815 audit_get_watch(old->watch);
816 new->watch = watch; 816 new->watch = old->watch;
817 } 817 }
818 818
819 return entry; 819 return entry;
@@ -866,7 +866,7 @@ static inline int audit_add_rule(struct audit_entry *entry)
866 struct audit_watch *watch = entry->rule.watch; 866 struct audit_watch *watch = entry->rule.watch;
867 struct audit_tree *tree = entry->rule.tree; 867 struct audit_tree *tree = entry->rule.tree;
868 struct list_head *list; 868 struct list_head *list;
869 int h, err; 869 int err;
870#ifdef CONFIG_AUDITSYSCALL 870#ifdef CONFIG_AUDITSYSCALL
871 int dont_count = 0; 871 int dont_count = 0;
872 872
@@ -889,15 +889,11 @@ static inline int audit_add_rule(struct audit_entry *entry)
889 889
890 if (watch) { 890 if (watch) {
891 /* audit_filter_mutex is dropped and re-taken during this call */ 891 /* audit_filter_mutex is dropped and re-taken during this call */
892 err = audit_add_watch(&entry->rule); 892 err = audit_add_watch(&entry->rule, &list);
893 if (err) { 893 if (err) {
894 mutex_unlock(&audit_filter_mutex); 894 mutex_unlock(&audit_filter_mutex);
895 goto error; 895 goto error;
896 } 896 }
897 /* entry->rule.watch may have changed during audit_add_watch() */
898 watch = entry->rule.watch;
899 h = audit_hash_ino((u32)audit_watch_inode(watch));
900 list = &audit_inode_hash[h];
901 } 897 }
902 if (tree) { 898 if (tree) {
903 err = audit_add_tree_rule(&entry->rule); 899 err = audit_add_tree_rule(&entry->rule);
@@ -949,7 +945,7 @@ static inline int audit_del_rule(struct audit_entry *entry)
949 struct audit_watch *watch = entry->rule.watch; 945 struct audit_watch *watch = entry->rule.watch;
950 struct audit_tree *tree = entry->rule.tree; 946 struct audit_tree *tree = entry->rule.tree;
951 struct list_head *list; 947 struct list_head *list;
952 LIST_HEAD(inotify_list); 948 LIST_HEAD(inotify_unregister_list);
953 int ret = 0; 949 int ret = 0;
954#ifdef CONFIG_AUDITSYSCALL 950#ifdef CONFIG_AUDITSYSCALL
955 int dont_count = 0; 951 int dont_count = 0;
@@ -969,7 +965,7 @@ static inline int audit_del_rule(struct audit_entry *entry)
969 } 965 }
970 966
971 if (e->rule.watch) 967 if (e->rule.watch)
972 audit_remove_watch_rule(&e->rule, &inotify_list); 968 audit_remove_watch_rule(&e->rule, &inotify_unregister_list);
973 969
974 if (e->rule.tree) 970 if (e->rule.tree)
975 audit_remove_tree_rule(&e->rule); 971 audit_remove_tree_rule(&e->rule);
@@ -987,8 +983,8 @@ static inline int audit_del_rule(struct audit_entry *entry)
987#endif 983#endif
988 mutex_unlock(&audit_filter_mutex); 984 mutex_unlock(&audit_filter_mutex);
989 985
990 if (!list_empty(&inotify_list)) 986 if (!list_empty(&inotify_unregister_list))
991 audit_inotify_unregister(&inotify_list); 987 audit_watch_inotify_unregister(&inotify_unregister_list);
992 988
993out: 989out:
994 if (watch) 990 if (watch)
@@ -1323,30 +1319,23 @@ static int update_lsm_rule(struct audit_krule *r)
1323{ 1319{
1324 struct audit_entry *entry = container_of(r, struct audit_entry, rule); 1320 struct audit_entry *entry = container_of(r, struct audit_entry, rule);
1325 struct audit_entry *nentry; 1321 struct audit_entry *nentry;
1326 struct audit_watch *watch;
1327 struct audit_tree *tree;
1328 int err = 0; 1322 int err = 0;
1329 1323
1330 if (!security_audit_rule_known(r)) 1324 if (!security_audit_rule_known(r))
1331 return 0; 1325 return 0;
1332 1326
1333 watch = r->watch; 1327 nentry = audit_dupe_rule(r);
1334 tree = r->tree;
1335 nentry = audit_dupe_rule(r, watch);
1336 if (IS_ERR(nentry)) { 1328 if (IS_ERR(nentry)) {
1337 /* save the first error encountered for the 1329 /* save the first error encountered for the
1338 * return value */ 1330 * return value */
1339 err = PTR_ERR(nentry); 1331 err = PTR_ERR(nentry);
1340 audit_panic("error updating LSM filters"); 1332 audit_panic("error updating LSM filters");
1341 if (watch) 1333 if (r->watch)
1342 list_del(&r->rlist); 1334 list_del(&r->rlist);
1343 list_del_rcu(&entry->list); 1335 list_del_rcu(&entry->list);
1344 list_del(&r->list); 1336 list_del(&r->list);
1345 } else { 1337 } else {
1346 if (watch) { 1338 if (r->watch || r->tree)
1347 list_add(&nentry->rule.rlist, audit_watch_rules(watch));
1348 list_del(&r->rlist);
1349 } else if (tree)
1350 list_replace_init(&r->rlist, &nentry->rule.rlist); 1339 list_replace_init(&r->rlist, &nentry->rule.rlist);
1351 list_replace_rcu(&entry->list, &nentry->list); 1340 list_replace_rcu(&entry->list, &nentry->list);
1352 list_replace(&r->list, &nentry->rule.list); 1341 list_replace(&r->list, &nentry->rule.list);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 3828ad5fb8f1..240063c370e6 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -549,9 +549,8 @@ static int audit_filter_rules(struct task_struct *tsk,
549 } 549 }
550 break; 550 break;
551 case AUDIT_WATCH: 551 case AUDIT_WATCH:
552 if (name && audit_watch_inode(rule->watch) != (unsigned long)-1) 552 if (name)
553 result = (name->dev == audit_watch_dev(rule->watch) && 553 result = audit_watch_compare(rule->watch, name->ino, name->dev);
554 name->ino == audit_watch_inode(rule->watch));
555 break; 554 break;
556 case AUDIT_DIR: 555 case AUDIT_DIR:
557 if (ctx) 556 if (ctx)