audit_watch.c 13.7 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-or-later
2 3 4 5 6 7 8
/* audit_watch.c -- watching inodes
 *
 * Copyright 2003-2009 Red Hat, Inc.
 * Copyright 2005 Hewlett-Packard Development Company, L.P.
 * Copyright 2005 IBM Corporation
 */

9
#include <linux/file.h>
10 11 12 13 14
#include <linux/kernel.h>
#include <linux/audit.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/fs.h>
15
#include <linux/fsnotify_backend.h>
16 17
#include <linux/namei.h>
#include <linux/netlink.h>
18
#include <linux/refcount.h>
19
#include <linux/sched.h>
20
#include <linux/slab.h>
21 22 23 24 25 26
#include <linux/security.h>
#include "audit.h"

/*
 * Reference counting:
 *
27
 * audit_parent: lifetime is from audit_init_parent() to receipt of an FS_IGNORED
28 29 30 31 32 33 34 35 36
 * 	event.  Each audit_watch holds a reference to its associated parent.
 *
 * audit_watch: if added to lists, lifetime is from audit_init_watch() to
 * 	audit_remove_watch().  Additionally, an audit_watch may exist
 * 	temporarily to assist in searching existing filter data.  Each
 * 	audit_krule holds a reference to its associated watch.
 */

struct audit_watch {
37
	refcount_t		count;	/* reference count */
38
	dev_t			dev;	/* associated superblock device */
39
	char			*path;	/* insertion path */
40 41 42
	unsigned long		ino;	/* associated inode number */
	struct audit_parent	*parent; /* associated parent */
	struct list_head	wlist;	/* entry in parent->watches list */
43
	struct list_head	rules;	/* anchor for krule->rlist */
44 45 46
};

struct audit_parent {
47
	struct list_head	watches; /* anchor for audit_watch->wlist */
48
	struct fsnotify_mark mark; /* fsnotify mark on the inode */
49 50
};

51
/* fsnotify handle. */
52
static struct fsnotify_group *audit_watch_group;
53

54 55
/* fsnotify events we care about. */
#define AUDIT_FS_WATCH (FS_MOVE | FS_CREATE | FS_DELETE | FS_DELETE_SELF |\
56
			FS_MOVE_SELF | FS_UNMOUNT)
57

58 59 60 61 62 63
static void audit_free_parent(struct audit_parent *parent)
{
	WARN_ON(!list_empty(&parent->watches));
	kfree(parent);
}

64
static void audit_watch_free_mark(struct fsnotify_mark *entry)
65 66 67
{
	struct audit_parent *parent;

68
	parent = container_of(entry, struct audit_parent, mark);
69
	audit_free_parent(parent);
70 71
}

72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
static void audit_get_parent(struct audit_parent *parent)
{
	if (likely(parent))
		fsnotify_get_mark(&parent->mark);
}

static void audit_put_parent(struct audit_parent *parent)
{
	if (likely(parent))
		fsnotify_put_mark(&parent->mark);
}

/*
 * Find and return the audit_parent on the given inode.  If found a reference
 * is taken on this parent.
 */
static inline struct audit_parent *audit_find_parent(struct inode *inode)
{
	struct audit_parent *parent = NULL;
91
	struct fsnotify_mark *entry;
92

93
	entry = fsnotify_find_mark(&inode->i_fsnotify_marks, audit_watch_group);
94 95 96 97 98 99
	if (entry)
		parent = container_of(entry, struct audit_parent, mark);

	return parent;
}

100 101
void audit_get_watch(struct audit_watch *watch)
{
102
	refcount_inc(&watch->count);
103 104 105 106
}

void audit_put_watch(struct audit_watch *watch)
{
107
	if (refcount_dec_and_test(&watch->count)) {
108 109 110 111 112 113 114
		WARN_ON(watch->parent);
		WARN_ON(!list_empty(&watch->rules));
		kfree(watch->path);
		kfree(watch);
	}
}

115
static void audit_remove_watch(struct audit_watch *watch)
116 117
{
	list_del(&watch->wlist);
118
	audit_put_parent(watch->parent);
119 120 121 122 123 124 125 126 127
	watch->parent = NULL;
	audit_put_watch(watch); /* match initial get */
}

char *audit_watch_path(struct audit_watch *watch)
{
	return watch->path;
}

128
int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
129
{
130
	return (watch->ino != AUDIT_INO_UNSET) &&
131 132
		(watch->ino == ino) &&
		(watch->dev == dev);
133 134 135
}

/* Initialize a parent watch entry. */
Al Viro's avatar
Al Viro committed
136
static struct audit_parent *audit_init_parent(struct path *path)
137
{
138
	struct inode *inode = d_backing_inode(path->dentry);
139
	struct audit_parent *parent;
140
	int ret;
141 142 143 144 145 146 147

	parent = kzalloc(sizeof(*parent), GFP_KERNEL);
	if (unlikely(!parent))
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&parent->watches);

