Blame view

kernel/auditfilter.c 34 KB
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  /* auditfilter.c -- filtering of audit events
   *
   * Copyright 2003-2004 Red Hat, Inc.
   * Copyright 2005 Hewlett-Packard Development Company, L.P.
   * Copyright 2005 IBM Corporation
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
f952d10ff   Richard Guy Briggs   audit: Use more c...
21
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
fe7752bab   David Woodhouse   [PATCH] Fix audit...
22
23
24
  #include <linux/kernel.h>
  #include <linux/audit.h>
  #include <linux/kthread.h>
f368c07d7   Amy Griffis   [PATCH] audit: pa...
25
26
27
  #include <linux/mutex.h>
  #include <linux/fs.h>
  #include <linux/namei.h>
fe7752bab   David Woodhouse   [PATCH] Fix audit...
28
  #include <linux/netlink.h>
f368c07d7   Amy Griffis   [PATCH] audit: pa...
29
  #include <linux/sched.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
30
  #include <linux/slab.h>
2a862b32f   Ahmed S. Darwish   Audit: use new LS...
31
  #include <linux/security.h>
48095d991   Eric W. Biederman   audit: Use struct...
32
  #include <net/net_namespace.h>
6f285b19d   Eric W. Biederman   audit: Send repli...
33
  #include <net/sock.h>
fe7752bab   David Woodhouse   [PATCH] Fix audit...
34
  #include "audit.h"
f368c07d7   Amy Griffis   [PATCH] audit: pa...
35
36
37
38
  /*
   * Locking model:
   *
   * audit_filter_mutex:
725131efa   Scott Matheina   audit: fix commen...
39
40
41
42
43
44
45
   *		Synchronizes writes and blocking reads of audit's filterlist
   *		data.  Rcu is used to traverse the filterlist and access
   *		contents of structs audit_entry, audit_watch and opaque
   *		LSM rules during filtering.  If modified, these structures
   *		must be copied and replace their counterparts in the filterlist.
   *		An audit_parent struct is not accessed during filtering, so may
   *		be written directly provided audit_filter_mutex is held.
f368c07d7   Amy Griffis   [PATCH] audit: pa...
46
   */
f368c07d7   Amy Griffis   [PATCH] audit: pa...
47
  /* Audit filter lists, defined in <linux/audit.h> */
fe7752bab   David Woodhouse   [PATCH] Fix audit...
48
49
50
51
52
53
54
55
56
57
58
  struct list_head audit_filter_list[AUDIT_NR_FILTERS] = {
  	LIST_HEAD_INIT(audit_filter_list[0]),
  	LIST_HEAD_INIT(audit_filter_list[1]),
  	LIST_HEAD_INIT(audit_filter_list[2]),
  	LIST_HEAD_INIT(audit_filter_list[3]),
  	LIST_HEAD_INIT(audit_filter_list[4]),
  	LIST_HEAD_INIT(audit_filter_list[5]),
  #if AUDIT_NR_FILTERS != 6
  #error Fix audit_filter_list initialiser
  #endif
  };
e45aa212e   Al Viro   audit rules order...
59
60
61
62
63
64
65
66
  static struct list_head audit_rules_list[AUDIT_NR_FILTERS] = {
  	LIST_HEAD_INIT(audit_rules_list[0]),
  	LIST_HEAD_INIT(audit_rules_list[1]),
  	LIST_HEAD_INIT(audit_rules_list[2]),
  	LIST_HEAD_INIT(audit_rules_list[3]),
  	LIST_HEAD_INIT(audit_rules_list[4]),
  	LIST_HEAD_INIT(audit_rules_list[5]),
  };
fe7752bab   David Woodhouse   [PATCH] Fix audit...
67

74c3cbe33   Al Viro   [PATCH] audit: wa...
68
  DEFINE_MUTEX(audit_filter_mutex);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
69

219ca3942   Richard Guy Briggs   audit: use union ...
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
  static void audit_free_lsm_field(struct audit_field *f)
  {
  	switch (f->type) {
  	case AUDIT_SUBJ_USER:
  	case AUDIT_SUBJ_ROLE:
  	case AUDIT_SUBJ_TYPE:
  	case AUDIT_SUBJ_SEN:
  	case AUDIT_SUBJ_CLR:
  	case AUDIT_OBJ_USER:
  	case AUDIT_OBJ_ROLE:
  	case AUDIT_OBJ_TYPE:
  	case AUDIT_OBJ_LEV_LOW:
  	case AUDIT_OBJ_LEV_HIGH:
  		kfree(f->lsm_str);
  		security_audit_rule_free(f->lsm_rule);
  	}
  }
93315ed6d   Amy Griffis   [PATCH] audit str...
87
  static inline void audit_free_rule(struct audit_entry *e)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
88
  {
3dc7e3153   Darrel Goeddel   [PATCH] support f...
89
  	int i;
c28bb7da7   Zhenwen Xu   make the e->rule....
90
  	struct audit_krule *erule = &e->rule;
ae7b8f410   Eric Paris   Audit: clean up t...
91

f368c07d7   Amy Griffis   [PATCH] audit: pa...
92
  	/* some rules don't have associated watches */
c28bb7da7   Zhenwen Xu   make the e->rule....
93
94
95
  	if (erule->watch)
  		audit_put_watch(erule->watch);
  	if (erule->fields)
219ca3942   Richard Guy Briggs   audit: use union ...
96
97
  		for (i = 0; i < erule->field_count; i++)
  			audit_free_lsm_field(&erule->fields[i]);
c28bb7da7   Zhenwen Xu   make the e->rule....
98
99
  	kfree(erule->fields);
  	kfree(erule->filterkey);
93315ed6d   Amy Griffis   [PATCH] audit str...
100
101
  	kfree(e);
  }
74c3cbe33   Al Viro   [PATCH] audit: wa...
102
  void audit_free_rule_rcu(struct rcu_head *head)
93315ed6d   Amy Griffis   [PATCH] audit str...
103
104
105
106
  {
  	struct audit_entry *e = container_of(head, struct audit_entry, rcu);
  	audit_free_rule(e);
  }
3dc7e3153   Darrel Goeddel   [PATCH] support f...
107
108
109
110
111
112
113
114
115
  /* Initialize an audit filterlist entry. */
  static inline struct audit_entry *audit_init_entry(u32 field_count)
  {
  	struct audit_entry *entry;
  	struct audit_field *fields;
  
  	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
  	if (unlikely(!entry))
  		return NULL;
bab5e2d65   Fabian Frederick   kernel/auditfilte...
116
  	fields = kcalloc(field_count, sizeof(*fields), GFP_KERNEL);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
117
118
119
120
121
122
123
124
  	if (unlikely(!fields)) {
  		kfree(entry);
  		return NULL;
  	}
  	entry->rule.fields = fields;
  
  	return entry;
  }
93315ed6d   Amy Griffis   [PATCH] audit str...
125
126
  /* Unpack a filter field's string representation from user-space
   * buffer. */
74c3cbe33   Al Viro   [PATCH] audit: wa...
127
  char *audit_unpack_string(void **bufp, size_t *remain, size_t len)
93315ed6d   Amy Griffis   [PATCH] audit str...
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  {
  	char *str;
  
  	if (!*bufp || (len == 0) || (len > *remain))
  		return ERR_PTR(-EINVAL);
  
  	/* Of the currently implemented string fields, PATH_MAX
  	 * defines the longest valid length.
  	 */
  	if (len > PATH_MAX)
  		return ERR_PTR(-ENAMETOOLONG);
  
  	str = kmalloc(len + 1, GFP_KERNEL);
  	if (unlikely(!str))
  		return ERR_PTR(-ENOMEM);
  
  	memcpy(str, *bufp, len);
  	str[len] = 0;
  	*bufp += len;
  	*remain -= len;
  
  	return str;
  }
fd97646b0   Wei Yuan   audit: Fix typo i...
151
  /* Translate an inode field to kernel representation. */
f368c07d7   Amy Griffis   [PATCH] audit: pa...
152
153
154
155
  static inline int audit_to_inode(struct audit_krule *krule,
  				 struct audit_field *f)
  {
  	if (krule->listnr != AUDIT_FILTER_EXIT ||
3639f1706   Richard Guy Briggs   audit: put rule e...
156
  	    krule->inode_f || krule->watch || krule->tree ||
5af75d8d5   Al Viro   audit: validate c...
157
  	    (f->op != Audit_equal && f->op != Audit_not_equal))
f368c07d7   Amy Griffis   [PATCH] audit: pa...
158
159
160
161
162
  		return -EINVAL;
  
  	krule->inode_f = f;
  	return 0;
  }
b915543b4   Al Viro   [PATCH] audit sys...
163
164
165
166
  static __u32 *classes[AUDIT_SYSCALL_CLASSES];
  
  int __init audit_register_class(int class, unsigned *list)
  {
bab5e2d65   Fabian Frederick   kernel/auditfilte...
167
  	__u32 *p = kcalloc(AUDIT_BITMASK_SIZE, sizeof(__u32), GFP_KERNEL);
b915543b4   Al Viro   [PATCH] audit sys...
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
  	if (!p)
  		return -ENOMEM;
  	while (*list != ~0U) {
  		unsigned n = *list++;
  		if (n >= AUDIT_BITMASK_SIZE * 32 - AUDIT_SYSCALL_CLASSES) {
  			kfree(p);
  			return -EINVAL;
  		}
  		p[AUDIT_WORD(n)] |= AUDIT_BIT(n);
  	}
  	if (class >= AUDIT_SYSCALL_CLASSES || classes[class]) {
  		kfree(p);
  		return -EINVAL;
  	}
  	classes[class] = p;
  	return 0;
  }
