Skip to content

Commit ae7b8f4

Browse files
committed
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>
1 parent b7ba837 commit ae7b8f4

File tree

5 files changed

+60
-67
lines changed

5 files changed

+60
-67
lines changed

kernel/audit.c

-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
#include <net/netlink.h>
5757
#include <linux/skbuff.h>
5858
#include <linux/netlink.h>
59-
#include <linux/inotify.h>
6059
#include <linux/freezer.h>
6160
#include <linux/tty.h>
6261

kernel/audit.h

+4-9
Original file line numberDiff line numberDiff line change
@@ -104,20 +104,15 @@ extern void audit_free_rule_rcu(struct rcu_head *);
104104
extern struct list_head audit_filter_list[];
105105

106106
/* audit watch functions */
107-
extern unsigned long audit_watch_inode(struct audit_watch *watch);
108-
extern dev_t audit_watch_dev(struct audit_watch *watch);
109107
extern void audit_put_watch(struct audit_watch *watch);
110108
extern void audit_get_watch(struct audit_watch *watch);
111109
extern int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op);
112-
extern int audit_add_watch(struct audit_krule *krule);
113-
extern void audit_remove_watch(struct audit_watch *watch);
110+
extern int audit_add_watch(struct audit_krule *krule, struct list_head **list);
114111
extern void audit_remove_watch_rule(struct audit_krule *krule, struct list_head *list);
115-
extern void audit_inotify_unregister(struct list_head *in_list);
112+
extern void audit_watch_inotify_unregister(struct list_head *in_list);
116113
extern char *audit_watch_path(struct audit_watch *watch);
117-
extern struct list_head *audit_watch_rules(struct audit_watch *watch);
118-
119-
extern struct audit_entry *audit_dupe_rule(struct audit_krule *old,
120-
struct audit_watch *watch);
114+
extern int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev);
115+
extern struct audit_entry *audit_dupe_rule(struct audit_krule *old);
121116

122117
#ifdef CONFIG_AUDIT_TREE
123118
extern struct audit_chunk *audit_tree_lookup(const struct inode *);

kernel/audit_watch.c

+39-28
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,12 @@ struct audit_watch {
5151
unsigned long ino; /* associated inode number */
5252
struct audit_parent *parent; /* associated parent */
5353
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 */
5555
};
5656

5757
struct audit_parent {
58-
struct list_head ilist; /* entry in inotify registration list */
59-
struct list_head watches; /* associated watches */
58+
struct list_head ilist; /* tmp list used to free parents */
59+
struct list_head watches; /* anchor for audit_watch->wlist */
6060
struct inotify_watch wdata; /* inotify watch data */
6161
unsigned flags; /* status flags */
6262
};
@@ -78,13 +78,18 @@ struct inotify_handle *audit_ih;
7878
/* Inotify events we care about. */
7979
#define AUDIT_IN_WATCH IN_MOVE|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELF
8080

81-
static void audit_free_parent(struct inotify_watch *i_watch)
81+
static void audit_free_parent(struct audit_parent *parent)
82+
{
83+
WARN_ON(!list_empty(&parent->watches));
84+
kfree(parent);
85+
}
86+
87+
static void audit_destroy_watch(struct inotify_watch *i_watch)
8288
{
8389
struct audit_parent *parent;
8490

8591
parent = container_of(i_watch, struct audit_parent, wdata);
86-
WARN_ON(!list_empty(&parent->watches));
87-
kfree(parent);
92+
audit_free_parent(parent);
8893
}
8994

9095
void audit_get_watch(struct audit_watch *watch)
@@ -115,19 +120,11 @@ char *audit_watch_path(struct audit_watch *watch)
115120
return watch->path;
116121
}
117122

118-
struct list_head *audit_watch_rules(struct audit_watch *watch)
123+
int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
119124
{
120-
return &watch->rules;
121-
}
122-
123-
unsigned long audit_watch_inode(struct audit_watch *watch)
124-
{
125-
return watch->ino;
126-
}
127-
128-
dev_t audit_watch_dev(struct audit_watch *watch)
129-
{
130-
return watch->dev;
125+
return (watch->ino != (unsigned long)-1) &&
126+
(watch->ino == ino) &&
127+
(watch->dev == dev);
131128
}
132129

133130
/* Initialize a parent watch entry. */
@@ -149,7 +146,7 @@ static struct audit_parent *audit_init_parent(struct nameidata *ndp)
149146
wd = inotify_add_watch(audit_ih, &parent->wdata,
150147
ndp->path.dentry->d_inode, AUDIT_IN_WATCH);
151148
if (wd < 0) {
152-
audit_free_parent(&parent->wdata);
149+
audit_free_parent(parent);
153150
return ERR_PTR(wd);
154151
}
155152