148
	fsnotify_init_mark(&parent->mark, audit_watch_group);
149
	parent->mark.mask = AUDIT_FS_WATCH;
150
	ret = fsnotify_add_inode_mark(&parent->mark, inode, 0);
151
	if (ret < 0) {
152
		audit_free_parent(parent);
153
		return ERR_PTR(ret);
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
	}

	return parent;
}

/* Initialize a watch entry. */
static struct audit_watch *audit_init_watch(char *path)
{
	struct audit_watch *watch;

	watch = kzalloc(sizeof(*watch), GFP_KERNEL);
	if (unlikely(!watch))
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&watch->rules);
169
	refcount_set(&watch->count, 1);
170
	watch->path = path;
171 172
	watch->dev = AUDIT_DEV_UNSET;
	watch->ino = AUDIT_INO_UNSET;
173 174 175 176

	return watch;
}

Wei Yuan's avatar
Wei Yuan committed
177
/* Translate a watch string to kernel representation. */
178 179 180 181
int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op)
{
	struct audit_watch *watch;

182
	if (!audit_watch_group)
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
		return -EOPNOTSUPP;

	if (path[0] != '/' || path[len-1] == '/' ||
	    krule->listnr != AUDIT_FILTER_EXIT ||
	    op != Audit_equal ||
	    krule->inode_f || krule->watch || krule->tree)
		return -EINVAL;

	watch = audit_init_watch(path);
	if (IS_ERR(watch))
		return PTR_ERR(watch);

	krule->watch = watch;

	return 0;
}

/* Duplicate the given audit watch.  The new watch's rules list is initialized
 * to an empty list and wlist is undefined. */
static struct audit_watch *audit_dupe_watch(struct audit_watch *old)
{
	char *path;
	struct audit_watch *new;

	path = kstrdup(old->path, GFP_KERNEL);
	if (unlikely(!path))
		return ERR_PTR(-ENOMEM);

	new = audit_init_watch(path);
	if (IS_ERR(new)) {
		kfree(path);
		goto out;
	}

	new->dev = old->dev;
	new->ino = old->ino;
219
	audit_get_parent(old->parent);
220 221 222 223 224 225 226 227
	new->parent = old->parent;

out:
	return new;
}

static void audit_watch_log_rule_change(struct audit_krule *r, struct audit_watch *w, char *op)
{
228 229 230 231
	struct audit_buffer *ab;

	if (!audit_enabled)
		return;
232
	ab = audit_log_start(audit_context(), GFP_NOFS, AUDIT_CONFIG_CHANGE);
233 234
	if (!ab)
		return;
235
	audit_log_session_info(ab);
236
	audit_log_format(ab, "op=%s path=", op);
237 238 239 240
	audit_log_untrustedstring(ab, w->path);
	audit_log_key(ab, r->filterkey);
	audit_log_format(ab, " list=%d res=1", r->listnr);
	audit_log_end(ab);
241 242 243 244
}

/* Update inode info in audit rules based on filesystem event. */
static void audit_update_watch(struct audit_parent *parent,
245
			       const struct qstr *dname, dev_t dev,
246 247 248 249 250 251 252
			       unsigned long ino, unsigned invalidating)
{
	struct audit_watch *owatch, *nwatch, *nextw;
	struct audit_krule *r, *nextr;
	struct audit_entry *oentry, *nentry;

	mutex_lock(&audit_filter_mutex);
253 254
	/* Run all of the watches on this parent looking for the one that
	 * matches the given dname */
255
	list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
256
		if (audit_compare_dname_path(dname, owatch->path,
257
					     AUDIT_NAME_FULL))
258 259 260 261
			continue;

		/* If the update involves invalidating rules, do the inode-based
		 * filtering now, so we don't omit records. */
262
		if (invalidating && !audit_dummy_context())
263
			audit_filter_inodes(current, audit_context());
264

265 266
		/* updating ino will likely change which audit_hash_list we
		 * are on so we need a new watch for the new list */
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
		nwatch = audit_dupe_watch(owatch);
		if (IS_ERR(nwatch)) {
			mutex_unlock(&audit_filter_mutex);
			audit_panic("error updating watch, skipping");
			return;
		}
		nwatch->dev = dev;
		nwatch->ino = ino;

		list_for_each_entry_safe(r, nextr, &owatch->rules, rlist) {

			oentry = container_of(r, struct audit_entry, rule);
			list_del(&oentry->rule.rlist);
			list_del_rcu(&oentry->list);

282
			nentry = audit_dupe_rule(&oentry->rule);
283 284 285 286 287
			if (IS_ERR(nentry)) {
				list_del(&oentry->rule.list);
				audit_panic("error updating watch, removing");
			} else {
				int h = audit_hash_ino((u32)ino);
288 289 290 291 292 293 294 295 296

				/*
				 * nentry->rule.watch == oentry->rule.watch so
				 * we must drop that reference and set it to our
				 * new watch.
				 */
				audit_put_watch(nentry->rule.watch);
				audit_get_watch(nwatch);
				nentry->rule.watch = nwatch;
297 298 299 300 301
				list_add(&nentry->rule.rlist, &nwatch->rules);
				list_add_rcu(&nentry->list, &audit_inode_hash[h]);
				list_replace(&oentry->rule.list,
					     &nentry->rule.list);
			}
302 303
			if (oentry->rule.exe)
				audit_remove_mark(oentry->rule.exe);
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330

			call_rcu(&oentry->rcu, audit_free_rule_rcu);
		}

		audit_remove_watch(owatch);
		goto add_watch_to_parent; /* event applies to a single watch */
	}
	mutex_unlock(&audit_filter_mutex);
	return;