55669bfa1   Al Viro   [PATCH] audit: AU...
185
186
  int audit_match_class(int class, unsigned syscall)
  {
c926e4f43   Klaus Weidner   [PATCH] audit: fi...
187
  	if (unlikely(syscall >= AUDIT_BITMASK_SIZE * 32))
55669bfa1   Al Viro   [PATCH] audit: AU...
188
189
190
191
192
  		return 0;
  	if (unlikely(class >= AUDIT_SYSCALL_CLASSES || !classes[class]))
  		return 0;
  	return classes[class][AUDIT_WORD(syscall)] & AUDIT_BIT(syscall);
  }
327b9eebb   Al Viro   audit_match_signa...
193
  #ifdef CONFIG_AUDITSYSCALL
e54dc2431   Amy Griffis   [PATCH] audit sig...
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
219
220
221
222
223
224
225
226
227
228
229
  static inline int audit_match_class_bits(int class, u32 *mask)
  {
  	int i;
  
  	if (classes[class]) {
  		for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
  			if (mask[i] & classes[class][i])
  				return 0;
  	}
  	return 1;
  }
  
  static int audit_match_signal(struct audit_entry *entry)
  {
  	struct audit_field *arch = entry->rule.arch_f;
  
  	if (!arch) {
  		/* When arch is unspecified, we must check both masks on biarch
  		 * as syscall number alone is ambiguous. */
  		return (audit_match_class_bits(AUDIT_CLASS_SIGNAL,
  					       entry->rule.mask) &&
  			audit_match_class_bits(AUDIT_CLASS_SIGNAL_32,
  					       entry->rule.mask));
  	}
  
  	switch(audit_classify_arch(arch->val)) {
  	case 0: /* native */
  		return (audit_match_class_bits(AUDIT_CLASS_SIGNAL,
  					       entry->rule.mask));
  	case 1: /* 32bit on biarch */
  		return (audit_match_class_bits(AUDIT_CLASS_SIGNAL_32,
  					       entry->rule.mask));
  	default:
  		return 1;
  	}
  }
327b9eebb   Al Viro   audit_match_signa...
230
  #endif
e54dc2431   Amy Griffis   [PATCH] audit sig...
231

93315ed6d   Amy Griffis   [PATCH] audit str...
232
  /* Common user-space to kernel rule translation. */
56c4911ae   Eric Paris   audit: do not cas...
233
  static inline struct audit_entry *audit_to_entry_common(struct audit_rule_data *rule)
93315ed6d   Amy Griffis   [PATCH] audit str...
234
235
236
  {
  	unsigned listnr;
  	struct audit_entry *entry;
93315ed6d   Amy Griffis   [PATCH] audit str...
237
238
239
240
241
242
243
  	int i, err;
  
  	err = -EINVAL;
  	listnr = rule->flags & ~AUDIT_FILTER_PREPEND;
  	switch(listnr) {
  	default:
  		goto exit_err;
93315ed6d   Amy Griffis   [PATCH] audit str...
244
245
  #ifdef CONFIG_AUDITSYSCALL
  	case AUDIT_FILTER_ENTRY:
7ff68e53e   Eric Paris   audit: reject ent...
246
247
  		if (rule->action == AUDIT_ALWAYS)
  			goto exit_err;
93315ed6d   Amy Griffis   [PATCH] audit str...
248
249
250
  	case AUDIT_FILTER_EXIT:
  	case AUDIT_FILTER_TASK:
  #endif
7ff68e53e   Eric Paris   audit: reject ent...
251
252
  	case AUDIT_FILTER_USER:
  	case AUDIT_FILTER_TYPE:
93315ed6d   Amy Griffis   [PATCH] audit str...
253
254
  		;
  	}
014149cce   Al Viro   [PATCH] deprecate...
255
  	if (unlikely(rule->action == AUDIT_POSSIBLE)) {
f952d10ff   Richard Guy Briggs   audit: Use more c...
256
257
  		pr_err("AUDIT_POSSIBLE is deprecated
  ");
014149cce   Al Viro   [PATCH] deprecate...
258
259
260
  		goto exit_err;
  	}
  	if (rule->action != AUDIT_NEVER && rule->action != AUDIT_ALWAYS)
93315ed6d   Amy Griffis   [PATCH] audit str...
261
262
263
264
265
  		goto exit_err;
  	if (rule->field_count > AUDIT_MAX_FIELDS)
  		goto exit_err;
  
  	err = -ENOMEM;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
266
267
  	entry = audit_init_entry(rule->field_count);
  	if (!entry)
93315ed6d   Amy Griffis   [PATCH] audit str...
268
  		goto exit_err;
93315ed6d   Amy Griffis   [PATCH] audit str...
269
270
271
272
273
  
  	entry->rule.flags = rule->flags & AUDIT_FILTER_PREPEND;
  	entry->rule.listnr = listnr;
  	entry->rule.action = rule->action;
  	entry->rule.field_count = rule->field_count;
93315ed6d   Amy Griffis   [PATCH] audit str...
274
275
276
  
  	for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
  		entry->rule.mask[i] = rule->mask[i];
b915543b4   Al Viro   [PATCH] audit sys...
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
  	for (i = 0; i < AUDIT_SYSCALL_CLASSES; i++) {
  		int bit = AUDIT_BITMASK_SIZE * 32 - i - 1;
  		__u32 *p = &entry->rule.mask[AUDIT_WORD(bit)];
  		__u32 *class;
  
  		if (!(*p & AUDIT_BIT(bit)))
  			continue;
  		*p &= ~AUDIT_BIT(bit);
  		class = classes[i];
  		if (class) {
  			int j;
  			for (j = 0; j < AUDIT_BITMASK_SIZE; j++)
  				entry->rule.mask[j] |= class[j];
  		}
  	}
93315ed6d   Amy Griffis   [PATCH] audit str...
292
293
294
295
296
  	return entry;
  
  exit_err:
  	return ERR_PTR(err);
  }
5af75d8d5   Al Viro   audit: validate c...
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
  static u32 audit_ops[] =
  {
  	[Audit_equal] = AUDIT_EQUAL,
  	[Audit_not_equal] = AUDIT_NOT_EQUAL,
  	[Audit_bitmask] = AUDIT_BIT_MASK,
  	[Audit_bittest] = AUDIT_BIT_TEST,
  	[Audit_lt] = AUDIT_LESS_THAN,
  	[Audit_gt] = AUDIT_GREATER_THAN,
  	[Audit_le] = AUDIT_LESS_THAN_OR_EQUAL,
  	[Audit_ge] = AUDIT_GREATER_THAN_OR_EQUAL,
  };
  
  static u32 audit_to_op(u32 op)
  {
  	u32 n;
  	for (n = Audit_equal; n < Audit_bad && audit_ops[n] != op; n++)
  		;
  	return n;
  }
ab61d38ed   Eric Paris   audit: make valid...
316
  /* check if an audit field is valid */
62062cf8a   Eric Paris   audit: allow chec...
317
  static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
93315ed6d   Amy Griffis   [PATCH] audit str...
318
  {
62062cf8a   Eric Paris   audit: allow chec...
319
320
321
322
323
324
325
  	switch(f->type) {
  	case AUDIT_MSGTYPE:
  		if (entry->rule.listnr != AUDIT_FILTER_TYPE &&
  		    entry->rule.listnr != AUDIT_FILTER_USER)
  			return -EINVAL;
  		break;
  	};
93315ed6d   Amy Griffis   [PATCH] audit str...
326

ab61d38ed   Eric Paris   audit: make valid...
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
  	switch(f->type) {
  	default:
  		return -EINVAL;
  	case AUDIT_UID:
  	case AUDIT_EUID:
  	case AUDIT_SUID:
  	case AUDIT_FSUID:
  	case AUDIT_LOGINUID:
  	case AUDIT_OBJ_UID:
  	case AUDIT_GID:
  	case AUDIT_EGID:
  	case AUDIT_SGID:
  	case AUDIT_FSGID:
  	case AUDIT_OBJ_GID:
  	case AUDIT_PID:
  	case AUDIT_PERS:
  	case AUDIT_MSGTYPE:
  	case AUDIT_PPID:
  	case AUDIT_DEVMAJOR:
  	case AUDIT_DEVMINOR:
  	case AUDIT_EXIT:
  	case AUDIT_SUCCESS:
78122037b   Eric Paris   audit: do not rej...
349
  	case AUDIT_INODE:
ab61d38ed   Eric Paris   audit: make valid...
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
  		/* bit ops are only useful on syscall args */
  		if (f->op == Audit_bitmask || f->op == Audit_bittest)
  			return -EINVAL;
  		break;
  	case AUDIT_ARG0:
  	case AUDIT_ARG1:
  	case AUDIT_ARG2:
  	case AUDIT_ARG3:
  	case AUDIT_SUBJ_USER:
  	case AUDIT_SUBJ_ROLE:
  	case AUDIT_SUBJ_TYPE:
  	case AUDIT_SUBJ_SEN:
  	case AUDIT_SUBJ_CLR:
  	case AUDIT_OBJ_USER:
  	case AUDIT_OBJ_ROLE:
  	case AUDIT_OBJ_TYPE:
  	case AUDIT_OBJ_LEV_LOW:
  	case AUDIT_OBJ_LEV_HIGH:
  	case AUDIT_WATCH:
  	case AUDIT_DIR:
  	case AUDIT_FILTERKEY:
  		break;
780a7654c   Eric W. Biederman   audit: Make testi...
372
373
374
375
  	case AUDIT_LOGINUID_SET:
  		if ((f->val != 0) && (f->val != 1))
  			return -EINVAL;
  	/* FALL THROUGH */
ab61d38ed   Eric Paris   audit: make valid...
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
  	case AUDIT_ARCH:
  		if (f->op != Audit_not_equal && f->op != Audit_equal)
  			return -EINVAL;
  		break;
  	case AUDIT_PERM:
  		if (f->val & ~15)
  			return -EINVAL;
  		break;
  	case AUDIT_FILETYPE:
  		if (f->val & ~S_IFMT)
  			return -EINVAL;
  		break;
  	case AUDIT_FIELD_COMPARE:
  		if (f->val > AUDIT_MAX_FIELD_COMPARE)
  			return -EINVAL;
  		break;
34d99af52   Richard Guy Briggs   audit: implement ...
392
393
394
395
396
397
  	case AUDIT_EXE:
  		if (f->op != Audit_equal)
  			return -EINVAL;
  		if (entry->rule.listnr != AUDIT_FILTER_EXIT)
  			return -EINVAL;
  		break;
ab61d38ed   Eric Paris   audit: make valid...
398
  	};
62062cf8a   Eric Paris   audit: allow chec...
399
  	return 0;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
400
  }
fd97646b0   Wei Yuan   audit: Fix typo i...
401
  /* Translate struct audit_rule_data to kernel's rule representation. */
93315ed6d   Amy Griffis   [PATCH] audit str...
402
403
  static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
  					       size_t datasz)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