@@ -251,15 +248,19 @@ static void audit_update_watch(struct audit_parent *parent,
251248
struct audit_entry *oentry, *nentry;
252249

253250
mutex_lock(&audit_filter_mutex);
251+
/* Run all of the watches on this parent looking for the one that
252+
* matches the given dname */
254253
list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
255254
if (audit_compare_dname_path(dname, owatch->path, NULL))
256255
continue;
257256

258257
/* If the update involves invalidating rules, do the inode-based
259258
* filtering now, so we don't omit records. */
260-
if (invalidating && current->audit_context)
259+
if (invalidating && !audit_dummy_context())
261260
audit_filter_inodes(current, current->audit_context);
262261

262+
/* updating ino will likely change which audit_hash_list we
263+
* are on so we need a new watch for the new list */
263264
nwatch = audit_dupe_watch(owatch);
264265
if (IS_ERR(nwatch)) {
265266
mutex_unlock(&audit_filter_mutex);
@@ -275,12 +276,21 @@ static void audit_update_watch(struct audit_parent *parent,
275276
list_del(&oentry->rule.rlist);
276277
list_del_rcu(&oentry->list);
277278

278-
nentry = audit_dupe_rule(&oentry->rule, nwatch);
279+
nentry = audit_dupe_rule(&oentry->rule);
279280
if (IS_ERR(nentry)) {
280281
list_del(&oentry->rule.list);
281282
audit_panic("error updating watch, removing");
282283
} else {
283284
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;
284294
list_add(&nentry->rule.rlist, &nwatch->rules);
285295
list_add_rcu(&nentry->list, &audit_inode_hash[h]);
286296
list_replace(&oentry->rule.list,
@@ -329,14 +339,14 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
329339

330340
/* Unregister inotify watches for parents on in_list.
331341
* Generates an IN_IGNORED event. */
332-
void audit_inotify_unregister(struct list_head *in_list)
342+
void audit_watch_inotify_unregister(struct list_head *in_list)
333343
{
334344
struct audit_parent *p, *n;
335345

336346
list_for_each_entry_safe(p, n, in_list, ilist) {
337347
list_del(&p->ilist);
338348
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() */
340350
unpin_inotify_watch(&p->wdata);
341351
}
342352
}
@@ -423,13 +433,13 @@ static void audit_add_to_parent(struct audit_krule *krule,
423433

424434
/* Find a matching watch entry, or add this one.
425435
* Caller must hold audit_filter_mutex. */
426-
int audit_add_watch(struct audit_krule *krule)
436+
int audit_add_watch(struct audit_krule *krule, struct list_head **list)
427437
{
428438
struct audit_watch *watch = krule->watch;
429439
struct inotify_watch *i_watch;
430440
struct audit_parent *parent;
431441
struct nameidata *ndp = NULL, *ndw = NULL;
432-
int ret = 0;
442+
int h, ret = 0;
433443

434444
mutex_unlock(&audit_filter_mutex);
435445

@@ -475,6 +485,8 @@ int audit_add_watch(struct audit_krule *krule)
475485
/* match get in audit_init_parent or inotify_find_watch */
476486
put_inotify_watch(&parent->wdata);
477487

488+
h = audit_hash_ino((u32)watch->ino);
489+
*list = &audit_inode_hash[h];
478490
error:
479491
audit_put_nd(ndp, ndw); /* NULL args OK */
480492
return ret;
@@ -514,8 +526,7 @@ static void audit_handle_ievent(struct inotify_watch *i_watch, u32 wd, u32 mask,
514526
parent = container_of(i_watch, struct audit_parent, wdata);
515527

516528
if (mask & (IN_CREATE|IN_MOVED_TO) && inode)
517-
audit_update_watch(parent, dname, inode->i_sb->s_dev,
518-
inode->i_ino, 0);
529+
audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0);
519530
else if (mask & (IN_DELETE|IN_MOVED_FROM))
520531
audit_update_watch(parent, dname, (dev_t)-1, (unsigned long)-1, 1);
521532
/* 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,
531542

532543
static const struct inotify_operations audit_inotify_ops = {
533544
.handle_event = audit_handle_ievent,
534-
.destroy_watch = audit_free_parent,
545+
.destroy_watch = audit_destroy_watch,
535546
};
536547

537548
static int __init audit_watch_init(void)

kernel/auditfilter.c

+15-26
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ static inline void audit_free_rule(struct audit_entry *e)
7171
{
7272
int i;
7373
struct audit_krule *erule = &e->rule;
74+
7475
/* some rules don't have associated watches */
7576
if (erule->watch)
7677
audit_put_watch(erule->watch);
@@ -746,8 +747,7 @@ static inline int audit_dupe_lsm_field(struct audit_field *df,
746747
* rule with the new rule in the filterlist, then free the old rule.
747748
* The rlist element is undefined; list manipulations are handled apart from
748749
* the initial copy. */
749-
struct audit_entry *audit_dupe_rule(struct audit_krule *old,
750-
struct audit_watch *watch)
750+
struct audit_entry *audit_dupe_rule(struct audit_krule *old)
751751
{
752752
u32 fcount = old->field_count;
753753
struct audit_entry *entry;
@@ -769,8 +769,8 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old,
769769
new->prio = old->prio;
770770
new->buflen = old->buflen;
771771
new->inode_f = old->inode_f;
772-
new->watch = NULL;
773772
new->field_count = old->field_count;
773+
774774
/*
775775
* note that we are OK with not refcounting here; audit_match_tree()
776776
* 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,
811811
}
812812
}
813813

814-
if (watch) {
815-
audit_get_watch(watch);
816-
new->watch = watch;
814+
if (old->watch) {
815+
audit_get_watch(old->watch);
816+
new->watch = old->watch;
817817
}
818818

819819
return entry;
@@ -866,7 +866,7 @@ static inline int audit_add_rule(struct audit_entry *entry)
866866
struct audit_watch *watch = entry->rule.watch;
867867
struct audit_tree *tree = entry->rule.tree;
868868
struct list_head *list;
869-
int h, err;
869+
int err;
870870
#ifdef CONFIG_AUDITSYSCALL
871871
int dont_count = 0;
872872

@@ -889,15 +889,11 @@ static inline int audit_add_rule(struct audit_entry *entry)
889889

890890
if (watch) {
891891
/* 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);
893893
if (err) {
894894
mutex_unlock(&audit_filter_mutex);
895895
goto error;
896896
}
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];
901897
}
902898
if (tree) {
903899
err = audit_add_tree_rule(&entry->rule);
@@ -949,7 +945,7 @@ static inline int audit_del_rule(struct audit_entry *entry)
949945
struct audit_watch *watch = entry->rule.watch;
950946
struct audit_tree *tree = entry->rule.tree;
951947
struct list_head *list;
952-
LIST_HEAD(inotify_list);
948+
LIST_HEAD(inotify_unregister_list);
953949
int ret = 0;
954950
#ifdef CONFIG_AUDITSYSCALL
955951
int dont_count = 0;
@@ -969,7 +965,7 @@ static inline int audit_del_rule(struct audit_entry *entry)
969965
}
970966

971967
if (e->rule.watch)
972-
audit_remove_watch_rule(&e->rule, &inotify_list);
968+
audit_remove_watch_rule(&e->rule, &inotify_unregister_list);
973969

974970
if (e->rule.tree)
975971
audit_remove_tree_rule(&e->rule);
@@ -987,8 +983,8 @@ static inline int audit_del_rule(struct audit_entry *entry)
987983
#endif
988984
mutex_unlock(&audit_filter_mutex);
989985

990-
if (!list_empty(&inotify_list))
991-
audit_inotify_unregister(&inotify_list);
986+
if (!list_empty(&inotify_unregister_list))
987+
audit_watch_inotify_unregister(&inotify_unregister_list);
992988

993989
out:
994990
if (watch)
@@ -1323,30 +1319,23 @@ static int update_lsm_rule(struct audit_krule *r)
13231319
{
13241320
struct audit_entry *entry = container_of(r, struct audit_entry, rule);
13251321
struct audit_entry *nentry;
1326-
struct audit_watch *watch;
1327-
struct audit_tree *tree;
13281322
int err = 0;
13291323

13301324
if (!security_audit_rule_known(r))
13311325
return 0;
13321326

1333-
watch = r->watch;
1334-
tree = r->tree;
1335-
nentry = audit_dupe_rule(r, watch);
1327+
nentry = audit_dupe_rule(r);
13361328
if (IS_ERR(nentry)) {
13371329
/* save the first error encountered for the
13381330
* return value */
13391331
err = PTR_ERR(nentry);
13401332
audit_panic("error updating LSM filters");
1341-
if (watch)
1333+
if (r->watch)
13421334
list_del(&r->rlist);
13431335
list_del_rcu(&entry->list);
13441336
list_del(&r->list);
13451337
} else {
1346-
if (watch) {
1347-
list_add(&nentry->rule.rlist, audit_watch_rules(watch));
1348-
list_del(&r->rlist);
1349-
} else if (tree)
1338+
if (r->watch || r->tree)
13501339
list_replace_init(&r->rlist, &nentry->rule.rlist);
13511340
list_replace_rcu(&entry->list, &nentry->list);
13521341
list_replace(&r->list, &nentry->rule.list);

kernel/auditsc.c

+2-3
Original file line numberDiff line numberDiff line change
@@ -549,9 +549,8 @@ static int audit_filter_rules(struct task_struct *tsk,
549549
}
550550
break;
551551
case AUDIT_WATCH:
552-
if (name && audit_watch_inode(rule->watch) != (unsigned long)-1)
553-
result = (name->dev == audit_watch_dev(rule->watch) &&
554-
name->ino == audit_watch_inode(rule->watch));
552+
if (name)
553+
result = audit_watch_compare(rule->watch, name->ino, name->dev);
555554
break;
556555
case AUDIT_DIR:
557556
if (ctx)

0 commit comments

Comments
 (0)