add_watch_to_parent:
	list_add(&nwatch->wlist, &parent->watches);
	mutex_unlock(&audit_filter_mutex);
	return;
}

/* Remove all watches & rules associated with a parent that is going away. */
static void audit_remove_parent_watches(struct audit_parent *parent)
{
	struct audit_watch *w, *nextw;
	struct audit_krule *r, *nextr;
	struct audit_entry *e;

	mutex_lock(&audit_filter_mutex);
	list_for_each_entry_safe(w, nextw, &parent->watches, wlist) {
		list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
			e = container_of(r, struct audit_entry, rule);
331
			audit_watch_log_rule_change(r, w, "remove_rule");
332 333
			if (e->rule.exe)
				audit_remove_mark(e->rule.exe);
334 335 336 337 338 339 340 341
			list_del(&r->rlist);
			list_del(&r->list);
			list_del_rcu(&e->list);
			call_rcu(&e->rcu, audit_free_rule_rcu);
		}
		audit_remove_watch(w);
	}
	mutex_unlock(&audit_filter_mutex);
342

343
	fsnotify_destroy_mark(&parent->mark, audit_watch_group);
344 345 346
}

/* Get path information necessary for adding watches. */
Al Viro's avatar
Al Viro committed
347
static int audit_get_nd(struct audit_watch *watch, struct path *parent)
348
{
Al Viro's avatar
Al Viro committed
349 350
	struct dentry *d = kern_path_locked(watch->path, parent);
	if (IS_ERR(d))
Al Viro's avatar
Al Viro committed
351
		return PTR_ERR(d);
352
	if (d_is_positive(d)) {
Al Viro's avatar
Al Viro committed
353
		/* update watch filter fields */
354
		watch->dev = d->d_sb->s_dev;
355
		watch->ino = d_backing_inode(d)->i_ino;
356
	}
357
	inode_unlock(d_backing_inode(parent->dentry));
Al Viro's avatar
Al Viro committed
358
	dput(d);
359 360 361
	return 0;
}

362
/* Associate the given rule with an existing parent.
363 364 365 366 367 368 369
 * Caller must hold audit_filter_mutex. */
static void audit_add_to_parent(struct audit_krule *krule,
				struct audit_parent *parent)
{
	struct audit_watch *w, *watch = krule->watch;
	int watch_found = 0;

370 371
	BUG_ON(!mutex_is_locked(&audit_filter_mutex));

372 373 374 375 376 377
	list_for_each_entry(w, &parent->watches, wlist) {
		if (strcmp(watch->path, w->path))
			continue;

		watch_found = 1;

378
		/* put krule's ref to temporary watch */
379 380 381 382
		audit_put_watch(watch);

		audit_get_watch(w);
		krule->watch = watch = w;
383 384

		audit_put_parent(parent);
385 386 387 388 389 390
		break;
	}

	if (!watch_found) {
		watch->parent = parent;

391
		audit_get_watch(watch);
392 393 394 395 396 397 398
		list_add(&watch->wlist, &parent->watches);
	}
	list_add(&krule->rlist, &watch->rules);
}

/* Find a matching watch entry, or add this one.
 * Caller must hold audit_filter_mutex. */