404
  {
93315ed6d   Amy Griffis   [PATCH] audit str...
405
406
407
  	int err = 0;
  	struct audit_entry *entry;
  	void *bufp;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
408
  	size_t remain = datasz - sizeof(struct audit_rule_data);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
409
  	int i;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
410
  	char *str;
34d99af52   Richard Guy Briggs   audit: implement ...
411
  	struct audit_fsnotify_mark *audit_mark;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
412

56c4911ae   Eric Paris   audit: do not cas...
413
  	entry = audit_to_entry_common(data);
93315ed6d   Amy Griffis   [PATCH] audit str...
414
415
  	if (IS_ERR(entry))
  		goto exit_nofree;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
416

93315ed6d   Amy Griffis   [PATCH] audit str...
417
  	bufp = data->buf;
93315ed6d   Amy Griffis   [PATCH] audit str...
418
419
420
421
  	for (i = 0; i < data->field_count; i++) {
  		struct audit_field *f = &entry->rule.fields[i];
  
  		err = -EINVAL;
5af75d8d5   Al Viro   audit: validate c...
422
423
424
  
  		f->op = audit_to_op(data->fieldflags[i]);
  		if (f->op == Audit_bad)
93315ed6d   Amy Griffis   [PATCH] audit str...
425
  			goto exit_free;
93315ed6d   Amy Griffis   [PATCH] audit str...
426
  		f->type = data->fields[i];
3dc7e3153   Darrel Goeddel   [PATCH] support f...
427
  		f->val = data->values[i];
62062cf8a   Eric Paris   audit: allow chec...
428

780a7654c   Eric W. Biederman   audit: Make testi...
429
  		/* Support legacy tests for a valid loginuid */
42f74461a   Richard Guy Briggs   audit: change dec...
430
  		if ((f->type == AUDIT_LOGINUID) && (f->val == AUDIT_UID_UNSET)) {
780a7654c   Eric W. Biederman   audit: Make testi...
431
432
  			f->type = AUDIT_LOGINUID_SET;
  			f->val = 0;
041d7b98f   Richard Guy Briggs   audit: restore AU...
433
  			entry->rule.pflags |= AUDIT_LOGINUID_LEGACY;
f1dc4867f   Richard Guy Briggs   audit: anchor all...
434
  		}
62062cf8a   Eric Paris   audit: allow chec...
435
436
437
438
439
  		err = audit_field_valid(entry, f);
  		if (err)
  			goto exit_free;
  
  		err = -EINVAL;
ab61d38ed   Eric Paris   audit: make valid...
440
  		switch (f->type) {
780a7654c   Eric W. Biederman   audit: Make testi...
441
  		case AUDIT_LOGINUID:
0a73dccc4   Al Viro   [PATCH] validate ...
442
443
444
445
  		case AUDIT_UID:
  		case AUDIT_EUID:
  		case AUDIT_SUID:
  		case AUDIT_FSUID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
446
  		case AUDIT_OBJ_UID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
447
448
449
450
  			f->uid = make_kuid(current_user_ns(), f->val);
  			if (!uid_valid(f->uid))
  				goto exit_free;
  			break;
0a73dccc4   Al Viro   [PATCH] validate ...
451
452
453
454
  		case AUDIT_GID:
  		case AUDIT_EGID:
  		case AUDIT_SGID:
  		case AUDIT_FSGID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
455
  		case AUDIT_OBJ_GID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
456
457
458
459
  			f->gid = make_kgid(current_user_ns(), f->val);
  			if (!gid_valid(f->gid))
  				goto exit_free;
  			break;
e54dc2431   Amy Griffis   [PATCH] audit sig...
460
461
462
  		case AUDIT_ARCH:
  			entry->rule.arch_f = f;
  			break;
3a6b9f85c   Darrel Goeddel   [PATCH] audit: re...
463
464
465
466
467
  		case AUDIT_SUBJ_USER:
  		case AUDIT_SUBJ_ROLE:
  		case AUDIT_SUBJ_TYPE:
  		case AUDIT_SUBJ_SEN:
  		case AUDIT_SUBJ_CLR:
6e5a2d1d3   Darrel Goeddel   [PATCH] audit: su...
468
469
470
471
472
  		case AUDIT_OBJ_USER:
  		case AUDIT_OBJ_ROLE:
  		case AUDIT_OBJ_TYPE:
  		case AUDIT_OBJ_LEV_LOW:
  		case AUDIT_OBJ_LEV_HIGH:
3dc7e3153   Darrel Goeddel   [PATCH] support f...
473
474
475
476
  			str = audit_unpack_string(&bufp, &remain, f->val);
  			if (IS_ERR(str))
  				goto exit_free;
  			entry->rule.buflen += f->val;
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
477
  			err = security_audit_rule_init(f->type, f->op, str,
04305e4af   Ahmed S. Darwish   Audit: Final rena...
478
  						       (void **)&f->lsm_rule);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
479
480
481
  			/* Keep currently invalid fields around in case they
  			 * become valid after a policy reload. */
  			if (err == -EINVAL) {
f952d10ff   Richard Guy Briggs   audit: Use more c...
482
483
484
  				pr_warn("audit rule for LSM \'%s\' is invalid
  ",
  					str);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
485
486
487
488
489
490
  				err = 0;
  			}
  			if (err) {
  				kfree(str);
  				goto exit_free;
  			} else
04305e4af   Ahmed S. Darwish   Audit: Final rena...
491
  				f->lsm_str = str;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
492
  			break;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
493
494
495
496
497
498
499
500
501
502
503
504
  		case AUDIT_WATCH:
  			str = audit_unpack_string(&bufp, &remain, f->val);
  			if (IS_ERR(str))
  				goto exit_free;
  			entry->rule.buflen += f->val;
  
  			err = audit_to_watch(&entry->rule, str, f->val, f->op);
  			if (err) {
  				kfree(str);
  				goto exit_free;
  			}
  			break;
74c3cbe33   Al Viro   [PATCH] audit: wa...
505
506
507
508
509
510
511
512
513
514
515
  		case AUDIT_DIR:
  			str = audit_unpack_string(&bufp, &remain, f->val);
  			if (IS_ERR(str))
  				goto exit_free;
  			entry->rule.buflen += f->val;
  
  			err = audit_make_tree(&entry->rule, str, f->op);
  			kfree(str);
  			if (err)
  				goto exit_free;
  			break;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
516
517
518
519
520
  		case AUDIT_INODE:
  			err = audit_to_inode(&entry->rule, f);
  			if (err)
  				goto exit_free;
  			break;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
521
  		case AUDIT_FILTERKEY:
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
522
523
524
525
526
527
528
529
  			if (entry->rule.filterkey || f->val > AUDIT_MAX_KEY_LEN)
  				goto exit_free;
  			str = audit_unpack_string(&bufp, &remain, f->val);
  			if (IS_ERR(str))
  				goto exit_free;
  			entry->rule.buflen += f->val;
  			entry->rule.filterkey = str;
  			break;
34d99af52   Richard Guy Briggs   audit: implement ...
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
  		case AUDIT_EXE:
  			if (entry->rule.exe || f->val > PATH_MAX)
  				goto exit_free;
  			str = audit_unpack_string(&bufp, &remain, f->val);
  			if (IS_ERR(str)) {
  				err = PTR_ERR(str);
  				goto exit_free;
  			}
  			entry->rule.buflen += f->val;
  
  			audit_mark = audit_alloc_mark(&entry->rule, str, f->val);
  			if (IS_ERR(audit_mark)) {
  				kfree(str);
  				err = PTR_ERR(audit_mark);
  				goto exit_free;
  			}
  			entry->rule.exe = audit_mark;
  			break;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
548
549
  		}
  	}
5af75d8d5   Al Viro   audit: validate c...
550
551
  	if (entry->rule.inode_f && entry->rule.inode_f->op == Audit_not_equal)
  		entry->rule.inode_f = NULL;
93315ed6d   Amy Griffis   [PATCH] audit str...
552
553
554
555
556
  
  exit_nofree:
  	return entry;
  
  exit_free:
373e0f340   Chen Gang   kernel/auditfilte...
557
558
  	if (entry->rule.tree)
  		audit_put_tree(entry->rule.tree); /* that's the temporary one */
34d99af52   Richard Guy Briggs   audit: implement ...
559
560
  	if (entry->rule.exe)
  		audit_remove_mark(entry->rule.exe); /* that's the template one */
93315ed6d   Amy Griffis   [PATCH] audit str...
561
562
563
564
565
  	audit_free_rule(entry);
  	return ERR_PTR(err);
  }
  
  /* Pack a filter field's string representation into data block. */
