Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/kernel/audit_watch.c
10818 views
1
/* audit_watch.c -- watching inodes
2
*
3
* Copyright 2003-2009 Red Hat, Inc.
4
* Copyright 2005 Hewlett-Packard Development Company, L.P.
5
* Copyright 2005 IBM Corporation
6
*
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
11
*
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
16
*
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
*/
21
22
#include <linux/kernel.h>
23
#include <linux/audit.h>
24
#include <linux/kthread.h>
25
#include <linux/mutex.h>
26
#include <linux/fs.h>
27
#include <linux/fsnotify_backend.h>
28
#include <linux/namei.h>
29
#include <linux/netlink.h>
30
#include <linux/sched.h>
31
#include <linux/slab.h>
32
#include <linux/security.h>
33
#include "audit.h"
34
35
/*
36
* Reference counting:
37
*
38
* audit_parent: lifetime is from audit_init_parent() to receipt of an FS_IGNORED
39
* event. Each audit_watch holds a reference to its associated parent.
40
*
41
* audit_watch: if added to lists, lifetime is from audit_init_watch() to
42
* audit_remove_watch(). Additionally, an audit_watch may exist
43
* temporarily to assist in searching existing filter data. Each
44
* audit_krule holds a reference to its associated watch.
45
*/
46
47
struct audit_watch {
48
atomic_t count; /* reference count */
49
dev_t dev; /* associated superblock device */
50
char *path; /* insertion path */
51
unsigned long ino; /* associated inode number */
52
struct audit_parent *parent; /* associated parent */
53
struct list_head wlist; /* entry in parent->watches list */
54
struct list_head rules; /* anchor for krule->rlist */
55
};
56
57
struct audit_parent {
58
struct list_head watches; /* anchor for audit_watch->wlist */
59
struct fsnotify_mark mark; /* fsnotify mark on the inode */
60
};
61
62
/* fsnotify handle. */
63
static struct fsnotify_group *audit_watch_group;
64
65
/* fsnotify events we care about. */
66
#define AUDIT_FS_WATCH (FS_MOVE | FS_CREATE | FS_DELETE | FS_DELETE_SELF |\
67
FS_MOVE_SELF | FS_EVENT_ON_CHILD)
68
69
static void audit_free_parent(struct audit_parent *parent)
70
{
71
WARN_ON(!list_empty(&parent->watches));
72
kfree(parent);
73
}
74
75
static void audit_watch_free_mark(struct fsnotify_mark *entry)
76
{
77
struct audit_parent *parent;
78
79
parent = container_of(entry, struct audit_parent, mark);
80
audit_free_parent(parent);
81
}
82
83
static void audit_get_parent(struct audit_parent *parent)
84
{
85
if (likely(parent))
86
fsnotify_get_mark(&parent->mark);
87
}
88
89
static void audit_put_parent(struct audit_parent *parent)
90
{
91
if (likely(parent))
92
fsnotify_put_mark(&parent->mark);
93
}
94
95
/*
96
* Find and return the audit_parent on the given inode. If found a reference
97
* is taken on this parent.
98
*/
99
static inline struct audit_parent *audit_find_parent(struct inode *inode)
100
{
101
struct audit_parent *parent = NULL;
102
struct fsnotify_mark *entry;
103
104
entry = fsnotify_find_inode_mark(audit_watch_group, inode);
105
if (entry)
106
parent = container_of(entry, struct audit_parent, mark);
107
108
return parent;
109
}
110
111
void audit_get_watch(struct audit_watch *watch)
112
{
113
atomic_inc(&watch->count);
114
}
115
116
void audit_put_watch(struct audit_watch *watch)
117
{
118
if (atomic_dec_and_test(&watch->count)) {
119
WARN_ON(watch->parent);
120
WARN_ON(!list_empty(&watch->rules));
121
kfree(watch->path);
122
kfree(watch);
123
}
124
}
125
126
static void audit_remove_watch(struct audit_watch *watch)
127
{
128
list_del(&watch->wlist);
129
audit_put_parent(watch->parent);
130
watch->parent = NULL;
131
audit_put_watch(watch); /* match initial get */
132
}
133
134
char *audit_watch_path(struct audit_watch *watch)
135
{
136
return watch->path;
137
}
138
139
int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
140
{
141
return (watch->ino != (unsigned long)-1) &&
142
(watch->ino == ino) &&
143
(watch->dev == dev);
144
}
145
146
/* Initialize a parent watch entry. */
147
static struct audit_parent *audit_init_parent(struct path *path)
148
{
149
struct inode *inode = path->dentry->d_inode;
150
struct audit_parent *parent;
151
int ret;
152
153
parent = kzalloc(sizeof(*parent), GFP_KERNEL);
154
if (unlikely(!parent))
155
return ERR_PTR(-ENOMEM);
156
157
INIT_LIST_HEAD(&parent->watches);
158
159
fsnotify_init_mark(&parent->mark, audit_watch_free_mark);
160
parent->mark.mask = AUDIT_FS_WATCH;
161
ret = fsnotify_add_mark(&parent->mark, audit_watch_group, inode, NULL, 0);
162
if (ret < 0) {
163
audit_free_parent(parent);
164
return ERR_PTR(ret);
165
}
166
167
return parent;
168
}
169
170
/* Initialize a watch entry. */
171
static struct audit_watch *audit_init_watch(char *path)
172
{
173
struct audit_watch *watch;
174
175
watch = kzalloc(sizeof(*watch), GFP_KERNEL);
176
if (unlikely(!watch))
177
return ERR_PTR(-ENOMEM);
178
179
INIT_LIST_HEAD(&watch->rules);
180
atomic_set(&watch->count, 1);
181
watch->path = path;
182
watch->dev = (dev_t)-1;
183
watch->ino = (unsigned long)-1;
184
185
return watch;
186
}
187
188
/* Translate a watch string to kernel respresentation. */
189
int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op)
190
{
191
struct audit_watch *watch;
192
193
if (!audit_watch_group)
194
return -EOPNOTSUPP;
195
196
if (path[0] != '/' || path[len-1] == '/' ||
197
krule->listnr != AUDIT_FILTER_EXIT ||
198
op != Audit_equal ||
199
krule->inode_f || krule->watch || krule->tree)
200
return -EINVAL;
201
202
watch = audit_init_watch(path);
203
if (IS_ERR(watch))
204
return PTR_ERR(watch);
205
206
audit_get_watch(watch);
207
krule->watch = watch;
208
209
return 0;
210
}
211
212
/* Duplicate the given audit watch. The new watch's rules list is initialized
213
* to an empty list and wlist is undefined. */
214
static struct audit_watch *audit_dupe_watch(struct audit_watch *old)
215
{
216
char *path;
217
struct audit_watch *new;
218
219
path = kstrdup(old->path, GFP_KERNEL);
220
if (unlikely(!path))
221
return ERR_PTR(-ENOMEM);
222
223
new = audit_init_watch(path);
224
if (IS_ERR(new)) {
225
kfree(path);
226
goto out;
227
}
228
229
new->dev = old->dev;
230
new->ino = old->ino;
231
audit_get_parent(old->parent);
232
new->parent = old->parent;
233
234
out:
235
return new;
236
}
237
238
static void audit_watch_log_rule_change(struct audit_krule *r, struct audit_watch *w, char *op)
239
{
240
if (audit_enabled) {
241
struct audit_buffer *ab;
242
ab = audit_log_start(NULL, GFP_NOFS, AUDIT_CONFIG_CHANGE);
243
audit_log_format(ab, "auid=%u ses=%u op=",
244
audit_get_loginuid(current),
245
audit_get_sessionid(current));
246
audit_log_string(ab, op);
247
audit_log_format(ab, " path=");
248
audit_log_untrustedstring(ab, w->path);
249
audit_log_key(ab, r->filterkey);
250
audit_log_format(ab, " list=%d res=1", r->listnr);
251
audit_log_end(ab);
252
}
253
}
254
255
/* Update inode info in audit rules based on filesystem event. */
256
static void audit_update_watch(struct audit_parent *parent,
257
const char *dname, dev_t dev,
258
unsigned long ino, unsigned invalidating)
259
{
260
struct audit_watch *owatch, *nwatch, *nextw;
261
struct audit_krule *r, *nextr;
262
struct audit_entry *oentry, *nentry;
263
264
mutex_lock(&audit_filter_mutex);
265
/* Run all of the watches on this parent looking for the one that
266
* matches the given dname */
267
list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
268
if (audit_compare_dname_path(dname, owatch->path, NULL))
269
continue;
270
271
/* If the update involves invalidating rules, do the inode-based
272
* filtering now, so we don't omit records. */
273
if (invalidating && !audit_dummy_context())
274
audit_filter_inodes(current, current->audit_context);
275
276
/* updating ino will likely change which audit_hash_list we
277
* are on so we need a new watch for the new list */
278
nwatch = audit_dupe_watch(owatch);
279
if (IS_ERR(nwatch)) {
280
mutex_unlock(&audit_filter_mutex);
281
audit_panic("error updating watch, skipping");
282
return;
283
}
284
nwatch->dev = dev;
285
nwatch->ino = ino;
286
287
list_for_each_entry_safe(r, nextr, &owatch->rules, rlist) {
288
289
oentry = container_of(r, struct audit_entry, rule);
290
list_del(&oentry->rule.rlist);
291
list_del_rcu(&oentry->list);
292
293
nentry = audit_dupe_rule(&oentry->rule);
294
if (IS_ERR(nentry)) {
295
list_del(&oentry->rule.list);
296
audit_panic("error updating watch, removing");
297
} else {
298
int h = audit_hash_ino((u32)ino);
299
300
/*
301
* nentry->rule.watch == oentry->rule.watch so
302
* we must drop that reference and set it to our
303
* new watch.
304
*/
305
audit_put_watch(nentry->rule.watch);
306
audit_get_watch(nwatch);
307
nentry->rule.watch = nwatch;
308
list_add(&nentry->rule.rlist, &nwatch->rules);
309
list_add_rcu(&nentry->list, &audit_inode_hash[h]);
310
list_replace(&oentry->rule.list,
311
&nentry->rule.list);
312
}
313
314
audit_watch_log_rule_change(r, owatch, "updated rules");
315
316
call_rcu(&oentry->rcu, audit_free_rule_rcu);
317
}
318
319
audit_remove_watch(owatch);
320
goto add_watch_to_parent; /* event applies to a single watch */
321
}
322
mutex_unlock(&audit_filter_mutex);
323
return;
324
325
add_watch_to_parent:
326
list_add(&nwatch->wlist, &parent->watches);
327
mutex_unlock(&audit_filter_mutex);
328
return;
329
}
330
331
/* Remove all watches & rules associated with a parent that is going away. */
332
static void audit_remove_parent_watches(struct audit_parent *parent)
333
{
334
struct audit_watch *w, *nextw;
335
struct audit_krule *r, *nextr;
336
struct audit_entry *e;
337
338
mutex_lock(&audit_filter_mutex);
339
list_for_each_entry_safe(w, nextw, &parent->watches, wlist) {
340
list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
341
e = container_of(r, struct audit_entry, rule);
342
audit_watch_log_rule_change(r, w, "remove rule");
343
list_del(&r->rlist);
344
list_del(&r->list);
345
list_del_rcu(&e->list);
346
call_rcu(&e->rcu, audit_free_rule_rcu);
347
}
348
audit_remove_watch(w);
349
}
350
mutex_unlock(&audit_filter_mutex);
351
352
fsnotify_destroy_mark(&parent->mark);
353
}
354
355
/* Get path information necessary for adding watches. */
356
static int audit_get_nd(struct audit_watch *watch, struct path *parent)
357
{
358
struct nameidata nd;
359
struct dentry *d;
360
int err;
361
362
err = kern_path_parent(watch->path, &nd);
363
if (err)
364
return err;
365
366
if (nd.last_type != LAST_NORM) {
367
path_put(&nd.path);
368
return -EINVAL;
369
}
370
371
mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
372
d = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
373
if (IS_ERR(d)) {
374
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
375
path_put(&nd.path);
376
return PTR_ERR(d);
377
}
378
if (d->d_inode) {
379
/* update watch filter fields */
380
watch->dev = d->d_inode->i_sb->s_dev;
381
watch->ino = d->d_inode->i_ino;
382
}
383
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
384
385
*parent = nd.path;
386
dput(d);
387
return 0;
388
}
389
390
/* Associate the given rule with an existing parent.
391
* Caller must hold audit_filter_mutex. */
392
static void audit_add_to_parent(struct audit_krule *krule,
393
struct audit_parent *parent)
394
{
395
struct audit_watch *w, *watch = krule->watch;
396
int watch_found = 0;
397
398
BUG_ON(!mutex_is_locked(&audit_filter_mutex));
399
400
list_for_each_entry(w, &parent->watches, wlist) {
401
if (strcmp(watch->path, w->path))
402
continue;
403
404
watch_found = 1;
405
406
/* put krule's and initial refs to temporary watch */
407
audit_put_watch(watch);
408
audit_put_watch(watch);
409
410
audit_get_watch(w);
411
krule->watch = watch = w;
412
break;
413
}
414
415
if (!watch_found) {
416
audit_get_parent(parent);
417
watch->parent = parent;
418
419
list_add(&watch->wlist, &parent->watches);
420
}
421
list_add(&krule->rlist, &watch->rules);
422
}
423
424
/* Find a matching watch entry, or add this one.
425
* Caller must hold audit_filter_mutex. */
426
int audit_add_watch(struct audit_krule *krule, struct list_head **list)
427
{
428
struct audit_watch *watch = krule->watch;
429
struct audit_parent *parent;
430
struct path parent_path;
431
int h, ret = 0;
432
433
mutex_unlock(&audit_filter_mutex);
434
435
/* Avoid calling path_lookup under audit_filter_mutex. */
436
ret = audit_get_nd(watch, &parent_path);
437
438
/* caller expects mutex locked */
439
mutex_lock(&audit_filter_mutex);
440
441
if (ret)
442
return ret;
443
444
/* either find an old parent or attach a new one */
445
parent = audit_find_parent(parent_path.dentry->d_inode);
446
if (!parent) {
447
parent = audit_init_parent(&parent_path);
448
if (IS_ERR(parent)) {
449
ret = PTR_ERR(parent);
450
goto error;
451
}
452
}
453
454
audit_add_to_parent(krule, parent);
455
456
/* match get in audit_find_parent or audit_init_parent */
457
audit_put_parent(parent);
458
459
h = audit_hash_ino((u32)watch->ino);
460
*list = &audit_inode_hash[h];
461
error:
462
path_put(&parent_path);
463
return ret;
464
}
465
466
void audit_remove_watch_rule(struct audit_krule *krule)
467
{
468
struct audit_watch *watch = krule->watch;
469
struct audit_parent *parent = watch->parent;
470
471
list_del(&krule->rlist);
472
473
if (list_empty(&watch->rules)) {
474
audit_remove_watch(watch);
475
476
if (list_empty(&parent->watches)) {
477
audit_get_parent(parent);
478
fsnotify_destroy_mark(&parent->mark);
479
audit_put_parent(parent);
480
}
481
}
482
}
483
484
static bool audit_watch_should_send_event(struct fsnotify_group *group, struct inode *inode,
485
struct fsnotify_mark *inode_mark,
486
struct fsnotify_mark *vfsmount_mark,
487
__u32 mask, void *data, int data_type)
488
{
489
return true;
490
}
491
492
/* Update watch data in audit rules based on fsnotify events. */
493
static int audit_watch_handle_event(struct fsnotify_group *group,
494
struct fsnotify_mark *inode_mark,
495
struct fsnotify_mark *vfsmount_mark,
496
struct fsnotify_event *event)
497
{
498
struct inode *inode;
499
__u32 mask = event->mask;
500
const char *dname = event->file_name;
501
struct audit_parent *parent;
502
503
parent = container_of(inode_mark, struct audit_parent, mark);
504
505
BUG_ON(group != audit_watch_group);
506
507
switch (event->data_type) {
508
case (FSNOTIFY_EVENT_PATH):
509
inode = event->path.dentry->d_inode;
510
break;
511
case (FSNOTIFY_EVENT_INODE):
512
inode = event->inode;
513
break;
514
default:
515
BUG();
516
inode = NULL;
517
break;
518
};
519
520
if (mask & (FS_CREATE|FS_MOVED_TO) && inode)
521
audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0);
522
else if (mask & (FS_DELETE|FS_MOVED_FROM))
523
audit_update_watch(parent, dname, (dev_t)-1, (unsigned long)-1, 1);
524
else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
525
audit_remove_parent_watches(parent);
526
527
return 0;
528
}
529
530
static const struct fsnotify_ops audit_watch_fsnotify_ops = {
531
.should_send_event = audit_watch_should_send_event,
532
.handle_event = audit_watch_handle_event,
533
.free_group_priv = NULL,
534
.freeing_mark = NULL,
535
.free_event_priv = NULL,
536
};
537
538
static int __init audit_watch_init(void)
539
{
540
audit_watch_group = fsnotify_alloc_group(&audit_watch_fsnotify_ops);
541
if (IS_ERR(audit_watch_group)) {
542
audit_watch_group = NULL;
543
audit_panic("cannot create audit fsnotify group");
544
}
545
return 0;
546
}
547
device_initcall(audit_watch_init);
548
549