399
int audit_add_watch(struct audit_krule *krule, struct list_head **list)
400 401 402
{
	struct audit_watch *watch = krule->watch;
	struct audit_parent *parent;
Al Viro's avatar
Al Viro committed
403
	struct path parent_path;
404
	int h, ret = 0;
405

406 407 408 409 410 411 412
	/*
	 * When we will be calling audit_add_to_parent, krule->watch might have
	 * been updated and watch might have been freed.
	 * So we need to keep a reference of watch.
	 */
	audit_get_watch(watch);

413 414 415
	mutex_unlock(&audit_filter_mutex);

	/* Avoid calling path_lookup under audit_filter_mutex. */
Al Viro's avatar
Al Viro committed
416
	ret = audit_get_nd(watch, &parent_path);
417

Al Viro's avatar
Al Viro committed
418
	/* caller expects mutex locked */
419 420
	mutex_lock(&audit_filter_mutex);

421 422
	if (ret) {
		audit_put_watch(watch);
Al Viro's avatar
Al Viro committed
423
		return ret;
424
	}
425

426
	/* either find an old parent or attach a new one */
427
	parent = audit_find_parent(d_backing_inode(parent_path.dentry));
428
	if (!parent) {
Al Viro's avatar
Al Viro committed
429
		parent = audit_init_parent(&parent_path);
430
		if (IS_ERR(parent)) {
431 432
			ret = PTR_ERR(parent);
			goto error;
433
		}
434
	}
435

436
	audit_add_to_parent(krule, parent);
437

438 439
	h = audit_hash_ino((u32)watch->ino);
	*list = &audit_inode_hash[h];
440
error:
Al Viro's avatar
Al Viro committed
441
	path_put(&parent_path);
442
	audit_put_watch(watch);
443 444 445
	return ret;
}

446
void audit_remove_watch_rule(struct audit_krule *krule)
447 448 449 450 451 452 453
{
	struct audit_watch *watch = krule->watch;
	struct audit_parent *parent = watch->parent;

	list_del(&krule->rlist);

	if (list_empty(&watch->rules)) {
454 455 456 457 458
		/*
		 * audit_remove_watch() drops our reference to 'parent' which
		 * can get freed. Grab our own reference to be safe.
		 */
		audit_get_parent(parent);
459
		audit_remove_watch(watch);
460
		if (list_empty(&parent->watches))
461
			fsnotify_destroy_mark(&parent->mark, audit_watch_group);
462
		audit_put_parent(parent);
463 464 465
	}
}

466
/* Update watch data in audit rules based on fsnotify events. */
467 468 469
static int audit_watch_handle_event(struct fsnotify_mark *inode_mark, u32 mask,
				    struct inode *inode, struct inode *dir,
				    const struct qstr *dname)
470
{
471 472
	struct audit_parent *parent;

473
	parent = container_of(inode_mark, struct audit_parent, mark);
474

475 476 477
	if (WARN_ON_ONCE(inode_mark->group != audit_watch_group) ||
	    WARN_ON_ONCE(!inode))
		return 0;
478

479
	if (mask & (FS_CREATE|FS_MOVED_TO) && inode)
480
		audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0);
481
	else if (mask & (FS_DELETE|FS_MOVED_FROM))
482
		audit_update_watch(parent, dname, AUDIT_DEV_UNSET, AUDIT_INO_UNSET, 1);
483
	else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
484
		audit_remove_parent_watches(parent);
485 486 487 488 489

	return 0;
}

static const struct fsnotify_ops audit_watch_fsnotify_ops = {
490
	.handle_inode_event =	audit_watch_handle_event,
491
	.free_mark =		audit_watch_free_mark,
492 493 494 495
};

static int __init audit_watch_init(void)
{
496
	audit_watch_group = fsnotify_alloc_group(&audit_watch_fsnotify_ops);
497 498 499 500
	if (IS_ERR(audit_watch_group)) {
		audit_watch_group = NULL;
		audit_panic("cannot create audit fsnotify group");
	}
501 502
	return 0;
}
503
device_initcall(audit_watch_init);
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525

int audit_dupe_exe(struct audit_krule *new, struct audit_krule *old)
{
	struct audit_fsnotify_mark *audit_mark;
	char *pathname;

	pathname = kstrdup(audit_mark_path(old->exe), GFP_KERNEL);
	if (!pathname)
		return -ENOMEM;

	audit_mark = audit_alloc_mark(new, pathname, strlen(pathname));
	if (IS_ERR(audit_mark)) {
		kfree(pathname);
		return PTR_ERR(audit_mark);
	}
	new->exe = audit_mark;

	return 0;
}

int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark *mark)
{
526 527 528 529
	struct file *exe_file;
	unsigned long ino;
	dev_t dev;

530 531 532
	exe_file = get_task_exe_file(tsk);
	if (!exe_file)
		return 0;
Al Viro's avatar
Al Viro committed
533 534
	ino = file_inode(exe_file)->i_ino;
	dev = file_inode(exe_file)->i_sb->s_dev;
535
	fput(exe_file);
536 537
	return audit_mark_compare(mark, ino, dev);
}