74c3cbe33   Al Viro   [PATCH] audit: wa...
566
  static inline size_t audit_pack_string(void **bufp, const char *str)
93315ed6d   Amy Griffis   [PATCH] audit str...
567
568
569
570
571
572
573
574
  {
  	size_t len = strlen(str);
  
  	memcpy(*bufp, str, len);
  	*bufp += len;
  
  	return len;
  }
fd97646b0   Wei Yuan   audit: Fix typo i...
575
  /* Translate kernel rule representation to struct audit_rule_data. */
93315ed6d   Amy Griffis   [PATCH] audit str...
576
577
578
579
580
581
582
583
  static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
  {
  	struct audit_rule_data *data;
  	void *bufp;
  	int i;
  
  	data = kmalloc(sizeof(*data) + krule->buflen, GFP_KERNEL);
  	if (unlikely(!data))
0a3b483e8   Amy Griffis   [PATCH] fix audit...
584
  		return NULL;
93315ed6d   Amy Griffis   [PATCH] audit str...
585
586
587
588
589
590
591
592
593
594
  	memset(data, 0, sizeof(*data));
  
  	data->flags = krule->flags | krule->listnr;
  	data->action = krule->action;
  	data->field_count = krule->field_count;
  	bufp = data->buf;
  	for (i = 0; i < data->field_count; i++) {
  		struct audit_field *f = &krule->fields[i];
  
  		data->fields[i] = f->type;
5af75d8d5   Al Viro   audit: validate c...
595
  		data->fieldflags[i] = audit_ops[f->op];
93315ed6d   Amy Griffis   [PATCH] audit str...
596
  		switch(f->type) {
3a6b9f85c   Darrel Goeddel   [PATCH] audit: re...
597
598
599
600
601
  		case AUDIT_SUBJ_USER:
  		case AUDIT_SUBJ_ROLE:
  		case AUDIT_SUBJ_TYPE:
  		case AUDIT_SUBJ_SEN:
  		case AUDIT_SUBJ_CLR:
6e5a2d1d3   Darrel Goeddel   [PATCH] audit: su...
602
603
604
605
606
  		case AUDIT_OBJ_USER:
  		case AUDIT_OBJ_ROLE:
  		case AUDIT_OBJ_TYPE:
  		case AUDIT_OBJ_LEV_LOW:
  		case AUDIT_OBJ_LEV_HIGH:
3dc7e3153   Darrel Goeddel   [PATCH] support f...
607
  			data->buflen += data->values[i] =
04305e4af   Ahmed S. Darwish   Audit: Final rena...
608
  				audit_pack_string(&bufp, f->lsm_str);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
609
  			break;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
610
611
  		case AUDIT_WATCH:
  			data->buflen += data->values[i] =
cfcad62c7   Eric Paris   audit: seperate a...
612
613
  				audit_pack_string(&bufp,
  						  audit_watch_path(krule->watch));
f368c07d7   Amy Griffis   [PATCH] audit: pa...
614
  			break;
74c3cbe33   Al Viro   [PATCH] audit: wa...
615
616
617
618
619
  		case AUDIT_DIR:
  			data->buflen += data->values[i] =
  				audit_pack_string(&bufp,
  						  audit_tree_path(krule->tree));
  			break;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
620
621
622
623
  		case AUDIT_FILTERKEY:
  			data->buflen += data->values[i] =
  				audit_pack_string(&bufp, krule->filterkey);
  			break;
34d99af52   Richard Guy Briggs   audit: implement ...
624
625
626
627
  		case AUDIT_EXE:
  			data->buflen += data->values[i] =
  				audit_pack_string(&bufp, audit_mark_path(krule->exe));
  			break;
041d7b98f   Richard Guy Briggs   audit: restore AU...
628
629
630
631
632
633
634
  		case AUDIT_LOGINUID_SET:
  			if (krule->pflags & AUDIT_LOGINUID_LEGACY && !f->val) {
  				data->fields[i] = AUDIT_LOGINUID;
  				data->values[i] = AUDIT_UID_UNSET;
  				break;
  			}
  			/* fallthrough if set */
93315ed6d   Amy Griffis   [PATCH] audit str...
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
  		default:
  			data->values[i] = f->val;
  		}
  	}
  	for (i = 0; i < AUDIT_BITMASK_SIZE; i++) data->mask[i] = krule->mask[i];
  
  	return data;
  }
  
  /* Compare two rules in kernel format.  Considered success if rules
   * don't match. */
  static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
  {
  	int i;
  
  	if (a->flags != b->flags ||
041d7b98f   Richard Guy Briggs   audit: restore AU...
651
  	    a->pflags != b->pflags ||
93315ed6d   Amy Griffis   [PATCH] audit str...
652
653
654
  	    a->listnr != b->listnr ||
  	    a->action != b->action ||
  	    a->field_count != b->field_count)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
655
656
657
  		return 1;
  
  	for (i = 0; i < a->field_count; i++) {
93315ed6d   Amy Griffis   [PATCH] audit str...
658
659
  		if (a->fields[i].type != b->fields[i].type ||
  		    a->fields[i].op != b->fields[i].op)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
660
  			return 1;
93315ed6d   Amy Griffis   [PATCH] audit str...
661
662
  
  		switch(a->fields[i].type) {
3a6b9f85c   Darrel Goeddel   [PATCH] audit: re...
663
664
665
666
667
  		case AUDIT_SUBJ_USER:
  		case AUDIT_SUBJ_ROLE:
  		case AUDIT_SUBJ_TYPE:
  		case AUDIT_SUBJ_SEN:
  		case AUDIT_SUBJ_CLR:
6e5a2d1d3   Darrel Goeddel   [PATCH] audit: su...
668
669
670
671
672
  		case AUDIT_OBJ_USER:
  		case AUDIT_OBJ_ROLE:
  		case AUDIT_OBJ_TYPE:
  		case AUDIT_OBJ_LEV_LOW:
  		case AUDIT_OBJ_LEV_HIGH:
04305e4af   Ahmed S. Darwish   Audit: Final rena...
673
  			if (strcmp(a->fields[i].lsm_str, b->fields[i].lsm_str))
3dc7e3153   Darrel Goeddel   [PATCH] support f...
674
675
  				return 1;
  			break;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
676
  		case AUDIT_WATCH:
cfcad62c7   Eric Paris   audit: seperate a...
677
678
  			if (strcmp(audit_watch_path(a->watch),
  				   audit_watch_path(b->watch)))
f368c07d7   Amy Griffis   [PATCH] audit: pa...
679
680
  				return 1;
  			break;
74c3cbe33   Al Viro   [PATCH] audit: wa...
681
682
683
684
685
  		case AUDIT_DIR:
  			if (strcmp(audit_tree_path(a->tree),
  				   audit_tree_path(b->tree)))
  				return 1;
  			break;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
686
687
688
689
690
  		case AUDIT_FILTERKEY:
  			/* both filterkeys exist based on above type compare */
  			if (strcmp(a->filterkey, b->filterkey))
  				return 1;
  			break;
34d99af52   Richard Guy Briggs   audit: implement ...
691
692
693
694
695
696
  		case AUDIT_EXE:
  			/* both paths exist based on above type compare */
  			if (strcmp(audit_mark_path(a->exe),
  				   audit_mark_path(b->exe)))
  				return 1;
  			break;
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
  		case AUDIT_UID:
  		case AUDIT_EUID:
  		case AUDIT_SUID:
  		case AUDIT_FSUID:
  		case AUDIT_LOGINUID:
  		case AUDIT_OBJ_UID:
  			if (!uid_eq(a->fields[i].uid, b->fields[i].uid))
  				return 1;
  			break;
  		case AUDIT_GID:
  		case AUDIT_EGID:
  		case AUDIT_SGID:
  		case AUDIT_FSGID:
  		case AUDIT_OBJ_GID:
  			if (!gid_eq(a->fields[i].gid, b->fields[i].gid))
  				return 1;
  			break;
93315ed6d   Amy Griffis   [PATCH] audit str...
714
715
716
717
  		default:
  			if (a->fields[i].val != b->fields[i].val)
  				return 1;
  		}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
718
719
720
721
722
723
724
725
  	}
  
  	for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
  		if (a->mask[i] != b->mask[i])
  			return 1;
  
  	return 0;
  }
