aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-09-08 16:34:59 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-09-08 16:34:59 -0400
commit425afcff13a4bea2a3cf6f395cbc66fc158852be (patch)
treec34863cf9fc8f608be586794db866285abbe317e /kernel
parentb793c005ceabf6db0b17494b0ec67ade6796bb34 (diff)
parent15ce414b82b07acb99afda6e4d9bd14f317b6011 (diff)
Merge branch 'upstream' of git://git.infradead.org/users/pcmoore/audit
Pull audit update from Paul Moore: "This is one of the larger audit patchsets in recent history, consisting of eight patches and almost 400 lines of changes. The bulk of the patchset is the new "audit by executable" functionality which allows admins to set an audit watch based on the executable on disk. Prior to this, admins could only track an application by PID, which has some obvious limitations. Beyond the new functionality we also have some refcnt fixes and a few minor cleanups" * 'upstream' of git://git.infradead.org/users/pcmoore/audit: fixup: audit: implement audit by executable audit: implement audit by executable audit: clean simple fsnotify implementation audit: use macros for unset inode and device values audit: make audit_del_rule() more robust audit: fix uninitialized variable in audit_add_rule() audit: eliminate unnecessary extra layer of watch parent references audit: eliminate unnecessary extra layer of watch references
Diffstat (limited to 'kernel')
-rw-r--r--kernel/Makefile2
-rw-r--r--kernel/audit.c2
-rw-r--r--kernel/audit.h18
-rw-r--r--kernel/audit_fsnotify.c216
-rw-r--r--kernel/audit_tree.c2
-rw-r--r--kernel/audit_watch.c56
-rw-r--r--kernel/auditfilter.c83
-rw-r--r--kernel/auditsc.c9
8 files changed, 351 insertions, 37 deletions
diff --git a/kernel/Makefile b/kernel/Makefile
index 330387cfb730..d25ebea0453a 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -64,7 +64,7 @@ obj-$(CONFIG_SMP) += stop_machine.o
64obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o 64obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o
65obj-$(CONFIG_AUDIT) += audit.o auditfilter.o 65obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
66obj-$(CONFIG_AUDITSYSCALL) += auditsc.o 66obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
67obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o 67obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o audit_fsnotify.o
68obj-$(CONFIG_AUDIT_TREE) += audit_tree.o 68obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
69obj-$(CONFIG_GCOV_KERNEL) += gcov/ 69obj-$(CONFIG_GCOV_KERNEL) += gcov/
70obj-$(CONFIG_KPROBES) += kprobes.o 70obj-$(CONFIG_KPROBES) += kprobes.o
diff --git a/kernel/audit.c b/kernel/audit.c
index f9e6065346db..662c007635fb 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1761,7 +1761,7 @@ void audit_log_name(struct audit_context *context, struct audit_names *n,
1761 } else 1761 } else
1762 audit_log_format(ab, " name=(null)"); 1762 audit_log_format(ab, " name=(null)");
1763 1763
1764 if (n->ino != (unsigned long)-1) 1764 if (n->ino != AUDIT_INO_UNSET)
1765 audit_log_format(ab, " inode=%lu" 1765 audit_log_format(ab, " inode=%lu"
1766 " dev=%02x:%02x mode=%#ho" 1766 " dev=%02x:%02x mode=%#ho"
1767 " ouid=%u ogid=%u rdev=%02x:%02x", 1767 " ouid=%u ogid=%u rdev=%02x:%02x",
diff --git a/kernel/audit.h b/kernel/audit.h
index d641f9bb3ed0..dadf86a0e59e 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -50,6 +50,7 @@ enum audit_state {
50 50
51/* Rule lists */ 51/* Rule lists */
52struct audit_watch; 52struct audit_watch;
53struct audit_fsnotify_mark;
53struct audit_tree; 54struct audit_tree;
54struct audit_chunk; 55struct audit_chunk;
55 56
@@ -252,6 +253,7 @@ struct audit_net {
252extern int selinux_audit_rule_update(void); 253extern int selinux_audit_rule_update(void);
253 254
254extern struct mutex audit_filter_mutex; 255extern struct mutex audit_filter_mutex;
256extern int audit_del_rule(struct audit_entry *);
255extern void audit_free_rule_rcu(struct rcu_head *); 257extern void audit_free_rule_rcu(struct rcu_head *);
256extern struct list_head audit_filter_list[]; 258extern struct list_head audit_filter_list[];
257 259
@@ -269,6 +271,15 @@ extern int audit_add_watch(struct audit_krule *krule, struct list_head **list);
269extern void audit_remove_watch_rule(struct audit_krule *krule); 271extern void audit_remove_watch_rule(struct audit_krule *krule);
270extern char *audit_watch_path(struct audit_watch *watch); 272extern char *audit_watch_path(struct audit_watch *watch);
271extern int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev); 273extern int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev);
274
275extern struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule, char *pathname, int len);
276extern char *audit_mark_path(struct audit_fsnotify_mark *mark);
277extern void audit_remove_mark(struct audit_fsnotify_mark *audit_mark);
278extern void audit_remove_mark_rule(struct audit_krule *krule);
279extern int audit_mark_compare(struct audit_fsnotify_mark *mark, unsigned long ino, dev_t dev);
280extern int audit_dupe_exe(struct audit_krule *new, struct audit_krule *old);
281extern int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark *mark);
282
272#else 283#else
273#define audit_put_watch(w) {} 284#define audit_put_watch(w) {}
274#define audit_get_watch(w) {} 285#define audit_get_watch(w) {}
@@ -278,6 +289,13 @@ extern int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev
278#define audit_watch_path(w) "" 289#define audit_watch_path(w) ""
279#define audit_watch_compare(w, i, d) 0 290#define audit_watch_compare(w, i, d) 0
280 291
292#define audit_alloc_mark(k, p, l) (ERR_PTR(-EINVAL))
293#define audit_mark_path(m) ""
294#define audit_remove_mark(m)
295#define audit_remove_mark_rule(k)
296#define audit_mark_compare(m, i, d) 0
297#define audit_exe_compare(t, m) (-EINVAL)
298#define audit_dupe_exe(n, o) (-EINVAL)
281#endif /* CONFIG_AUDIT_WATCH */ 299#endif /* CONFIG_AUDIT_WATCH */
282 300
283#ifdef CONFIG_AUDIT_TREE 301#ifdef CONFIG_AUDIT_TREE
diff --git a/kernel/audit_fsnotify.c b/kernel/audit_fsnotify.c
new file mode 100644
index 000000000000..27c6046c2c3d
--- /dev/null
+++ b/kernel/audit_fsnotify.c
@@ -0,0 +1,216 @@
1/* audit_fsnotify.c -- tracking inodes
2 *
3 * Copyright 2003-2009,2014-2015 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
18#include <linux/kernel.h>
19#include <linux/audit.h>
20#include <linux/kthread.h>
21#include <linux/mutex.h>
22#include <linux/fs.h>
23#include <linux/fsnotify_backend.h>
24#include <linux/namei.h>
25#include <linux/netlink.h>
26#include <linux/sched.h>
27#include <linux/slab.h>
28#include <linux/security.h>
29#include "audit.h"
30
31/*
32 * this mark lives on the parent directory of the inode in question.
33 * but dev, ino, and path are about the child
34 */
35struct audit_fsnotify_mark {
36 dev_t dev; /* associated superblock device */
37 unsigned long ino; /* associated inode number */
38 char *path; /* insertion path */
39 struct fsnotify_mark mark; /* fsnotify mark on the inode */
40 struct audit_krule *rule;
41};
42
43/* fsnotify handle. */
44static struct fsnotify_group *audit_fsnotify_group;
45
46/* fsnotify events we care about. */
47#define AUDIT_FS_EVENTS (FS_MOVE | FS_CREATE | FS_DELETE | FS_DELETE_SELF |\
48 FS_MOVE_SELF | FS_EVENT_ON_CHILD)
49
50static void audit_fsnotify_mark_free(struct audit_fsnotify_mark *audit_mark)
51{
52 kfree(audit_mark->path);
53 kfree(audit_mark);
54}
55
56static void audit_fsnotify_free_mark(struct fsnotify_mark *mark)
57{
58 struct audit_fsnotify_mark *audit_mark;
59
60 audit_mark = container_of(mark, struct audit_fsnotify_mark, mark);
61 audit_fsnotify_mark_free(audit_mark);
62}
63
64char *audit_mark_path(struct audit_fsnotify_mark *mark)
65{
66 return mark->path;
67}
68
69int audit_mark_compare(struct audit_fsnotify_mark *mark, unsigned long ino, dev_t dev)
70{
71 if (mark->ino == AUDIT_INO_UNSET)
72 return 0;
73 return (mark->ino == ino) && (mark->dev == dev);
74}
75
76static void audit_update_mark(struct audit_fsnotify_mark *audit_mark,
77 struct inode *inode)
78{
79 audit_mark->dev = inode ? inode->i_sb->s_dev : AUDIT_DEV_UNSET;
80 audit_mark->ino = inode ? inode->i_ino : AUDIT_INO_UNSET;
81}
82
83struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule, char *pathname, int len)
84{
85 struct audit_fsnotify_mark *audit_mark;
86 struct path path;
87 struct dentry *dentry;
88 struct inode *inode;
89 int ret;
90
91 if (pathname[0] != '/' || pathname[len-1] == '/')
92 return ERR_PTR(-EINVAL);
93
94 dentry = kern_path_locked(pathname, &path);
95 if (IS_ERR(dentry))
96 return (void *)dentry; /* returning an error */
97 inode = path.dentry->d_inode;
98 mutex_unlock(&inode->i_mutex);
99
100 audit_mark = kzalloc(sizeof(*audit_mark), GFP_KERNEL);
101 if (unlikely(!audit_mark)) {
102 audit_mark = ERR_PTR(-ENOMEM);
103 goto out;
104 }
105
106 fsnotify_init_mark(&audit_mark->mark, audit_fsnotify_free_mark);
107 audit_mark->mark.mask = AUDIT_FS_EVENTS;
108 audit_mark->path = pathname;
109 audit_update_mark(audit_mark, dentry->d_inode);
110 audit_mark->rule = krule;
111
112 ret = fsnotify_add_mark(&audit_mark->mark, audit_fsnotify_group, inode, NULL, true);
113 if (ret < 0) {
114 audit_fsnotify_mark_free(audit_mark);
115 audit_mark = ERR_PTR(ret);
116 }
117out:
118 dput(dentry);
119 path_put(&path);
120 return audit_mark;
121}
122
123static void audit_mark_log_rule_change(struct audit_fsnotify_mark *audit_mark, char *op)
124{
125 struct audit_buffer *ab;
126 struct audit_krule *rule = audit_mark->rule;
127
128 if (!audit_enabled)
129 return;
130 ab = audit_log_start(NULL, GFP_NOFS, AUDIT_CONFIG_CHANGE);
131 if (unlikely(!ab))
132 return;
133 audit_log_format(ab, "auid=%u ses=%u op=",
134 from_kuid(&init_user_ns, audit_get_loginuid(current)),
135 audit_get_sessionid(current));
136 audit_log_string(ab, op);
137 audit_log_format(ab, " path=");
138 audit_log_untrustedstring(ab, audit_mark->path);
139 audit_log_key(ab, rule->filterkey);
140 audit_log_format(ab, " list=%d res=1", rule->listnr);
141 audit_log_end(ab);
142}
143
144void audit_remove_mark(struct audit_fsnotify_mark *audit_mark)
145{
146 fsnotify_destroy_mark(&audit_mark->mark, audit_fsnotify_group);
147 fsnotify_put_mark(&audit_mark->mark);
148}
149
150void audit_remove_mark_rule(struct audit_krule *krule)
151{
152 struct audit_fsnotify_mark *mark = krule->exe;
153
154 audit_remove_mark(mark);
155}
156
157static void audit_autoremove_mark_rule(struct audit_fsnotify_mark *audit_mark)
158{
159 struct audit_krule *rule = audit_mark->rule;
160 struct audit_entry *entry = container_of(rule, struct audit_entry, rule);
161
162 audit_mark_log_rule_change(audit_mark, "autoremove_rule");
163 audit_del_rule(entry);
164}
165
166/* Update mark data in audit rules based on fsnotify events. */
167static int audit_mark_handle_event(struct fsnotify_group *group,
168 struct inode *to_tell,
169 struct fsnotify_mark *inode_mark,
170 struct fsnotify_mark *vfsmount_mark,
171 u32 mask, void *data, int data_type,
172 const unsigned char *dname, u32 cookie)
173{
174 struct audit_fsnotify_mark *audit_mark;
175 struct inode *inode = NULL;
176
177 audit_mark = container_of(inode_mark, struct audit_fsnotify_mark, mark);
178
179 BUG_ON(group != audit_fsnotify_group);
180
181 switch (data_type) {
182 case (FSNOTIFY_EVENT_PATH):
183 inode = ((struct path *)data)->dentry->d_inode;
184 break;
185 case (FSNOTIFY_EVENT_INODE):
186 inode = (struct inode *)data;
187 break;
188 default:
189 BUG();
190 return 0;
191 };
192
193 if (mask & (FS_CREATE|FS_MOVED_TO|FS_DELETE|FS_MOVED_FROM)) {
194 if (audit_compare_dname_path(dname, audit_mark->path, AUDIT_NAME_FULL))
195 return 0;
196 audit_update_mark(audit_mark, inode);
197 } else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
198 audit_autoremove_mark_rule(audit_mark);
199
200 return 0;
201}
202
203static const struct fsnotify_ops audit_mark_fsnotify_ops = {
204 .handle_event = audit_mark_handle_event,
205};
206
207static int __init audit_fsnotify_init(void)
208{
209 audit_fsnotify_group = fsnotify_alloc_group(&audit_mark_fsnotify_ops);
210 if (IS_ERR(audit_fsnotify_group)) {
211 audit_fsnotify_group = NULL;
212 audit_panic("cannot create audit fsnotify group");
213 }
214 return 0;
215}
216device_initcall(audit_fsnotify_init);
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index b0f9877273fc..94ecdabda8e6 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -479,6 +479,8 @@ static void kill_rules(struct audit_tree *tree)
479 if (rule->tree) { 479 if (rule->tree) {
480 /* not a half-baked one */ 480 /* not a half-baked one */
481 audit_tree_log_remove_rule(rule); 481 audit_tree_log_remove_rule(rule);
482 if (entry->rule.exe)
483 audit_remove_mark(entry->rule.exe);
482 rule->tree = NULL; 484 rule->tree = NULL;
483 list_del_rcu(&entry->list); 485 list_del_rcu(&entry->list);
484 list_del(&entry->rule.list); 486 list_del(&entry->rule.list);
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 6e30024d9aac..656c7e93ac0d 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -138,7 +138,7 @@ char *audit_watch_path(struct audit_watch *watch)
138 138
139int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev) 139int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
140{ 140{
141 return (watch->ino != (unsigned long)-1) && 141 return (watch->ino != AUDIT_INO_UNSET) &&
142 (watch->ino == ino) && 142 (watch->ino == ino) &&
143 (watch->dev == dev); 143 (watch->dev == dev);
144} 144}
@@ -179,8 +179,8 @@ static struct audit_watch *audit_init_watch(char *path)
179 INIT_LIST_HEAD(&watch->rules); 179 INIT_LIST_HEAD(&watch->rules);
180 atomic_set(&watch->count, 1); 180 atomic_set(&watch->count, 1);
181 watch->path = path; 181 watch->path = path;
182 watch->dev = (dev_t)-1; 182 watch->dev = AUDIT_DEV_UNSET;
183 watch->ino = (unsigned long)-1; 183 watch->ino = AUDIT_INO_UNSET;
184 184
185 return watch; 185 return watch;
186} 186}
@@ -203,7 +203,6 @@ int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op)
203 if (IS_ERR(watch)) 203 if (IS_ERR(watch))
204 return PTR_ERR(watch); 204 return PTR_ERR(watch);
205 205
206 audit_get_watch(watch);
207 krule->watch = watch; 206 krule->watch = watch;
208 207
209 return 0; 208 return 0;
@@ -313,6 +312,8 @@ static void audit_update_watch(struct audit_parent *parent,
313 list_replace(&oentry->rule.list, 312 list_replace(&oentry->rule.list,
314 &nentry->rule.list); 313 &nentry->rule.list);
315 } 314 }
315 if (oentry->rule.exe)
316 audit_remove_mark(oentry->rule.exe);
316 317
317 audit_watch_log_rule_change(r, owatch, "updated_rules"); 318 audit_watch_log_rule_change(r, owatch, "updated_rules");
318 319
@@ -343,6 +344,8 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
343 list_for_each_entry_safe(r, nextr, &w->rules, rlist) { 344 list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
344 e = container_of(r, struct audit_entry, rule); 345 e = container_of(r, struct audit_entry, rule);
345 audit_watch_log_rule_change(r, w, "remove_rule"); 346 audit_watch_log_rule_change(r, w, "remove_rule");
347 if (e->rule.exe)
348 audit_remove_mark(e->rule.exe);
346 list_del(&r->rlist); 349 list_del(&r->rlist);
347 list_del(&r->list); 350 list_del(&r->list);
348 list_del_rcu(&e->list); 351 list_del_rcu(&e->list);
@@ -387,19 +390,20 @@ static void audit_add_to_parent(struct audit_krule *krule,
387 390
388 watch_found = 1; 391 watch_found = 1;
389 392
390 /* put krule's and initial refs to temporary watch */ 393 /* put krule's ref to temporary watch */
391 audit_put_watch(watch);
392 audit_put_watch(watch); 394 audit_put_watch(watch);
393 395
394 audit_get_watch(w); 396 audit_get_watch(w);
395 krule->watch = watch = w; 397 krule->watch = watch = w;
398
399 audit_put_parent(parent);
396 break; 400 break;
397 } 401 }
398 402
399 if (!watch_found) { 403 if (!watch_found) {
400 audit_get_parent(parent);
401 watch->parent = parent; 404 watch->parent = parent;
402 405
406 audit_get_watch(watch);
403 list_add(&watch->wlist, &parent->watches); 407 list_add(&watch->wlist, &parent->watches);
404 } 408 }
405 list_add(&krule->rlist, &watch->rules); 409 list_add(&krule->rlist, &watch->rules);
@@ -437,9 +441,6 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list)
437 441
438 audit_add_to_parent(krule, parent); 442 audit_add_to_parent(krule, parent);
439 443
440 /* match get in audit_find_parent or audit_init_parent */
441 audit_put_parent(parent);
442
443 h = audit_hash_ino((u32)watch->ino); 444 h = audit_hash_ino((u32)watch->ino);
444 *list = &audit_inode_hash[h]; 445 *list = &audit_inode_hash[h];
445error: 446error:
@@ -496,7 +497,7 @@ static int audit_watch_handle_event(struct fsnotify_group *group,
496 if (mask & (FS_CREATE|FS_MOVED_TO) && inode) 497 if (mask & (FS_CREATE|FS_MOVED_TO) && inode)
497 audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0); 498 audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0);
498 else if (mask & (FS_DELETE|FS_MOVED_FROM)) 499 else if (mask & (FS_DELETE|FS_MOVED_FROM))
499 audit_update_watch(parent, dname, (dev_t)-1, (unsigned long)-1, 1); 500 audit_update_watch(parent, dname, AUDIT_DEV_UNSET, AUDIT_INO_UNSET, 1);
500 else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF)) 501 else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
501 audit_remove_parent_watches(parent); 502 audit_remove_parent_watches(parent);
502 503
@@ -517,3 +518,36 @@ static int __init audit_watch_init(void)
517 return 0; 518 return 0;
518} 519}
519device_initcall(audit_watch_init); 520device_initcall(audit_watch_init);
521
522int audit_dupe_exe(struct audit_krule *new, struct audit_krule *old)
523{
524 struct audit_fsnotify_mark *audit_mark;
525 char *pathname;
526
527 pathname = kstrdup(audit_mark_path(old->exe), GFP_KERNEL);
528 if (!pathname)
529 return -ENOMEM;
530
531 audit_mark = audit_alloc_mark(new, pathname, strlen(pathname));
532 if (IS_ERR(audit_mark)) {
533 kfree(pathname);
534 return PTR_ERR(audit_mark);
535 }
536 new->exe = audit_mark;
537
538 return 0;
539}
540
541int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark *mark)
542{
543 struct file *exe_file;
544 unsigned long ino;
545 dev_t dev;
546
547 rcu_read_lock();
548 exe_file = rcu_dereference(tsk->mm->exe_file);
549 ino = exe_file->f_inode->i_ino;
550 dev = exe_file->f_inode->i_sb->s_dev;
551 rcu_read_unlock();
552 return audit_mark_compare(mark, ino, dev);
553}
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 72e1660a79a3..7714d93edb85 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -405,6 +405,12 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
405 if (f->val > AUDIT_MAX_FIELD_COMPARE) 405 if (f->val > AUDIT_MAX_FIELD_COMPARE)
406 return -EINVAL; 406 return -EINVAL;
407 break; 407 break;
408 case AUDIT_EXE:
409 if (f->op != Audit_equal)
410 return -EINVAL;
411 if (entry->rule.listnr != AUDIT_FILTER_EXIT)
412 return -EINVAL;
413 break;
408 }; 414 };
409 return 0; 415 return 0;
410} 416}
@@ -419,6 +425,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
419 size_t remain = datasz - sizeof(struct audit_rule_data); 425 size_t remain = datasz - sizeof(struct audit_rule_data);
420 int i; 426 int i;
421 char *str; 427 char *str;
428 struct audit_fsnotify_mark *audit_mark;
422 429
423 entry = audit_to_entry_common(data); 430 entry = audit_to_entry_common(data);
424 if (IS_ERR(entry)) 431 if (IS_ERR(entry))
@@ -539,6 +546,24 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
539 entry->rule.buflen += f->val; 546 entry->rule.buflen += f->val;
540 entry->rule.filterkey = str; 547 entry->rule.filterkey = str;
541 break; 548 break;
549 case AUDIT_EXE:
550 if (entry->rule.exe || f->val > PATH_MAX)
551 goto exit_free;
552 str = audit_unpack_string(&bufp, &remain, f->val);
553 if (IS_ERR(str)) {
554 err = PTR_ERR(str);
555 goto exit_free;
556 }
557 entry->rule.buflen += f->val;
558
559 audit_mark = audit_alloc_mark(&entry->rule, str, f->val);
560 if (IS_ERR(audit_mark)) {
561 kfree(str);
562 err = PTR_ERR(audit_mark);
563 goto exit_free;
564 }
565 entry->rule.exe = audit_mark;
566 break;
542 } 567 }
543 } 568 }
544 569
@@ -549,10 +574,10 @@ exit_nofree:
549 return entry; 574 return entry;
550 575
551exit_free: 576exit_free:
552 if (entry->rule.watch)
553 audit_put_watch(entry->rule.watch); /* matches initial get */
554 if (entry->rule.tree) 577 if (entry->rule.tree)
555 audit_put_tree(entry->rule.tree); /* that's the temporary one */ 578 audit_put_tree(entry->rule.tree); /* that's the temporary one */
579 if (entry->rule.exe)
580 audit_remove_mark(entry->rule.exe); /* that's the template one */
556 audit_free_rule(entry); 581 audit_free_rule(entry);
557 return ERR_PTR(err); 582 return ERR_PTR(err);
558} 583}
@@ -617,6 +642,10 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
617 data->buflen += data->values[i] = 642 data->buflen += data->values[i] =
618 audit_pack_string(&bufp, krule->filterkey); 643 audit_pack_string(&bufp, krule->filterkey);
619 break; 644 break;
645 case AUDIT_EXE:
646 data->buflen += data->values[i] =
647 audit_pack_string(&bufp, audit_mark_path(krule->exe));
648 break;
620 case AUDIT_LOGINUID_SET: 649 case AUDIT_LOGINUID_SET:
621 if (krule->pflags & AUDIT_LOGINUID_LEGACY && !f->val) { 650 if (krule->pflags & AUDIT_LOGINUID_LEGACY && !f->val) {
622 data->fields[i] = AUDIT_LOGINUID; 651 data->fields[i] = AUDIT_LOGINUID;
@@ -680,6 +709,12 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
680 if (strcmp(a->filterkey, b->filterkey)) 709 if (strcmp(a->filterkey, b->filterkey))
681 return 1; 710 return 1;
682 break; 711 break;
712 case AUDIT_EXE:
713 /* both paths exist based on above type compare */
714 if (strcmp(audit_mark_path(a->exe),
715 audit_mark_path(b->exe)))
716 return 1;
717 break;
683 case AUDIT_UID: 718 case AUDIT_UID:
684 case AUDIT_EUID: 719 case AUDIT_EUID:
685 case AUDIT_SUID: 720 case AUDIT_SUID:
@@ -801,8 +836,14 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old)
801 err = -ENOMEM; 836 err = -ENOMEM;
802 else 837 else
803 new->filterkey = fk; 838 new->filterkey = fk;
839 break;
840 case AUDIT_EXE:
841 err = audit_dupe_exe(new, old);
842 break;
804 } 843 }
805 if (err) { 844 if (err) {
845 if (new->exe)
846 audit_remove_mark(new->exe);
806 audit_free_rule(entry); 847 audit_free_rule(entry);
807 return ERR_PTR(err); 848 return ERR_PTR(err);
808 } 849 }
@@ -863,7 +904,7 @@ static inline int audit_add_rule(struct audit_entry *entry)
863 struct audit_watch *watch = entry->rule.watch; 904 struct audit_watch *watch = entry->rule.watch;
864 struct audit_tree *tree = entry->rule.tree; 905 struct audit_tree *tree = entry->rule.tree;
865 struct list_head *list; 906 struct list_head *list;
866 int err; 907 int err = 0;
867#ifdef CONFIG_AUDITSYSCALL 908#ifdef CONFIG_AUDITSYSCALL
868 int dont_count = 0; 909 int dont_count = 0;
869 910
@@ -881,7 +922,7 @@ static inline int audit_add_rule(struct audit_entry *entry)
881 /* normally audit_add_tree_rule() will free it on failure */ 922 /* normally audit_add_tree_rule() will free it on failure */
882 if (tree) 923 if (tree)
883 audit_put_tree(tree); 924 audit_put_tree(tree);
884 goto error; 925 return err;
885 } 926 }
886 927
887 if (watch) { 928 if (watch) {
@@ -895,14 +936,14 @@ static inline int audit_add_rule(struct audit_entry *entry)
895 */ 936 */
896 if (tree) 937 if (tree)
897 audit_put_tree(tree); 938 audit_put_tree(tree);
898 goto error; 939 return err;
899 } 940 }
900 } 941 }
901 if (tree) { 942 if (tree) {
902 err = audit_add_tree_rule(&entry->rule); 943 err = audit_add_tree_rule(&entry->rule);
903 if (err) { 944 if (err) {
904 mutex_unlock(&audit_filter_mutex); 945 mutex_unlock(&audit_filter_mutex);
905 goto error; 946 return err;
906 } 947 }
907 } 948 }
908 949
@@ -933,19 +974,13 @@ static inline int audit_add_rule(struct audit_entry *entry)
933#endif 974#endif
934 mutex_unlock(&audit_filter_mutex); 975 mutex_unlock(&audit_filter_mutex);
935 976
936 return 0;
937
938error:
939 if (watch)
940 audit_put_watch(watch); /* tmp watch, matches initial get */
941 return err; 977 return err;
942} 978}
943 979
944/* Remove an existing rule from filterlist. */ 980/* Remove an existing rule from filterlist. */
945static inline int audit_del_rule(struct audit_entry *entry) 981int audit_del_rule(struct audit_entry *entry)
946{ 982{
947 struct audit_entry *e; 983 struct audit_entry *e;
948 struct audit_watch *watch = entry->rule.watch;
949 struct audit_tree *tree = entry->rule.tree; 984 struct audit_tree *tree = entry->rule.tree;
950 struct list_head *list; 985 struct list_head *list;
951 int ret = 0; 986 int ret = 0;
@@ -961,7 +996,6 @@ static inline int audit_del_rule(struct audit_entry *entry)
961 mutex_lock(&audit_filter_mutex); 996 mutex_lock(&audit_filter_mutex);
962 e = audit_find_rule(entry, &list); 997 e = audit_find_rule(entry, &list);
963 if (!e) { 998 if (!e) {
964 mutex_unlock(&audit_filter_mutex);
965 ret = -ENOENT; 999 ret = -ENOENT;
966 goto out; 1000 goto out;
967 } 1001 }
@@ -972,9 +1006,8 @@ static inline int audit_del_rule(struct audit_entry *entry)
972 if (e->rule.tree) 1006 if (e->rule.tree)
973 audit_remove_tree_rule(&e->rule); 1007 audit_remove_tree_rule(&e->rule);
974 1008
975 list_del_rcu(&e->list); 1009 if (e->rule.exe)
976 list_del(&e->rule.list); 1010 audit_remove_mark_rule(&e->rule);
977 call_rcu(&e->rcu, audit_free_rule_rcu);
978 1011
979#ifdef CONFIG_AUDITSYSCALL 1012#ifdef CONFIG_AUDITSYSCALL
980 if (!dont_count) 1013 if (!dont_count)
@@ -983,11 +1016,14 @@ static inline int audit_del_rule(struct audit_entry *entry)
983 if (!audit_match_signal(entry)) 1016 if (!audit_match_signal(entry))
984 audit_signals--; 1017 audit_signals--;
985#endif 1018#endif
986 mutex_unlock(&audit_filter_mutex); 1019
1020 list_del_rcu(&e->list);
1021 list_del(&e->rule.list);
1022 call_rcu(&e->rcu, audit_free_rule_rcu);
987 1023
988out: 1024out:
989 if (watch) 1025 mutex_unlock(&audit_filter_mutex);
990 audit_put_watch(watch); /* match initial get */ 1026
991 if (tree) 1027 if (tree)
992 audit_put_tree(tree); /* that's the temporary one */ 1028 audit_put_tree(tree); /* that's the temporary one */
993 1029
@@ -1077,8 +1113,11 @@ int audit_rule_change(int type, __u32 portid, int seq, void *data,
1077 WARN_ON(1); 1113 WARN_ON(1);
1078 } 1114 }
1079 1115
1080 if (err || type == AUDIT_DEL_RULE) 1116 if (err || type == AUDIT_DEL_RULE) {
1117 if (entry->rule.exe)
1118 audit_remove_mark(entry->rule.exe);
1081 audit_free_rule(entry); 1119 audit_free_rule(entry);
1120 }
1082 1121
1083 return err; 1122 return err;
1084} 1123}
@@ -1370,6 +1409,8 @@ static int update_lsm_rule(struct audit_krule *r)
1370 return 0; 1409 return 0;
1371 1410
1372 nentry = audit_dupe_rule(r); 1411 nentry = audit_dupe_rule(r);
1412 if (entry->rule.exe)
1413 audit_remove_mark(entry->rule.exe);
1373 if (IS_ERR(nentry)) { 1414 if (IS_ERR(nentry)) {
1374 /* save the first error encountered for the 1415 /* save the first error encountered for the
1375 * return value */ 1416 * return value */
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index e85bdfd15fed..b86cc04959de 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -180,7 +180,7 @@ static int audit_match_filetype(struct audit_context *ctx, int val)
180 return 0; 180 return 0;
181 181
182 list_for_each_entry(n, &ctx->names_list, list) { 182 list_for_each_entry(n, &ctx->names_list, list) {
183 if ((n->ino != -1) && 183 if ((n->ino != AUDIT_INO_UNSET) &&
184 ((n->mode & S_IFMT) == mode)) 184 ((n->mode & S_IFMT) == mode))
185 return 1; 185 return 1;
186 } 186 }
@@ -466,6 +466,9 @@ static int audit_filter_rules(struct task_struct *tsk,
466 result = audit_comparator(ctx->ppid, f->op, f->val); 466 result = audit_comparator(ctx->ppid, f->op, f->val);
467 } 467 }
468 break; 468 break;
469 case AUDIT_EXE:
470 result = audit_exe_compare(tsk, rule->exe);
471 break;
469 case AUDIT_UID: 472 case AUDIT_UID:
470 result = audit_uid_comparator(cred->uid, f->op, f->uid); 473 result = audit_uid_comparator(cred->uid, f->op, f->uid);
471 break; 474 break;
@@ -1680,7 +1683,7 @@ static struct audit_names *audit_alloc_name(struct audit_context *context,
1680 aname->should_free = true; 1683 aname->should_free = true;
1681 } 1684 }
1682 1685
1683 aname->ino = (unsigned long)-1; 1686 aname->ino = AUDIT_INO_UNSET;
1684 aname->type = type; 1687 aname->type = type;
1685 list_add_tail(&aname->list, &context->names_list); 1688 list_add_tail(&aname->list, &context->names_list);
1686 1689
@@ -1922,7 +1925,7 @@ void __audit_inode_child(const struct inode *parent,
1922 if (inode) 1925 if (inode)
1923 audit_copy_inode(found_child, dentry, inode); 1926 audit_copy_inode(found_child, dentry, inode);
1924 else 1927 else
1925 found_child->ino = (unsigned long)-1; 1928 found_child->ino = AUDIT_INO_UNSET;
1926} 1929}
1927EXPORT_SYMBOL_GPL(__audit_inode_child); 1930EXPORT_SYMBOL_GPL(__audit_inode_child);
1928 1931