11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2cfcad62cSEric Paris /* audit_watch.c -- watching inodes
3cfcad62cSEric Paris *
4cfcad62cSEric Paris * Copyright 2003-2009 Red Hat, Inc.
5cfcad62cSEric Paris * Copyright 2005 Hewlett-Packard Development Company, L.P.
6cfcad62cSEric Paris * Copyright 2005 IBM Corporation
7cfcad62cSEric Paris */
8cfcad62cSEric Paris
95efc2443SMateusz Guzik #include <linux/file.h>
10cfcad62cSEric Paris #include <linux/kernel.h>
11cfcad62cSEric Paris #include <linux/audit.h>
12cfcad62cSEric Paris #include <linux/kthread.h>
13cfcad62cSEric Paris #include <linux/mutex.h>
14cfcad62cSEric Paris #include <linux/fs.h>
15e9fd702aSEric Paris #include <linux/fsnotify_backend.h>
16cfcad62cSEric Paris #include <linux/namei.h>
17cfcad62cSEric Paris #include <linux/netlink.h>
18bd120dedSElena Reshetova #include <linux/refcount.h>
19cfcad62cSEric Paris #include <linux/sched.h>
205a0e3ad6STejun Heo #include <linux/slab.h>
21cfcad62cSEric Paris #include <linux/security.h>
22cfcad62cSEric Paris #include "audit.h"
23cfcad62cSEric Paris
24cfcad62cSEric Paris /*
25cfcad62cSEric Paris * Reference counting:
26cfcad62cSEric Paris *
27e9fd702aSEric Paris * audit_parent: lifetime is from audit_init_parent() to receipt of an FS_IGNORED
28cfcad62cSEric Paris * event. Each audit_watch holds a reference to its associated parent.
29cfcad62cSEric Paris *
30cfcad62cSEric Paris * audit_watch: if added to lists, lifetime is from audit_init_watch() to
31cfcad62cSEric Paris * audit_remove_watch(). Additionally, an audit_watch may exist
32cfcad62cSEric Paris * temporarily to assist in searching existing filter data. Each
33cfcad62cSEric Paris * audit_krule holds a reference to its associated watch.
34cfcad62cSEric Paris */
35cfcad62cSEric Paris
36cfcad62cSEric Paris struct audit_watch {
37bd120dedSElena Reshetova refcount_t count; /* reference count */
38cfcad62cSEric Paris dev_t dev; /* associated superblock device */
39e08b061eSEric Paris char *path; /* insertion path */
40cfcad62cSEric Paris unsigned long ino; /* associated inode number */
41cfcad62cSEric Paris struct audit_parent *parent; /* associated parent */
42cfcad62cSEric Paris struct list_head wlist; /* entry in parent->watches list */
43ae7b8f41SEric Paris struct list_head rules; /* anchor for krule->rlist */
44cfcad62cSEric Paris };
45cfcad62cSEric Paris
46cfcad62cSEric Paris struct audit_parent {
47ae7b8f41SEric Paris struct list_head watches; /* anchor for audit_watch->wlist */
48e61ce867SEric Paris struct fsnotify_mark mark; /* fsnotify mark on the inode */
49cfcad62cSEric Paris };
50cfcad62cSEric Paris
51e9fd702aSEric Paris /* fsnotify handle. */
52b8800aa5SStephen Hemminger static struct fsnotify_group *audit_watch_group;
53cfcad62cSEric Paris
54e9fd702aSEric Paris /* fsnotify events we care about. */
55e9fd702aSEric Paris #define AUDIT_FS_WATCH (FS_MOVE | FS_CREATE | FS_DELETE | FS_DELETE_SELF |\
567dbe6080SAmir Goldstein FS_MOVE_SELF | FS_UNMOUNT)
57cfcad62cSEric Paris
audit_free_parent(struct audit_parent * parent)58ae7b8f41SEric Paris static void audit_free_parent(struct audit_parent *parent)
59ae7b8f41SEric Paris {
60ae7b8f41SEric Paris WARN_ON(!list_empty(&parent->watches));
61ae7b8f41SEric Paris kfree(parent);
62ae7b8f41SEric Paris }
63ae7b8f41SEric Paris
audit_watch_free_mark(struct fsnotify_mark * entry)64e61ce867SEric Paris static void audit_watch_free_mark(struct fsnotify_mark *entry)
65cfcad62cSEric Paris {
66cfcad62cSEric Paris struct audit_parent *parent;
67cfcad62cSEric Paris
68e9fd702aSEric Paris parent = container_of(entry, struct audit_parent, mark);
69ae7b8f41SEric Paris audit_free_parent(parent);
70cfcad62cSEric Paris }
71cfcad62cSEric Paris
audit_get_parent(struct audit_parent * parent)72e9fd702aSEric Paris static void audit_get_parent(struct audit_parent *parent)
73e9fd702aSEric Paris {
74e9fd702aSEric Paris if (likely(parent))
75e9fd702aSEric Paris fsnotify_get_mark(&parent->mark);
76e9fd702aSEric Paris }
77e9fd702aSEric Paris
audit_put_parent(struct audit_parent * parent)78e9fd702aSEric Paris static void audit_put_parent(struct audit_parent *parent)
79e9fd702aSEric Paris {
80e9fd702aSEric Paris if (likely(parent))
81e9fd702aSEric Paris fsnotify_put_mark(&parent->mark);
82e9fd702aSEric Paris }
83e9fd702aSEric Paris
84e9fd702aSEric Paris /*
85e9fd702aSEric Paris * Find and return the audit_parent on the given inode. If found a reference
86e9fd702aSEric Paris * is taken on this parent.
87e9fd702aSEric Paris */
audit_find_parent(struct inode * inode)88e9fd702aSEric Paris static inline struct audit_parent *audit_find_parent(struct inode *inode)
89e9fd702aSEric Paris {
90e9fd702aSEric Paris struct audit_parent *parent = NULL;
91e61ce867SEric Paris struct fsnotify_mark *entry;
92e9fd702aSEric Paris
93230d97d3SAmir Goldstein entry = fsnotify_find_inode_mark(inode, audit_watch_group);
94e9fd702aSEric Paris if (entry)
95e9fd702aSEric Paris parent = container_of(entry, struct audit_parent, mark);
96e9fd702aSEric Paris
97e9fd702aSEric Paris return parent;
98e9fd702aSEric Paris }
99e9fd702aSEric Paris
audit_get_watch(struct audit_watch * watch)100cfcad62cSEric Paris void audit_get_watch(struct audit_watch *watch)
101cfcad62cSEric Paris {
102bd120dedSElena Reshetova refcount_inc(&watch->count);
103cfcad62cSEric Paris }
104cfcad62cSEric Paris
audit_put_watch(struct audit_watch * watch)105cfcad62cSEric Paris void audit_put_watch(struct audit_watch *watch)
106cfcad62cSEric Paris {
107bd120dedSElena Reshetova if (refcount_dec_and_test(&watch->count)) {
108cfcad62cSEric Paris WARN_ON(watch->parent);
109cfcad62cSEric Paris WARN_ON(!list_empty(&watch->rules));
110cfcad62cSEric Paris kfree(watch->path);
111cfcad62cSEric Paris kfree(watch);
112cfcad62cSEric Paris }
113cfcad62cSEric Paris }
114cfcad62cSEric Paris
audit_remove_watch(struct audit_watch * watch)115b8800aa5SStephen Hemminger static void audit_remove_watch(struct audit_watch *watch)
116cfcad62cSEric Paris {
117cfcad62cSEric Paris list_del(&watch->wlist);
118e9fd702aSEric Paris audit_put_parent(watch->parent);
119cfcad62cSEric Paris watch->parent = NULL;
120cfcad62cSEric Paris audit_put_watch(watch); /* match initial get */
121cfcad62cSEric Paris }
122cfcad62cSEric Paris
audit_watch_path(struct audit_watch * watch)123cfcad62cSEric Paris char *audit_watch_path(struct audit_watch *watch)
124cfcad62cSEric Paris {
125cfcad62cSEric Paris return watch->path;
126cfcad62cSEric Paris }
127cfcad62cSEric Paris
audit_watch_compare(struct audit_watch * watch,unsigned long ino,dev_t dev)128ae7b8f41SEric Paris int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
129cfcad62cSEric Paris {
13084cb777eSRichard Guy Briggs return (watch->ino != AUDIT_INO_UNSET) &&
131ae7b8f41SEric Paris (watch->ino == ino) &&
132ae7b8f41SEric Paris (watch->dev == dev);
133cfcad62cSEric Paris }
134cfcad62cSEric Paris
135cfcad62cSEric Paris /* Initialize a parent watch entry. */
audit_init_parent(const struct path * path)136bf2e1ae4SAl Viro static struct audit_parent *audit_init_parent(const struct path *path)
137cfcad62cSEric Paris {
1383b362157SDavid Howells struct inode *inode = d_backing_inode(path->dentry);
139cfcad62cSEric Paris struct audit_parent *parent;
140e9fd702aSEric Paris int ret;
141cfcad62cSEric Paris
142cfcad62cSEric Paris parent = kzalloc(sizeof(*parent), GFP_KERNEL);
143cfcad62cSEric Paris if (unlikely(!parent))
144cfcad62cSEric Paris return ERR_PTR(-ENOMEM);
145cfcad62cSEric Paris
146cfcad62cSEric Paris INIT_LIST_HEAD(&parent->watches);
147cfcad62cSEric Paris
148054c636eSJan Kara fsnotify_init_mark(&parent->mark, audit_watch_group);
149e9fd702aSEric Paris parent->mark.mask = AUDIT_FS_WATCH;
150b249f5beSAmir Goldstein ret = fsnotify_add_inode_mark(&parent->mark, inode, 0);
151e9fd702aSEric Paris if (ret < 0) {
152ae7b8f41SEric Paris audit_free_parent(parent);
153e9fd702aSEric Paris return ERR_PTR(ret);
154cfcad62cSEric Paris }
155cfcad62cSEric Paris
156cfcad62cSEric Paris return parent;
157cfcad62cSEric Paris }
158cfcad62cSEric Paris
159cfcad62cSEric Paris /* Initialize a watch entry. */
audit_init_watch(char * path)160cfcad62cSEric Paris static struct audit_watch *audit_init_watch(char *path)
161cfcad62cSEric Paris {
162cfcad62cSEric Paris struct audit_watch *watch;
163cfcad62cSEric Paris
164cfcad62cSEric Paris watch = kzalloc(sizeof(*watch), GFP_KERNEL);
165cfcad62cSEric Paris if (unlikely(!watch))
166cfcad62cSEric Paris return ERR_PTR(-ENOMEM);
167cfcad62cSEric Paris
168cfcad62cSEric Paris INIT_LIST_HEAD(&watch->rules);
169bd120dedSElena Reshetova refcount_set(&watch->count, 1);
170cfcad62cSEric Paris watch->path = path;
17184cb777eSRichard Guy Briggs watch->dev = AUDIT_DEV_UNSET;
17284cb777eSRichard Guy Briggs watch->ino = AUDIT_INO_UNSET;
173cfcad62cSEric Paris
174cfcad62cSEric Paris return watch;
175cfcad62cSEric Paris }
176cfcad62cSEric Paris
177fd97646bSWei Yuan /* Translate a watch string to kernel representation. */
audit_to_watch(struct audit_krule * krule,char * path,int len,u32 op)178cfcad62cSEric Paris int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op)
179cfcad62cSEric Paris {
180cfcad62cSEric Paris struct audit_watch *watch;
181cfcad62cSEric Paris
182e9fd702aSEric Paris if (!audit_watch_group)
183cfcad62cSEric Paris return -EOPNOTSUPP;
184cfcad62cSEric Paris
185cfcad62cSEric Paris if (path[0] != '/' || path[len-1] == '/' ||
18667daf270SPaul Moore (krule->listnr != AUDIT_FILTER_EXIT &&
18767daf270SPaul Moore krule->listnr != AUDIT_FILTER_URING_EXIT) ||
188cfcad62cSEric Paris op != Audit_equal ||
189cfcad62cSEric Paris krule->inode_f || krule->watch || krule->tree)
190cfcad62cSEric Paris return -EINVAL;
191cfcad62cSEric Paris
192cfcad62cSEric Paris watch = audit_init_watch(path);
193cfcad62cSEric Paris if (IS_ERR(watch))
194cfcad62cSEric Paris return PTR_ERR(watch);
195cfcad62cSEric Paris
196cfcad62cSEric Paris krule->watch = watch;
197cfcad62cSEric Paris
198cfcad62cSEric Paris return 0;
199cfcad62cSEric Paris }
200cfcad62cSEric Paris
201cfcad62cSEric Paris /* Duplicate the given audit watch. The new watch's rules list is initialized
202cfcad62cSEric Paris * to an empty list and wlist is undefined. */
audit_dupe_watch(struct audit_watch * old)203cfcad62cSEric Paris static struct audit_watch *audit_dupe_watch(struct audit_watch *old)
204cfcad62cSEric Paris {
205cfcad62cSEric Paris char *path;
206cfcad62cSEric Paris struct audit_watch *new;
207cfcad62cSEric Paris
208cfcad62cSEric Paris path = kstrdup(old->path, GFP_KERNEL);
209cfcad62cSEric Paris if (unlikely(!path))
210cfcad62cSEric Paris return ERR_PTR(-ENOMEM);
211cfcad62cSEric Paris
212cfcad62cSEric Paris new = audit_init_watch(path);
213cfcad62cSEric Paris if (IS_ERR(new)) {
214cfcad62cSEric Paris kfree(path);
215cfcad62cSEric Paris goto out;
216cfcad62cSEric Paris }
217cfcad62cSEric Paris
218cfcad62cSEric Paris new->dev = old->dev;
219cfcad62cSEric Paris new->ino = old->ino;
220e9fd702aSEric Paris audit_get_parent(old->parent);
221cfcad62cSEric Paris new->parent = old->parent;
222cfcad62cSEric Paris
223cfcad62cSEric Paris out:
224cfcad62cSEric Paris return new;
225cfcad62cSEric Paris }
226cfcad62cSEric Paris
audit_watch_log_rule_change(struct audit_krule * r,struct audit_watch * w,char * op)227cfcad62cSEric Paris static void audit_watch_log_rule_change(struct audit_krule *r, struct audit_watch *w, char *op)
228cfcad62cSEric Paris {
229cfcad62cSEric Paris struct audit_buffer *ab;
2304fa7f086SRichard Guy Briggs
2314fa7f086SRichard Guy Briggs if (!audit_enabled)
2324fa7f086SRichard Guy Briggs return;
233626abcd1SRichard Guy Briggs ab = audit_log_start(audit_context(), GFP_NOFS, AUDIT_CONFIG_CHANGE);
2344fa7f086SRichard Guy Briggs if (!ab)
2350644ec0cSKees Cook return;
236a2c97da1SRichard Guy Briggs audit_log_session_info(ab);
237d0a3f18aSPaul Moore audit_log_format(ab, "op=%s path=", op);
238cfcad62cSEric Paris audit_log_untrustedstring(ab, w->path);
2399d960985SEric Paris audit_log_key(ab, r->filterkey);
240cfcad62cSEric Paris audit_log_format(ab, " list=%d res=1", r->listnr);
241cfcad62cSEric Paris audit_log_end(ab);
242cfcad62cSEric Paris }
243cfcad62cSEric Paris
244cfcad62cSEric Paris /* Update inode info in audit rules based on filesystem event. */
audit_update_watch(struct audit_parent * parent,const struct qstr * dname,dev_t dev,unsigned long ino,unsigned invalidating)245cfcad62cSEric Paris static void audit_update_watch(struct audit_parent *parent,
2466921d4ebSAl Viro const struct qstr *dname, dev_t dev,
247cfcad62cSEric Paris unsigned long ino, unsigned invalidating)
248cfcad62cSEric Paris {
249cfcad62cSEric Paris struct audit_watch *owatch, *nwatch, *nextw;
250cfcad62cSEric Paris struct audit_krule *r, *nextr;
251cfcad62cSEric Paris struct audit_entry *oentry, *nentry;
252cfcad62cSEric Paris
253cfcad62cSEric Paris mutex_lock(&audit_filter_mutex);
254ae7b8f41SEric Paris /* Run all of the watches on this parent looking for the one that
255ae7b8f41SEric Paris * matches the given dname */
256cfcad62cSEric Paris list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
257795d673aSAl Viro if (audit_compare_dname_path(dname, owatch->path,
258e3d6b07bSJeff Layton AUDIT_NAME_FULL))
259cfcad62cSEric Paris continue;
260cfcad62cSEric Paris
261cfcad62cSEric Paris /* If the update involves invalidating rules, do the inode-based
262cfcad62cSEric Paris * filtering now, so we don't omit records. */
263ae7b8f41SEric Paris if (invalidating && !audit_dummy_context())
264cdfb6b34SRichard Guy Briggs audit_filter_inodes(current, audit_context());
265cfcad62cSEric Paris
266ae7b8f41SEric Paris /* updating ino will likely change which audit_hash_list we
267ae7b8f41SEric Paris * are on so we need a new watch for the new list */
268cfcad62cSEric Paris nwatch = audit_dupe_watch(owatch);
269cfcad62cSEric Paris if (IS_ERR(nwatch)) {
270cfcad62cSEric Paris mutex_unlock(&audit_filter_mutex);
271cfcad62cSEric Paris audit_panic("error updating watch, skipping");
272cfcad62cSEric Paris return;
273cfcad62cSEric Paris }
274cfcad62cSEric Paris nwatch->dev = dev;
275cfcad62cSEric Paris nwatch->ino = ino;
276cfcad62cSEric Paris
277cfcad62cSEric Paris list_for_each_entry_safe(r, nextr, &owatch->rules, rlist) {
278cfcad62cSEric Paris
279cfcad62cSEric Paris oentry = container_of(r, struct audit_entry, rule);
280cfcad62cSEric Paris list_del(&oentry->rule.rlist);
281cfcad62cSEric Paris list_del_rcu(&oentry->list);
282cfcad62cSEric Paris
283ae7b8f41SEric Paris nentry = audit_dupe_rule(&oentry->rule);
284cfcad62cSEric Paris if (IS_ERR(nentry)) {
285cfcad62cSEric Paris list_del(&oentry->rule.list);
286cfcad62cSEric Paris audit_panic("error updating watch, removing");
287cfcad62cSEric Paris } else {
288cfcad62cSEric Paris int h = audit_hash_ino((u32)ino);
289ae7b8f41SEric Paris
290ae7b8f41SEric Paris /*
291ae7b8f41SEric Paris * nentry->rule.watch == oentry->rule.watch so
292ae7b8f41SEric Paris * we must drop that reference and set it to our
293ae7b8f41SEric Paris * new watch.
294ae7b8f41SEric Paris */
295ae7b8f41SEric Paris audit_put_watch(nentry->rule.watch);
296ae7b8f41SEric Paris audit_get_watch(nwatch);
297ae7b8f41SEric Paris nentry->rule.watch = nwatch;
298cfcad62cSEric Paris list_add(&nentry->rule.rlist, &nwatch->rules);
299cfcad62cSEric Paris list_add_rcu(&nentry->list, &audit_inode_hash[h]);
300cfcad62cSEric Paris list_replace(&oentry->rule.list,
301cfcad62cSEric Paris &nentry->rule.list);
302cfcad62cSEric Paris }
30334d99af5SRichard Guy Briggs if (oentry->rule.exe)
30434d99af5SRichard Guy Briggs audit_remove_mark(oentry->rule.exe);
305cfcad62cSEric Paris
306cfcad62cSEric Paris call_rcu(&oentry->rcu, audit_free_rule_rcu);
307cfcad62cSEric Paris }
308cfcad62cSEric Paris
309cfcad62cSEric Paris audit_remove_watch(owatch);
310cfcad62cSEric Paris goto add_watch_to_parent; /* event applies to a single watch */
311cfcad62cSEric Paris }
312cfcad62cSEric Paris mutex_unlock(&audit_filter_mutex);
313cfcad62cSEric Paris return;
314cfcad62cSEric Paris
315cfcad62cSEric Paris add_watch_to_parent:
316cfcad62cSEric Paris list_add(&nwatch->wlist, &parent->watches);
317cfcad62cSEric Paris mutex_unlock(&audit_filter_mutex);
318cfcad62cSEric Paris return;
319cfcad62cSEric Paris }
320cfcad62cSEric Paris
321cfcad62cSEric Paris /* Remove all watches & rules associated with a parent that is going away. */
audit_remove_parent_watches(struct audit_parent * parent)322cfcad62cSEric Paris static void audit_remove_parent_watches(struct audit_parent *parent)
323cfcad62cSEric Paris {
324cfcad62cSEric Paris struct audit_watch *w, *nextw;
325cfcad62cSEric Paris struct audit_krule *r, *nextr;
326cfcad62cSEric Paris struct audit_entry *e;
327cfcad62cSEric Paris
328cfcad62cSEric Paris mutex_lock(&audit_filter_mutex);
329cfcad62cSEric Paris list_for_each_entry_safe(w, nextw, &parent->watches, wlist) {
330cfcad62cSEric Paris list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
331cfcad62cSEric Paris e = container_of(r, struct audit_entry, rule);
332e7df61f4SBurn Alting audit_watch_log_rule_change(r, w, "remove_rule");
33334d99af5SRichard Guy Briggs if (e->rule.exe)
33434d99af5SRichard Guy Briggs audit_remove_mark(e->rule.exe);
335cfcad62cSEric Paris list_del(&r->rlist);
336cfcad62cSEric Paris list_del(&r->list);
337cfcad62cSEric Paris list_del_rcu(&e->list);
338cfcad62cSEric Paris call_rcu(&e->rcu, audit_free_rule_rcu);
339cfcad62cSEric Paris }
340cfcad62cSEric Paris audit_remove_watch(w);
341cfcad62cSEric Paris }
342cfcad62cSEric Paris mutex_unlock(&audit_filter_mutex);
343e9fd702aSEric Paris
344e2a29943SLino Sanfilippo fsnotify_destroy_mark(&parent->mark, audit_watch_group);
345cfcad62cSEric Paris }
346cfcad62cSEric Paris
347cfcad62cSEric Paris /* Get path information necessary for adding watches. */
audit_get_nd(struct audit_watch * watch,struct path * parent)34815a9155fSAl Viro static int audit_get_nd(struct audit_watch *watch, struct path *parent)
349cfcad62cSEric Paris {
350*c86b300bSChristian Brauner struct dentry *d;
351*c86b300bSChristian Brauner
352*c86b300bSChristian Brauner d = kern_path_locked_negative(watch->path, parent);
35379714f72SAl Viro if (IS_ERR(d))
35415a9155fSAl Viro return PTR_ERR(d);
355*c86b300bSChristian Brauner
356*c86b300bSChristian Brauner if (d_is_positive(d)) {
35715a9155fSAl Viro /* update watch filter fields */
358fc64005cSAl Viro watch->dev = d->d_sb->s_dev;
3593b362157SDavid Howells watch->ino = d_backing_inode(d)->i_ino;
360*c86b300bSChristian Brauner }
3611c3cb50bSNeilBrown
36269924b89SAl Viro inode_unlock(d_backing_inode(parent->dentry));
36315a9155fSAl Viro dput(d);
364cfcad62cSEric Paris return 0;
365cfcad62cSEric Paris }
366cfcad62cSEric Paris
367e9fd702aSEric Paris /* Associate the given rule with an existing parent.
368cfcad62cSEric Paris * Caller must hold audit_filter_mutex. */
audit_add_to_parent(struct audit_krule * krule,struct audit_parent * parent)369cfcad62cSEric Paris static void audit_add_to_parent(struct audit_krule *krule,
370cfcad62cSEric Paris struct audit_parent *parent)
371cfcad62cSEric Paris {
372cfcad62cSEric Paris struct audit_watch *w, *watch = krule->watch;
373cfcad62cSEric Paris int watch_found = 0;
374cfcad62cSEric Paris
375e9fd702aSEric Paris BUG_ON(!mutex_is_locked(&audit_filter_mutex));
376e9fd702aSEric Paris
377cfcad62cSEric Paris list_for_each_entry(w, &parent->watches, wlist) {
378cfcad62cSEric Paris if (strcmp(watch->path, w->path))
379cfcad62cSEric Paris continue;
380cfcad62cSEric Paris
381cfcad62cSEric Paris watch_found = 1;
382cfcad62cSEric Paris
383f8259b26SRichard Guy Briggs /* put krule's ref to temporary watch */
384cfcad62cSEric Paris audit_put_watch(watch);
385cfcad62cSEric Paris
386cfcad62cSEric Paris audit_get_watch(w);
387cfcad62cSEric Paris krule->watch = watch = w;
388aa7c043dSRichard Guy Briggs
389aa7c043dSRichard Guy Briggs audit_put_parent(parent);
390cfcad62cSEric Paris break;
391cfcad62cSEric Paris }
392cfcad62cSEric Paris
393cfcad62cSEric Paris if (!watch_found) {
394cfcad62cSEric Paris watch->parent = parent;
395cfcad62cSEric Paris
396f8259b26SRichard Guy Briggs audit_get_watch(watch);
397cfcad62cSEric Paris list_add(&watch->wlist, &parent->watches);
398cfcad62cSEric Paris }
399cfcad62cSEric Paris list_add(&krule->rlist, &watch->rules);
400cfcad62cSEric Paris }
401cfcad62cSEric Paris
402cfcad62cSEric Paris /* Find a matching watch entry, or add this one.
403cfcad62cSEric Paris * Caller must hold audit_filter_mutex. */
audit_add_watch(struct audit_krule * krule,struct list_head ** list)404ae7b8f41SEric Paris int audit_add_watch(struct audit_krule *krule, struct list_head **list)
405cfcad62cSEric Paris {
406cfcad62cSEric Paris struct audit_watch *watch = krule->watch;
407cfcad62cSEric Paris struct audit_parent *parent;
40815a9155fSAl Viro struct path parent_path;
409ae7b8f41SEric Paris int h, ret = 0;
410cfcad62cSEric Paris
411baa2a4fdSRonny Chevalier /*
412baa2a4fdSRonny Chevalier * When we will be calling audit_add_to_parent, krule->watch might have
413baa2a4fdSRonny Chevalier * been updated and watch might have been freed.
414baa2a4fdSRonny Chevalier * So we need to keep a reference of watch.
415baa2a4fdSRonny Chevalier */
416baa2a4fdSRonny Chevalier audit_get_watch(watch);
417baa2a4fdSRonny Chevalier
41835fe4d0bSEric Paris mutex_unlock(&audit_filter_mutex);
41935fe4d0bSEric Paris
42035fe4d0bSEric Paris /* Avoid calling path_lookup under audit_filter_mutex. */
42115a9155fSAl Viro ret = audit_get_nd(watch, &parent_path);
42215a9155fSAl Viro
42335fe4d0bSEric Paris /* caller expects mutex locked */
42435fe4d0bSEric Paris mutex_lock(&audit_filter_mutex);
42535fe4d0bSEric Paris
426*c86b300bSChristian Brauner if (ret) {
427baa2a4fdSRonny Chevalier audit_put_watch(watch);
42815a9155fSAl Viro return ret;
429baa2a4fdSRonny Chevalier }
430cfcad62cSEric Paris
431e118e9c5SEric Paris /* either find an old parent or attach a new one */
4323b362157SDavid Howells parent = audit_find_parent(d_backing_inode(parent_path.dentry));
433e9fd702aSEric Paris if (!parent) {
43415a9155fSAl Viro parent = audit_init_parent(&parent_path);
435cfcad62cSEric Paris if (IS_ERR(parent)) {
43635fe4d0bSEric Paris ret = PTR_ERR(parent);
43735fe4d0bSEric Paris goto error;
438cfcad62cSEric Paris }
439e9fd702aSEric Paris }
440cfcad62cSEric Paris
441cfcad62cSEric Paris audit_add_to_parent(krule, parent);
442cfcad62cSEric Paris
443ae7b8f41SEric Paris h = audit_hash_ino((u32)watch->ino);
444ae7b8f41SEric Paris *list = &audit_inode_hash[h];
44535fe4d0bSEric Paris error:
44615a9155fSAl Viro path_put(&parent_path);
447baa2a4fdSRonny Chevalier audit_put_watch(watch);
448cfcad62cSEric Paris return ret;
449cfcad62cSEric Paris }
450cfcad62cSEric Paris
audit_remove_watch_rule(struct audit_krule * krule)451a05fb6ccSEric Paris void audit_remove_watch_rule(struct audit_krule *krule)
452cfcad62cSEric Paris {
453cfcad62cSEric Paris struct audit_watch *watch = krule->watch;
454cfcad62cSEric Paris struct audit_parent *parent = watch->parent;
455cfcad62cSEric Paris
456cfcad62cSEric Paris list_del(&krule->rlist);
457cfcad62cSEric Paris
458cfcad62cSEric Paris if (list_empty(&watch->rules)) {
459d76036abSJan Kara /*
460d76036abSJan Kara * audit_remove_watch() drops our reference to 'parent' which
461d76036abSJan Kara * can get freed. Grab our own reference to be safe.
462d76036abSJan Kara */
463e9fd702aSEric Paris audit_get_parent(parent);
464d76036abSJan Kara audit_remove_watch(watch);
465d76036abSJan Kara if (list_empty(&parent->watches))
466e2a29943SLino Sanfilippo fsnotify_destroy_mark(&parent->mark, audit_watch_group);
467a05fb6ccSEric Paris audit_put_parent(parent);
468cfcad62cSEric Paris }
469cfcad62cSEric Paris }
470cfcad62cSEric Paris
471e9fd702aSEric Paris /* Update watch data in audit rules based on fsnotify events. */
audit_watch_handle_event(struct fsnotify_mark * inode_mark,u32 mask,struct inode * inode,struct inode * dir,const struct qstr * dname,u32 cookie)472b9a1b977SAmir Goldstein static int audit_watch_handle_event(struct fsnotify_mark *inode_mark, u32 mask,
473b9a1b977SAmir Goldstein struct inode *inode, struct inode *dir,
474950cc0d2SAmir Goldstein const struct qstr *dname, u32 cookie)
475e9fd702aSEric Paris {
476e9fd702aSEric Paris struct audit_parent *parent;
477e9fd702aSEric Paris
478ce8f76fbSEric Paris parent = container_of(inode_mark, struct audit_parent, mark);
479e9fd702aSEric Paris
480dabe729dSAmir Goldstein if (WARN_ON_ONCE(inode_mark->group != audit_watch_group))
481b9a1b977SAmir Goldstein return 0;
482e9fd702aSEric Paris
483e9fd702aSEric Paris if (mask & (FS_CREATE|FS_MOVED_TO) && inode)
4846921d4ebSAl Viro audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0);
485e9fd702aSEric Paris else if (mask & (FS_DELETE|FS_MOVED_FROM))
4866921d4ebSAl Viro audit_update_watch(parent, dname, AUDIT_DEV_UNSET, AUDIT_INO_UNSET, 1);
487e9fd702aSEric Paris else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
488e9fd702aSEric Paris audit_remove_parent_watches(parent);
489e9fd702aSEric Paris
490e9fd702aSEric Paris return 0;
491e9fd702aSEric Paris }
492e9fd702aSEric Paris
493e9fd702aSEric Paris static const struct fsnotify_ops audit_watch_fsnotify_ops = {
494b9a1b977SAmir Goldstein .handle_inode_event = audit_watch_handle_event,
495054c636eSJan Kara .free_mark = audit_watch_free_mark,
496cfcad62cSEric Paris };
497cfcad62cSEric Paris
audit_watch_init(void)498cfcad62cSEric Paris static int __init audit_watch_init(void)
499cfcad62cSEric Paris {
500867a448dSAmir Goldstein audit_watch_group = fsnotify_alloc_group(&audit_watch_fsnotify_ops, 0);
501e9fd702aSEric Paris if (IS_ERR(audit_watch_group)) {
502e9fd702aSEric Paris audit_watch_group = NULL;
503e9fd702aSEric Paris audit_panic("cannot create audit fsnotify group");
504e9fd702aSEric Paris }
505cfcad62cSEric Paris return 0;
506cfcad62cSEric Paris }
5071a3aedbcSEric Paris device_initcall(audit_watch_init);
50834d99af5SRichard Guy Briggs
audit_dupe_exe(struct audit_krule * new,struct audit_krule * old)50934d99af5SRichard Guy Briggs int audit_dupe_exe(struct audit_krule *new, struct audit_krule *old)
51034d99af5SRichard Guy Briggs {
51134d99af5SRichard Guy Briggs struct audit_fsnotify_mark *audit_mark;
51234d99af5SRichard Guy Briggs char *pathname;
51334d99af5SRichard Guy Briggs
51434d99af5SRichard Guy Briggs pathname = kstrdup(audit_mark_path(old->exe), GFP_KERNEL);
51534d99af5SRichard Guy Briggs if (!pathname)
51634d99af5SRichard Guy Briggs return -ENOMEM;
51734d99af5SRichard Guy Briggs
51834d99af5SRichard Guy Briggs audit_mark = audit_alloc_mark(new, pathname, strlen(pathname));
51934d99af5SRichard Guy Briggs if (IS_ERR(audit_mark)) {
52034d99af5SRichard Guy Briggs kfree(pathname);
52134d99af5SRichard Guy Briggs return PTR_ERR(audit_mark);
52234d99af5SRichard Guy Briggs }
52334d99af5SRichard Guy Briggs new->exe = audit_mark;
52434d99af5SRichard Guy Briggs
52534d99af5SRichard Guy Briggs return 0;
52634d99af5SRichard Guy Briggs }
52734d99af5SRichard Guy Briggs
audit_exe_compare(struct task_struct * tsk,struct audit_fsnotify_mark * mark)52834d99af5SRichard Guy Briggs int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark *mark)
52934d99af5SRichard Guy Briggs {
53015ce414bSRichard Guy Briggs struct file *exe_file;
53115ce414bSRichard Guy Briggs unsigned long ino;
53215ce414bSRichard Guy Briggs dev_t dev;
53334d99af5SRichard Guy Briggs
53447846d51SPaul Moore /* only do exe filtering if we are recording @current events/records */
53547846d51SPaul Moore if (tsk != current)
53647846d51SPaul Moore return 0;
53747846d51SPaul Moore
538969d90ecSPaul Moore if (!current->mm)
53947846d51SPaul Moore return 0;
54047846d51SPaul Moore exe_file = get_mm_exe_file(current->mm);
5415efc2443SMateusz Guzik if (!exe_file)
5425efc2443SMateusz Guzik return 0;
54345063097SAl Viro ino = file_inode(exe_file)->i_ino;
54445063097SAl Viro dev = file_inode(exe_file)->i_sb->s_dev;
5455efc2443SMateusz Guzik fput(exe_file);
54647846d51SPaul Moore
54734d99af5SRichard Guy Briggs return audit_mark_compare(mark, ino, dev);
54834d99af5SRichard Guy Briggs }
549