04305e4af   Ahmed S. Darwish   Audit: Final rena...
726
  /* Duplicate LSM field information.  The lsm_rule is opaque, so must be
3dc7e3153   Darrel Goeddel   [PATCH] support f...
727
   * re-initialized. */
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
728
  static inline int audit_dupe_lsm_field(struct audit_field *df,
3dc7e3153   Darrel Goeddel   [PATCH] support f...
729
730
731
  					   struct audit_field *sf)
  {
  	int ret = 0;
04305e4af   Ahmed S. Darwish   Audit: Final rena...
732
  	char *lsm_str;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
733

04305e4af   Ahmed S. Darwish   Audit: Final rena...
734
735
736
  	/* our own copy of lsm_str */
  	lsm_str = kstrdup(sf->lsm_str, GFP_KERNEL);
  	if (unlikely(!lsm_str))
3e1fbd12c   Akinobu Mita   [PATCH] audit: fi...
737
  		return -ENOMEM;
04305e4af   Ahmed S. Darwish   Audit: Final rena...
738
  	df->lsm_str = lsm_str;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
739

04305e4af   Ahmed S. Darwish   Audit: Final rena...
740
741
742
  	/* our own (refreshed) copy of lsm_rule */
  	ret = security_audit_rule_init(df->type, df->op, df->lsm_str,
  				       (void **)&df->lsm_rule);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
743
744
745
  	/* Keep currently invalid fields around in case they
  	 * become valid after a policy reload. */
  	if (ret == -EINVAL) {
f952d10ff   Richard Guy Briggs   audit: Use more c...
746
747
748
  		pr_warn("audit rule for LSM \'%s\' is invalid
  ",
  			df->lsm_str);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
749
750
751
752
753
754
755
  		ret = 0;
  	}
  
  	return ret;
  }
  
  /* Duplicate an audit rule.  This will be a deep copy with the exception
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
756
   * of the watch - that pointer is carried over.  The LSM specific fields
3dc7e3153   Darrel Goeddel   [PATCH] support f...
757
   * will be updated in the copy.  The point is to be able to replace the old
f368c07d7   Amy Griffis   [PATCH] audit: pa...
758
759
760
   * rule with the new rule in the filterlist, then free the old rule.
   * The rlist element is undefined; list manipulations are handled apart from
   * the initial copy. */
ae7b8f410   Eric Paris   Audit: clean up t...
761
  struct audit_entry *audit_dupe_rule(struct audit_krule *old)
3dc7e3153   Darrel Goeddel   [PATCH] support f...
762
763
764
765
  {
  	u32 fcount = old->field_count;
  	struct audit_entry *entry;
  	struct audit_krule *new;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
766
  	char *fk;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
767
768
769
770
771
772
773
  	int i, err = 0;
  
  	entry = audit_init_entry(fcount);
  	if (unlikely(!entry))
  		return ERR_PTR(-ENOMEM);
  
  	new = &entry->rule;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
774
  	new->flags = old->flags;
041d7b98f   Richard Guy Briggs   audit: restore AU...
775
  	new->pflags = old->pflags;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
776
777
778
779
  	new->listnr = old->listnr;
  	new->action = old->action;
  	for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
  		new->mask[i] = old->mask[i];
0590b9335   Al Viro   fixing audit rule...
780
  	new->prio = old->prio;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
781
  	new->buflen = old->buflen;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
782
  	new->inode_f = old->inode_f;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
783
  	new->field_count = old->field_count;
ae7b8f410   Eric Paris   Audit: clean up t...
784

74c3cbe33   Al Viro   [PATCH] audit: wa...
785
786
787
788
789
790
791
792
  	/*
  	 * note that we are OK with not refcounting here; audit_match_tree()
  	 * never dereferences tree and we can't get false positives there
  	 * since we'd have to have rule gone from the list *and* removed
  	 * before the chunks found by lookup had been allocated, i.e. before
  	 * the beginning of list scan.
  	 */
  	new->tree = old->tree;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
793
  	memcpy(new->fields, old->fields, sizeof(struct audit_field) * fcount);
04305e4af   Ahmed S. Darwish   Audit: Final rena...
794
  	/* deep copy this information, updating the lsm_rule fields, because
3dc7e3153   Darrel Goeddel   [PATCH] support f...
795
796
797
  	 * the originals will all be freed when the old rule is freed. */
  	for (i = 0; i < fcount; i++) {
  		switch (new->fields[i].type) {
3a6b9f85c   Darrel Goeddel   [PATCH] audit: re...
798
799
800
801
802
  		case AUDIT_SUBJ_USER:
  		case AUDIT_SUBJ_ROLE:
  		case AUDIT_SUBJ_TYPE:
  		case AUDIT_SUBJ_SEN:
  		case AUDIT_SUBJ_CLR:
6e5a2d1d3   Darrel Goeddel   [PATCH] audit: su...
803
804
805
806
807
  		case AUDIT_OBJ_USER:
  		case AUDIT_OBJ_ROLE:
  		case AUDIT_OBJ_TYPE:
  		case AUDIT_OBJ_LEV_LOW:
  		case AUDIT_OBJ_LEV_HIGH:
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
808
  			err = audit_dupe_lsm_field(&new->fields[i],
3dc7e3153   Darrel Goeddel   [PATCH] support f...
809
  						       &old->fields[i]);
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
810
811
812
813
814
815
816
  			break;
  		case AUDIT_FILTERKEY:
  			fk = kstrdup(old->filterkey, GFP_KERNEL);
  			if (unlikely(!fk))
  				err = -ENOMEM;
  			else
  				new->filterkey = fk;
34d99af52   Richard Guy Briggs   audit: implement ...
817
818
819
820
  			break;
  		case AUDIT_EXE:
  			err = audit_dupe_exe(new, old);
  			break;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
821
822
  		}
  		if (err) {
34d99af52   Richard Guy Briggs   audit: implement ...
823
824
  			if (new->exe)
  				audit_remove_mark(new->exe);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
825
826
827
828
  			audit_free_rule(entry);
  			return ERR_PTR(err);
  		}
  	}
ae7b8f410   Eric Paris   Audit: clean up t...
829
830
831
  	if (old->watch) {
  		audit_get_watch(old->watch);
  		new->watch = old->watch;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
832
  	}
3dc7e3153   Darrel Goeddel   [PATCH] support f...
833
834
  	return entry;
  }
f368c07d7   Amy Griffis   [PATCH] audit: pa...
835
836
837
  /* Find an existing audit rule.
   * Caller must hold audit_filter_mutex to prevent stale rule data. */
  static struct audit_entry *audit_find_rule(struct audit_entry *entry,
36c4f1b18   Al Viro   clean up audit_ru...
838
  					   struct list_head **p)
f368c07d7   Amy Griffis   [PATCH] audit: pa...
839
840
  {
  	struct audit_entry *e, *found = NULL;
36c4f1b18   Al Viro   clean up audit_ru...
841
  	struct list_head *list;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
842
  	int h;
36c4f1b18   Al Viro   clean up audit_ru...
843
844
845
846
  	if (entry->rule.inode_f) {
  		h = audit_hash_ino(entry->rule.inode_f->val);
  		*p = list = &audit_inode_hash[h];
  	} else if (entry->rule.watch) {
f368c07d7   Amy Griffis   [PATCH] audit: pa...
847
848
849
850
851
852
853
854
855
856
  		/* we don't know the inode number, so must walk entire hash */
  		for (h = 0; h < AUDIT_INODE_BUCKETS; h++) {
  			list = &audit_inode_hash[h];
  			list_for_each_entry(e, list, list)
  				if (!audit_compare_rule(&entry->rule, &e->rule)) {
  					found = e;
  					goto out;
  				}
  		}
  		goto out;
36c4f1b18   Al Viro   clean up audit_ru...
857
858
  	} else {
  		*p = list = &audit_filter_list[entry->rule.listnr];
f368c07d7   Amy Griffis   [PATCH] audit: pa...
859
860
861
862
863
864
865
866
867
868
869
  	}
  
  	list_for_each_entry(e, list, list)
  		if (!audit_compare_rule(&entry->rule, &e->rule)) {
  			found = e;
  			goto out;
  		}
  
  out:
  	return found;
  }
0590b9335   Al Viro   fixing audit rule...
870
871
  static u64 prio_low = ~0ULL/2;
  static u64 prio_high = ~0ULL/2 - 1;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
872
  /* Add rule to given filterlist if not a duplicate. */
