aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/audit.h5
-rw-r--r--kernel/audit_watch.c27
-rw-r--r--kernel/auditfilter.c15
3 files changed, 23 insertions, 24 deletions
diff --git a/kernel/audit.h b/kernel/audit.h
index 704d5b01d9fd..bb1c0d69db08 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -109,10 +109,7 @@ extern dev_t audit_watch_dev(struct audit_watch *watch);
109extern void audit_put_watch(struct audit_watch *watch); 109extern void audit_put_watch(struct audit_watch *watch);
110extern void audit_get_watch(struct audit_watch *watch); 110extern void audit_get_watch(struct audit_watch *watch);
111extern int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op); 111extern int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op);
112extern int audit_get_nd(char *path, struct nameidata **ndp, struct nameidata **ndw); 112extern int audit_add_watch(struct audit_krule *krule);
113extern void audit_put_nd(struct nameidata *ndp, struct nameidata *ndw);
114extern int audit_add_watch(struct audit_krule *krule, struct nameidata *ndp,
115 struct nameidata *ndw);
116extern void audit_remove_watch(struct audit_watch *watch); 113extern void audit_remove_watch(struct audit_watch *watch);
117extern void audit_remove_watch_rule(struct audit_krule *krule, struct list_head *list); 114extern void audit_remove_watch_rule(struct audit_krule *krule, struct list_head *list);
118extern void audit_inotify_unregister(struct list_head *in_list); 115extern void audit_inotify_unregister(struct list_head *in_list);
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index da8be6d39c1a..b49ab019fdff 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -345,7 +345,7 @@ void audit_inotify_unregister(struct list_head *in_list)
345} 345}
346 346
347/* Get path information necessary for adding watches. */ 347/* Get path information necessary for adding watches. */
348int audit_get_nd(char *path, struct nameidata **ndp, struct nameidata **ndw) 348static int audit_get_nd(char *path, struct nameidata **ndp, struct nameidata **ndw)
349{ 349{
350 struct nameidata *ndparent, *ndwatch; 350 struct nameidata *ndparent, *ndwatch;
351 int err; 351 int err;
@@ -380,7 +380,7 @@ int audit_get_nd(char *path, struct nameidata **ndp, struct nameidata **ndw)
380} 380}
381 381
382/* Release resources used for watch path information. */ 382/* Release resources used for watch path information. */
383void audit_put_nd(struct nameidata *ndp, struct nameidata *ndw) 383static void audit_put_nd(struct nameidata *ndp, struct nameidata *ndw)
384{ 384{
385 if (ndp) { 385 if (ndp) {
386 path_put(&ndp->path); 386 path_put(&ndp->path);
@@ -426,14 +426,24 @@ static void audit_add_to_parent(struct audit_krule *krule,
426 426
427/* Find a matching watch entry, or add this one. 427/* Find a matching watch entry, or add this one.
428 * Caller must hold audit_filter_mutex. */ 428 * Caller must hold audit_filter_mutex. */
429int audit_add_watch(struct audit_krule *krule, struct nameidata *ndp, 429int audit_add_watch(struct audit_krule *krule)
430 struct nameidata *ndw)
431{ 430{
432 struct audit_watch *watch = krule->watch; 431 struct audit_watch *watch = krule->watch;
433 struct inotify_watch *i_watch; 432 struct inotify_watch *i_watch;
434 struct audit_parent *parent; 433 struct audit_parent *parent;
434 struct nameidata *ndp = NULL, *ndw = NULL;
435 int ret = 0; 435 int ret = 0;
436 436
437 mutex_unlock(&audit_filter_mutex);
438
439 /* Avoid calling path_lookup under audit_filter_mutex. */
440 ret = audit_get_nd(watch->path, &ndp, &ndw);
441 if (ret) {
442 /* caller expects mutex locked */
443 mutex_lock(&audit_filter_mutex);
444 goto error;
445 }
446
437 /* update watch filter fields */ 447 /* update watch filter fields */
438 if (ndw) { 448 if (ndw) {
439 watch->dev = ndw->path.dentry->d_inode->i_sb->s_dev; 449 watch->dev = ndw->path.dentry->d_inode->i_sb->s_dev;
@@ -445,15 +455,14 @@ int audit_add_watch(struct audit_krule *krule, struct nameidata *ndp,
445 * inotify watch is found, inotify_find_watch() grabs a reference before 455 * inotify watch is found, inotify_find_watch() grabs a reference before
446 * returning. 456 * returning.
447 */ 457 */
448 mutex_unlock(&audit_filter_mutex);
449
450 if (inotify_find_watch(audit_ih, ndp->path.dentry->d_inode, 458 if (inotify_find_watch(audit_ih, ndp->path.dentry->d_inode,
451 &i_watch) < 0) { 459 &i_watch) < 0) {
452 parent = audit_init_parent(ndp); 460 parent = audit_init_parent(ndp);
453 if (IS_ERR(parent)) { 461 if (IS_ERR(parent)) {
454 /* caller expects mutex locked */ 462 /* caller expects mutex locked */
455 mutex_lock(&audit_filter_mutex); 463 mutex_lock(&audit_filter_mutex);
456 return PTR_ERR(parent); 464 ret = PTR_ERR(parent);
465 goto error;
457 } 466 }
458 } else 467 } else
459 parent = container_of(i_watch, struct audit_parent, wdata); 468 parent = container_of(i_watch, struct audit_parent, wdata);
@@ -468,7 +477,11 @@ int audit_add_watch(struct audit_krule *krule, struct nameidata *ndp,
468 477
469 /* match get in audit_init_parent or inotify_find_watch */ 478 /* match get in audit_init_parent or inotify_find_watch */
470 put_inotify_watch(&parent->wdata); 479 put_inotify_watch(&parent->wdata);
480
481error:
482 audit_put_nd(ndp, ndw); /* NULL args OK */
471 return ret; 483 return ret;
484
472} 485}
473 486
474void audit_remove_watch_rule(struct audit_krule *krule, struct list_head *list) 487void audit_remove_watch_rule(struct audit_krule *krule, struct list_head *list)
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 9d4c93437de6..21b623595aad 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -864,7 +864,6 @@ static inline int audit_add_rule(struct audit_entry *entry)
864 struct audit_entry *e; 864 struct audit_entry *e;
865 struct audit_watch *watch = entry->rule.watch; 865 struct audit_watch *watch = entry->rule.watch;
866 struct audit_tree *tree = entry->rule.tree; 866 struct audit_tree *tree = entry->rule.tree;
867 struct nameidata *ndp = NULL, *ndw = NULL;
868 struct list_head *list; 867 struct list_head *list;
869 int h, err; 868 int h, err;
870#ifdef CONFIG_AUDITSYSCALL 869#ifdef CONFIG_AUDITSYSCALL
@@ -878,8 +877,8 @@ static inline int audit_add_rule(struct audit_entry *entry)
878 877
879 mutex_lock(&audit_filter_mutex); 878 mutex_lock(&audit_filter_mutex);
880 e = audit_find_rule(entry, &list); 879 e = audit_find_rule(entry, &list);
881 mutex_unlock(&audit_filter_mutex);
882 if (e) { 880 if (e) {
881 mutex_unlock(&audit_filter_mutex);
883 err = -EEXIST; 882 err = -EEXIST;
884 /* normally audit_add_tree_rule() will free it on failure */ 883 /* normally audit_add_tree_rule() will free it on failure */
885 if (tree) 884 if (tree)
@@ -887,17 +886,9 @@ static inline int audit_add_rule(struct audit_entry *entry)
887 goto error; 886 goto error;
888 } 887 }
889 888
890 /* Avoid calling path_lookup under audit_filter_mutex. */
891 if (watch) {
892 err = audit_get_nd(audit_watch_path(watch), &ndp, &ndw);
893 if (err)
894 goto error;
895 }
896
897 mutex_lock(&audit_filter_mutex);
898 if (watch) { 889 if (watch) {
899 /* audit_filter_mutex is dropped and re-taken during this call */ 890 /* audit_filter_mutex is dropped and re-taken during this call */
900 err = audit_add_watch(&entry->rule, ndp, ndw); 891 err = audit_add_watch(&entry->rule);
901 if (err) { 892 if (err) {
902 mutex_unlock(&audit_filter_mutex); 893 mutex_unlock(&audit_filter_mutex);
903 goto error; 894 goto error;
@@ -942,11 +933,9 @@ static inline int audit_add_rule(struct audit_entry *entry)
942#endif 933#endif
943 mutex_unlock(&audit_filter_mutex); 934 mutex_unlock(&audit_filter_mutex);
944 935
945 audit_put_nd(ndp, ndw); /* NULL args OK */
946 return 0; 936 return 0;
947 937
948error: 938error:
949 audit_put_nd(ndp, ndw); /* NULL args OK */
950 if (watch) 939 if (watch)
951 audit_put_watch(watch); /* tmp watch, matches initial get */ 940 audit_put_watch(watch); /* tmp watch, matches initial get */
952 return err; 941 return err;