36c4f1b18   Al Viro   clean up audit_ru...
873
  static inline int audit_add_rule(struct audit_entry *entry)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
874
  {
93315ed6d   Amy Griffis   [PATCH] audit str...
875
  	struct audit_entry *e;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
876
  	struct audit_watch *watch = entry->rule.watch;
74c3cbe33   Al Viro   [PATCH] audit: wa...
877
  	struct audit_tree *tree = entry->rule.tree;
36c4f1b18   Al Viro   clean up audit_ru...
878
  	struct list_head *list;
ae9d2fb48   Paul Moore   audit: fix uninit...
879
  	int err = 0;
471a5c7c8   Al Viro   [PATCH] introduce...
880
881
882
883
884
885
886
887
  #ifdef CONFIG_AUDITSYSCALL
  	int dont_count = 0;
  
  	/* If either of these, don't count towards total */
  	if (entry->rule.listnr == AUDIT_FILTER_USER ||
  		entry->rule.listnr == AUDIT_FILTER_TYPE)
  		dont_count = 1;
  #endif
f368c07d7   Amy Griffis   [PATCH] audit: pa...
888

f368c07d7   Amy Griffis   [PATCH] audit: pa...
889
  	mutex_lock(&audit_filter_mutex);
36c4f1b18   Al Viro   clean up audit_ru...
890
  	e = audit_find_rule(entry, &list);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
891
  	if (e) {
35fe4d0b1   Eric Paris   Audit: move audit...
892
  		mutex_unlock(&audit_filter_mutex);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
893
  		err = -EEXIST;
74c3cbe33   Al Viro   [PATCH] audit: wa...
894
895
896
  		/* normally audit_add_tree_rule() will free it on failure */
  		if (tree)
  			audit_put_tree(tree);
f8259b262   Richard Guy Briggs   audit: eliminate ...
897
  		return err;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
898
  	}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
899

f368c07d7   Amy Griffis   [PATCH] audit: pa...
900
901
  	if (watch) {
  		/* audit_filter_mutex is dropped and re-taken during this call */
ae7b8f410   Eric Paris   Audit: clean up t...
902
  		err = audit_add_watch(&entry->rule, &list);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
903
904
  		if (err) {
  			mutex_unlock(&audit_filter_mutex);
2f992ee85   Chen Gang   kernel/auditfilte...
905
906
907
908
909
910
  			/*
  			 * normally audit_add_tree_rule() will free it
  			 * on failure
  			 */
  			if (tree)
  				audit_put_tree(tree);
f8259b262   Richard Guy Briggs   audit: eliminate ...
911
  			return err;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
912
  		}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
913
  	}
74c3cbe33   Al Viro   [PATCH] audit: wa...
914
915
916
917
  	if (tree) {
  		err = audit_add_tree_rule(&entry->rule);
  		if (err) {
  			mutex_unlock(&audit_filter_mutex);
f8259b262   Richard Guy Briggs   audit: eliminate ...
918
  			return err;
74c3cbe33   Al Viro   [PATCH] audit: wa...
919
920
  		}
  	}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
921

0590b9335   Al Viro   fixing audit rule...
922
923
924
925
926
927
928
  	entry->rule.prio = ~0ULL;
  	if (entry->rule.listnr == AUDIT_FILTER_EXIT) {
  		if (entry->rule.flags & AUDIT_FILTER_PREPEND)
  			entry->rule.prio = ++prio_high;
  		else
  			entry->rule.prio = --prio_low;
  	}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
929
  	if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
e45aa212e   Al Viro   audit rules order...
930
931
  		list_add(&entry->rule.list,
  			 &audit_rules_list[entry->rule.listnr]);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
932
  		list_add_rcu(&entry->list, list);
6a2bceec0   Amy Griffis   [PATCH] fix AUDIT...
933
  		entry->rule.flags &= ~AUDIT_FILTER_PREPEND;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
934
  	} else {
e45aa212e   Al Viro   audit rules order...
935
936
  		list_add_tail(&entry->rule.list,
  			      &audit_rules_list[entry->rule.listnr]);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
937
938
  		list_add_tail_rcu(&entry->list, list);
  	}
471a5c7c8   Al Viro   [PATCH] introduce...
939
940
941
  #ifdef CONFIG_AUDITSYSCALL
  	if (!dont_count)
  		audit_n_rules++;
e54dc2431   Amy Griffis   [PATCH] audit sig...
942
943
944
  
  	if (!audit_match_signal(entry))
  		audit_signals++;
471a5c7c8   Al Viro   [PATCH] introduce...
945
  #endif
f368c07d7   Amy Griffis   [PATCH] audit: pa...
946
  	mutex_unlock(&audit_filter_mutex);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
947

f368c07d7   Amy Griffis   [PATCH] audit: pa...
948
  	return err;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
949
  }
f368c07d7   Amy Griffis   [PATCH] audit: pa...
950
  /* Remove an existing rule from filterlist. */
7f4929428   Richard Guy Briggs   audit: clean simp...
951
  int audit_del_rule(struct audit_entry *entry)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
952
953
  {
  	struct audit_entry  *e;
74c3cbe33   Al Viro   [PATCH] audit: wa...
954
  	struct audit_tree *tree = entry->rule.tree;
36c4f1b18   Al Viro   clean up audit_ru...
955
  	struct list_head *list;
36c4f1b18   Al Viro   clean up audit_ru...
956
  	int ret = 0;
471a5c7c8   Al Viro   [PATCH] introduce...
957
958
959
960
961
962
963
964
  #ifdef CONFIG_AUDITSYSCALL
  	int dont_count = 0;
  
  	/* If either of these, don't count towards total */
  	if (entry->rule.listnr == AUDIT_FILTER_USER ||
  		entry->rule.listnr == AUDIT_FILTER_TYPE)
  		dont_count = 1;
  #endif
f368c07d7   Amy Griffis   [PATCH] audit: pa...
965

f368c07d7   Amy Griffis   [PATCH] audit: pa...
966
  	mutex_lock(&audit_filter_mutex);
36c4f1b18   Al Viro   clean up audit_ru...
967
  	e = audit_find_rule(entry, &list);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
968
  	if (!e) {
f368c07d7   Amy Griffis   [PATCH] audit: pa...
969
970
971
  		ret = -ENOENT;
  		goto out;
  	}
cfcad62c7   Eric Paris   audit: seperate a...
972
  	if (e->rule.watch)
a05fb6cc5   Eric Paris   audit: do not get...
973
  		audit_remove_watch_rule(&e->rule);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
974

74c3cbe33   Al Viro   [PATCH] audit: wa...
975
976
  	if (e->rule.tree)
  		audit_remove_tree_rule(&e->rule);
34d99af52   Richard Guy Briggs   audit: implement ...
977
978
  	if (e->rule.exe)
  		audit_remove_mark_rule(&e->rule);
471a5c7c8   Al Viro   [PATCH] introduce...
979
980
981
  #ifdef CONFIG_AUDITSYSCALL
  	if (!dont_count)
  		audit_n_rules--;
e54dc2431   Amy Griffis   [PATCH] audit sig...
982
983
984
  
  	if (!audit_match_signal(entry))
  		audit_signals--;
471a5c7c8   Al Viro   [PATCH] introduce...
985
  #endif
8c85fc9ae   Richard Guy Briggs   audit: make audit...
986
987
988
989
  
  	list_del_rcu(&e->list);
  	list_del(&e->rule.list);
  	call_rcu(&e->rcu, audit_free_rule_rcu);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
990

f368c07d7   Amy Griffis   [PATCH] audit: pa...
991
  out:
8c85fc9ae   Richard Guy Briggs   audit: make audit...
992
  	mutex_unlock(&audit_filter_mutex);
74c3cbe33   Al Viro   [PATCH] audit: wa...
993
994
  	if (tree)
  		audit_put_tree(tree);	/* that's the temporary one */
f368c07d7   Amy Griffis   [PATCH] audit: pa...
995
996
  
  	return ret;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
997
  }
93315ed6d   Amy Griffis   [PATCH] audit str...
998
  /* List rules using struct audit_rule_data. */
f9441639e   Richard Guy Briggs   audit: fix netlin...
999
  static void audit_list_rules(__u32 portid, int seq, struct sk_buff_head *q)
93315ed6d   Amy Griffis   [PATCH] audit str...
1000
  {
9044e6bca   Al Viro   [PATCH] fix deadl...
1001
  	struct sk_buff *skb;
e45aa212e   Al Viro   audit rules order...
1002
  	struct audit_krule *r;
93315ed6d   Amy Griffis   [PATCH] audit str...
1003
  	int i;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1004
1005
  	/* This is a blocking read, so use audit_filter_mutex instead of rcu
  	 * iterator to sync with list writers. */
93315ed6d   Amy Griffis   [PATCH] audit str...
1006
  	for (i=0; i<AUDIT_NR_FILTERS; i++) {
e45aa212e   Al Viro   audit rules order...
1007
  		list_for_each_entry(r, &audit_rules_list[i], list) {
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1008
  			struct audit_rule_data *data;
e45aa212e   Al Viro   audit rules order...
1009
  			data = audit_krule_to_data(r);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1010
1011
  			if (unlikely(!data))
  				break;
f9441639e   Richard Guy Briggs   audit: fix netlin...
1012
1013
1014
  			skb = audit_make_reply(portid, seq, AUDIT_LIST_RULES,
  					       0, 1, data,
  					       sizeof(*data) + data->buflen);
9044e6bca   Al Viro   [PATCH] fix deadl...
1015
1016
  			if (skb)
  				skb_queue_tail(q, skb);
93315ed6d   Amy Griffis   [PATCH] audit str...
1017
1018
1019
  			kfree(data);
  		}
  	}
f9441639e   Richard Guy Briggs   audit: fix netlin...
1020
  	skb = audit_make_reply(portid, seq, AUDIT_LIST_RULES, 1, 1, NULL, 0);
9044e6bca   Al Viro   [PATCH] fix deadl...
1021
1022
  	if (skb)
  		skb_queue_tail(q, skb);
93315ed6d   Amy Griffis   [PATCH] audit str...
1023
  }
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
1024
  /* Log rule additions and removals */
dc9eb698f   Eric Paris   audit: stop pushi...
1025
  static void audit_log_rule_change(char *action, struct audit_krule *rule, int res)
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
1026
1027
  {
  	struct audit_buffer *ab;
dc9eb698f   Eric Paris   audit: stop pushi...
1028
  	uid_t loginuid = from_kuid(&init_user_ns, audit_get_loginuid(current));
4440e8548   Eric Paris   audit: convert al...
1029
  	unsigned int sessionid = audit_get_sessionid(current);
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
1030

1a6b9f231   Eric Paris   [AUDIT] make audi...
1031
1032
  	if (!audit_enabled)
  		return;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
1033
1034
1035
  	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
  	if (!ab)
  		return;
dc9eb698f   Eric Paris   audit: stop pushi...
1036
  	audit_log_format(ab, "auid=%u ses=%u" ,loginuid, sessionid);
b122c3767   Eric Paris   audit: use a cons...
1037
  	audit_log_task_context(ab);
9d9609851   Eric Paris   Audit: clean up a...
1038
1039
1040
  	audit_log_format(ab, " op=");
  	audit_log_string(ab, action);
  	audit_log_key(ab, rule->filterkey);
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
1041
1042
1043
  	audit_log_format(ab, " list=%d res=%d", rule->listnr, res);
  	audit_log_end(ab);
  }
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1044
  /**
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1045
   * audit_rule_change - apply all rules to the specified message type
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1046
   * @type: audit message type
f9441639e   Richard Guy Briggs   audit: fix netlin...
1047
   * @portid: target port id for netlink audit messages
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1048
1049
   * @seq: netlink audit message sequence (serial) number
   * @data: payload data
93315ed6d   Amy Griffis   [PATCH] audit str...
1050
   * @datasz: size of payload data
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1051
   */
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1052
1053
  int audit_rule_change(int type, __u32 portid, int seq, void *data,
  			size_t datasz)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1054
  {
93315ed6d   Amy Griffis   [PATCH] audit str...
1055
1056
  	int err = 0;
  	struct audit_entry *entry;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1057

e85322d21   Richard Guy Briggs   audit: cull redun...
1058
1059
1060
  	entry = audit_data_to_entry(data, datasz);
  	if (IS_ERR(entry))
  		return PTR_ERR(entry);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1061
  	switch (type) {
93315ed6d   Amy Griffis   [PATCH] audit str...
1062
  	case AUDIT_ADD_RULE:
36c4f1b18   Al Viro   clean up audit_ru...
1063
  		err = audit_add_rule(entry);
e7df61f4d   Burn Alting   audit: invalid op...
1064
  		audit_log_rule_change("add_rule", &entry->rule, !err);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1065
  		break;
93315ed6d   Amy Griffis   [PATCH] audit str...
1066
  	case AUDIT_DEL_RULE:
36c4f1b18   Al Viro   clean up audit_ru...
1067
  		err = audit_del_rule(entry);
e7df61f4d   Burn Alting   audit: invalid op...
1068
  		audit_log_rule_change("remove_rule", &entry->rule, !err);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1069
1070
  		break;
  	default:
739c95038   Eric Paris   audit: WARN if au...
1071
1072
  		err = -EINVAL;
  		WARN_ON(1);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1073
  	}
34d99af52   Richard Guy Briggs   audit: implement ...
1074
1075
1076
  	if (err || type == AUDIT_DEL_RULE) {
  		if (entry->rule.exe)
  			audit_remove_mark(entry->rule.exe);
e85322d21   Richard Guy Briggs   audit: cull redun...
1077
  		audit_free_rule(entry);
34d99af52   Richard Guy Briggs   audit: implement ...
1078
  	}
e85322d21   Richard Guy Briggs   audit: cull redun...
1079

fe7752bab   David Woodhouse   [PATCH] Fix audit...
1080
1081
  	return err;
  }
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1082
1083
  /**
   * audit_list_rules_send - list the audit rules
d211f177b   Eric W. Biederman   audit: Update kdo...
1084
   * @request_skb: skb of request we are replying to (used to target the reply)
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1085
1086
   * @seq: netlink audit message sequence (serial) number
   */
6f285b19d   Eric W. Biederman   audit: Send repli...
1087
  int audit_list_rules_send(struct sk_buff *request_skb, int seq)
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1088
  {
6f285b19d   Eric W. Biederman   audit: Send repli...
1089
1090
  	u32 portid = NETLINK_CB(request_skb).portid;
  	struct net *net = sock_net(NETLINK_CB(request_skb).sk);
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
  	struct task_struct *tsk;
  	struct audit_netlink_list *dest;
  	int err = 0;
  
  	/* We can't just spew out the rules here because we might fill
  	 * the available socket buffer space and deadlock waiting for
  	 * auditctl to read from it... which isn't ever going to
  	 * happen if we're actually running in the context of auditctl
  	 * trying to _send_ the stuff */
  
  	dest = kmalloc(sizeof(struct audit_netlink_list), GFP_KERNEL);
  	if (!dest)
  		return -ENOMEM;
6f285b19d   Eric W. Biederman   audit: Send repli...
1104
  	dest->net = get_net(net);
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1105
  	dest->portid = portid;
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
  	skb_queue_head_init(&dest->q);
  
  	mutex_lock(&audit_filter_mutex);
  	audit_list_rules(portid, seq, &dest->q);
  	mutex_unlock(&audit_filter_mutex);
  
  	tsk = kthread_run(audit_send_list, dest, "audit_send_list");
  	if (IS_ERR(tsk)) {
  		skb_queue_purge(&dest->q);
  		kfree(dest);
  		err = PTR_ERR(tsk);
  	}
  
  	return err;
  }
5af75d8d5   Al Viro   audit: validate c...
1121
  int audit_comparator(u32 left, u32 op, u32 right)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1122
1123
  {
  	switch (op) {
5af75d8d5   Al Viro   audit: validate c...
1124
  	case Audit_equal:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1125
  		return (left == right);
5af75d8d5   Al Viro   audit: validate c...
1126
  	case Audit_not_equal:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1127
  		return (left != right);
5af75d8d5   Al Viro   audit: validate c...
1128
  	case Audit_lt:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1129
  		return (left < right);
5af75d8d5   Al Viro   audit: validate c...
1130
  	case Audit_le:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1131
  		return (left <= right);
5af75d8d5   Al Viro   audit: validate c...
1132
  	case Audit_gt:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1133
  		return (left > right);
5af75d8d5   Al Viro   audit: validate c...
1134
  	case Audit_ge:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1135
  		return (left >= right);
5af75d8d5   Al Viro   audit: validate c...
1136
  	case Audit_bitmask:
74f2345b6   Eric Paris   [PATCH] allow aud...
1137
  		return (left & right);
5af75d8d5   Al Viro   audit: validate c...
1138
  	case Audit_bittest:
74f2345b6   Eric Paris   [PATCH] allow aud...
1139
  		return ((left & right) == right);
5af75d8d5   Al Viro   audit: validate c...
1140
1141
1142
  	default:
  		BUG();
  		return 0;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1143
1144
  	}
  }
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
  int audit_uid_comparator(kuid_t left, u32 op, kuid_t right)
  {
  	switch (op) {
  	case Audit_equal:
  		return uid_eq(left, right);
  	case Audit_not_equal:
  		return !uid_eq(left, right);
  	case Audit_lt:
  		return uid_lt(left, right);
  	case Audit_le:
  		return uid_lte(left, right);
  	case Audit_gt:
  		return uid_gt(left, right);
  	case Audit_ge:
  		return uid_gte(left, right);
  	case Audit_bitmask:
  	case Audit_bittest:
  	default:
  		BUG();
  		return 0;
  	}
  }
  
  int audit_gid_comparator(kgid_t left, u32 op, kgid_t right)
  {
  	switch (op) {
  	case Audit_equal:
  		return gid_eq(left, right);
  	case Audit_not_equal:
  		return !gid_eq(left, right);
  	case Audit_lt:
  		return gid_lt(left, right);
  	case Audit_le:
  		return gid_lte(left, right);
  	case Audit_gt:
  		return gid_gt(left, right);
  	case Audit_ge:
  		return gid_gte(left, right);
  	case Audit_bitmask:
  	case Audit_bittest:
  	default:
  		BUG();
  		return 0;
  	}
  }
bfcec7087   Jeff Layton   audit: set the na...
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
  /**
   * parent_len - find the length of the parent portion of a pathname
   * @path: pathname of which to determine length
   */
  int parent_len(const char *path)
  {
  	int plen;
  	const char *p;
  
  	plen = strlen(path);
  
  	if (plen == 0)
  		return plen;
  
  	/* disregard trailing slashes */
  	p = path + plen - 1;
  	while ((*p == '/') && (p > path))
  		p--;
  
  	/* walk backward until we find the next slash or hit beginning */
  	while ((*p != '/') && (p > path))
  		p--;
  
  	/* did we find a slash? Then increment to include it in path */
  	if (*p == '/')
  		p++;
  
  	return p - path;
  }
e3d6b07b8   Jeff Layton   audit: optimize a...
1219
1220
1221
1222
1223
1224
1225
1226
1227
  /**
   * audit_compare_dname_path - compare given dentry name with last component in
   * 			      given path. Return of 0 indicates a match.
   * @dname:	dentry name that we're comparing
   * @path:	full pathname that we're comparing
   * @parentlen:	length of the parent if known. Passing in AUDIT_NAME_FULL
   * 		here indicates that we must compute this value.
   */
  int audit_compare_dname_path(const char *dname, const char *path, int parentlen)
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1228
  {
e3d6b07b8   Jeff Layton   audit: optimize a...
1229
  	int dlen, pathlen;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1230
  	const char *p;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1231
  	dlen = strlen(dname);
29e9a3467   Eric Paris   audit: make audit...
1232
1233
  	pathlen = strlen(path);
  	if (pathlen < dlen)
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1234
  		return 1;
e3d6b07b8   Jeff Layton   audit: optimize a...
1235
  	parentlen = parentlen == AUDIT_NAME_FULL ? parent_len(path) : parentlen;
29e9a3467   Eric Paris   audit: make audit...
1236
  	if (pathlen - parentlen != dlen)
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1237
  		return 1;
29e9a3467   Eric Paris   audit: make audit...
1238
1239
  
  	p = path + parentlen;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1240

f368c07d7   Amy Griffis   [PATCH] audit: pa...
1241
1242
  	return strncmp(p, dname, dlen);
  }
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1243

86b2efbe3   Richard Guy Briggs   audit: add fields...
1244
  int audit_filter(int msgtype, unsigned int listtype)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1245
1246
  {
  	struct audit_entry *e;
86b2efbe3   Richard Guy Briggs   audit: add fields...
1247
  	int ret = 1; /* Audit by default */
9ce34218a   Daniel Walker   whitespace fixes:...
1248

fe7752bab   David Woodhouse   [PATCH] Fix audit...
1249
  	rcu_read_lock();
86b2efbe3   Richard Guy Briggs   audit: add fields...
1250
  	if (list_empty(&audit_filter_list[listtype]))
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1251
  		goto unlock_and_return;
86b2efbe3   Richard Guy Briggs   audit: add fields...
1252
1253
  	list_for_each_entry_rcu(e, &audit_filter_list[listtype], list) {
  		int i, result = 0;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1254

93315ed6d   Amy Griffis   [PATCH] audit str...
1255
1256
  		for (i = 0; i < e->rule.field_count; i++) {
  			struct audit_field *f = &e->rule.fields[i];
86b2efbe3   Richard Guy Briggs   audit: add fields...
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
  			pid_t pid;
  			u32 sid;
  
  			switch (f->type) {
  			case AUDIT_PID:
  				pid = task_pid_nr(current);
  				result = audit_comparator(pid, f->op, f->val);
  				break;
  			case AUDIT_UID:
  				result = audit_uid_comparator(current_uid(), f->op, f->uid);
  				break;
  			case AUDIT_GID:
  				result = audit_gid_comparator(current_gid(), f->op, f->gid);
  				break;
  			case AUDIT_LOGINUID:
  				result = audit_uid_comparator(audit_get_loginuid(current),
  							      f->op, f->uid);
  				break;
  			case AUDIT_LOGINUID_SET:
  				result = audit_comparator(audit_loginuid_set(current),
  							  f->op, f->val);
  				break;
  			case AUDIT_MSGTYPE:
  				result = audit_comparator(msgtype, f->op, f->val);
  				break;
  			case AUDIT_SUBJ_USER:
  			case AUDIT_SUBJ_ROLE:
  			case AUDIT_SUBJ_TYPE:
  			case AUDIT_SUBJ_SEN:
  			case AUDIT_SUBJ_CLR:
  				if (f->lsm_rule) {
  					security_task_getsecid(current, &sid);
  					result = security_audit_rule_match(sid,
  							f->type, f->op, f->lsm_rule, NULL);
  				}
  				break;
  			default:
  				goto unlock_and_return;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1295
  			}
86b2efbe3   Richard Guy Briggs   audit: add fields...
1296
1297
1298
1299
1300
1301
1302
1303
1304
  			if (result < 0) /* error */
  				goto unlock_and_return;
  			if (!result)
  				break;
  		}
  		if (result > 0) {
  			if (e->rule.action == AUDIT_NEVER || listtype == AUDIT_FILTER_TYPE)
  				ret = 0;
  			break;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1305
  		}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1306
1307
1308
  	}
  unlock_and_return:
  	rcu_read_unlock();
86b2efbe3   Richard Guy Briggs   audit: add fields...
1309
  	return ret;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1310
  }
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1311

e45aa212e   Al Viro   audit rules order...
1312
  static int update_lsm_rule(struct audit_krule *r)
1a9d0797b   Al Viro   audit_update_lsm_...
1313
  {
e45aa212e   Al Viro   audit rules order...
1314
  	struct audit_entry *entry = container_of(r, struct audit_entry, rule);
1a9d0797b   Al Viro   audit_update_lsm_...
1315
  	struct audit_entry *nentry;
1a9d0797b   Al Viro   audit_update_lsm_...
1316
  	int err = 0;
e45aa212e   Al Viro   audit rules order...
1317
  	if (!security_audit_rule_known(r))
1a9d0797b   Al Viro   audit_update_lsm_...
1318
  		return 0;
ae7b8f410   Eric Paris   Audit: clean up t...
1319
  	nentry = audit_dupe_rule(r);
34d99af52   Richard Guy Briggs   audit: implement ...
1320
1321
  	if (entry->rule.exe)
  		audit_remove_mark(entry->rule.exe);
1a9d0797b   Al Viro   audit_update_lsm_...
1322
1323
1324
1325
1326
  	if (IS_ERR(nentry)) {
  		/* save the first error encountered for the
  		 * return value */
  		err = PTR_ERR(nentry);
  		audit_panic("error updating LSM filters");
ae7b8f410   Eric Paris   Audit: clean up t...
1327
  		if (r->watch)
e45aa212e   Al Viro   audit rules order...
1328
  			list_del(&r->rlist);
1a9d0797b   Al Viro   audit_update_lsm_...
1329
  		list_del_rcu(&entry->list);
e45aa212e   Al Viro   audit rules order...
1330
  		list_del(&r->list);
1a9d0797b   Al Viro   audit_update_lsm_...
1331
  	} else {
ae7b8f410   Eric Paris   Audit: clean up t...
1332
  		if (r->watch || r->tree)
e45aa212e   Al Viro   audit rules order...
1333
  			list_replace_init(&r->rlist, &nentry->rule.rlist);
1a9d0797b   Al Viro   audit_update_lsm_...
1334
  		list_replace_rcu(&entry->list, &nentry->list);
e45aa212e   Al Viro   audit rules order...
1335
  		list_replace(&r->list, &nentry->rule.list);
1a9d0797b   Al Viro   audit_update_lsm_...
1336
1337
1338
1339
1340
  	}
  	call_rcu(&entry->rcu, audit_free_rule_rcu);
  
  	return err;
  }
04305e4af   Ahmed S. Darwish   Audit: Final rena...
1341
  /* This function will re-initialize the lsm_rule field of all applicable rules.
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
1342
   * It will traverse the filter lists serarching for rules that contain LSM
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1343
   * specific filter fields.  When such a rule is found, it is copied, the
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
1344
   * LSM field is re-initialized, and the old rule is replaced with the
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1345
   * updated rule. */
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
1346
  int audit_update_lsm_rules(void)
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1347
  {
e45aa212e   Al Viro   audit rules order...
1348
  	struct audit_krule *r, *n;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1349
  	int i, err = 0;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1350
1351
  	/* audit_filter_mutex synchronizes the writers */
  	mutex_lock(&audit_filter_mutex);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1352
1353
  
  	for (i = 0; i < AUDIT_NR_FILTERS; i++) {
e45aa212e   Al Viro   audit rules order...
1354
1355
  		list_for_each_entry_safe(r, n, &audit_rules_list[i], list) {
  			int res = update_lsm_rule(r);
1a9d0797b   Al Viro   audit_update_lsm_...
1356
1357
  			if (!err)
  				err = res;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1358
1359
  		}
  	}
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1360
  	mutex_unlock(&audit_filter_mutex);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1361
1362
1363
  
  	return err;
  }