Blame view

kernel/auditfilter.c 32.8 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
21
22
23
24
  /* 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
   */
  
  #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>
fe7752bab   David Woodhouse   [PATCH] Fix audit...
32
  #include "audit.h"
f368c07d7   Amy Griffis   [PATCH] audit: pa...
33
34
35
36
37
38
39
  /*
   * Locking model:
   *
   * audit_filter_mutex:
   * 		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
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
40
   * 		LSM rules during filtering.  If modified, these structures
f368c07d7   Amy Griffis   [PATCH] audit: pa...
41
42
43
44
   * 		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...
45
  /* Audit filter lists, defined in <linux/audit.h> */
fe7752bab   David Woodhouse   [PATCH] Fix audit...
46
47
48
49
50
51
52
53
54
55
56
  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...
57
58
59
60
61
62
63
64
  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...
65

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

93315ed6d   Amy Griffis   [PATCH] audit str...
68
  static inline void audit_free_rule(struct audit_entry *e)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
69
  {
3dc7e3153   Darrel Goeddel   [PATCH] support f...
70
  	int i;
c28bb7da7   Zhenwen Xu   make the e->rule....
71
  	struct audit_krule *erule = &e->rule;
ae7b8f410   Eric Paris   Audit: clean up t...
72

f368c07d7   Amy Griffis   [PATCH] audit: pa...
73
  	/* some rules don't have associated watches */
c28bb7da7   Zhenwen Xu   make the e->rule....
74
75
76
77
78
  	if (erule->watch)
  		audit_put_watch(erule->watch);
  	if (erule->fields)
  		for (i = 0; i < erule->field_count; i++) {
  			struct audit_field *f = &erule->fields[i];
04305e4af   Ahmed S. Darwish   Audit: Final rena...
79
80
  			kfree(f->lsm_str);
  			security_audit_rule_free(f->lsm_rule);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
81
  		}
c28bb7da7   Zhenwen Xu   make the e->rule....
82
83
  	kfree(erule->fields);
  	kfree(erule->filterkey);
93315ed6d   Amy Griffis   [PATCH] audit str...
84
85
  	kfree(e);
  }
74c3cbe33   Al Viro   [PATCH] audit: wa...
86
  void audit_free_rule_rcu(struct rcu_head *head)
93315ed6d   Amy Griffis   [PATCH] audit str...
87
88
89
90
  {
  	struct audit_entry *e = container_of(head, struct audit_entry, rcu);
  	audit_free_rule(e);
  }
3dc7e3153   Darrel Goeddel   [PATCH] support f...
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  /* 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;
  
  	fields = kzalloc(sizeof(*fields) * field_count, GFP_KERNEL);
  	if (unlikely(!fields)) {
  		kfree(entry);
  		return NULL;
  	}
  	entry->rule.fields = fields;
  
  	return entry;
  }
93315ed6d   Amy Griffis   [PATCH] audit str...
110
111
  /* Unpack a filter field's string representation from user-space
   * buffer. */
74c3cbe33   Al Viro   [PATCH] audit: wa...
112
  char *audit_unpack_string(void **bufp, size_t *remain, size_t len)
93315ed6d   Amy Griffis   [PATCH] audit str...
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
  {
  	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;
  }
f368c07d7   Amy Griffis   [PATCH] audit: pa...
136
137
138
139
140
  /* Translate an inode field to kernel respresentation. */
  static inline int audit_to_inode(struct audit_krule *krule,
  				 struct audit_field *f)
  {
  	if (krule->listnr != AUDIT_FILTER_EXIT ||
5af75d8d5   Al Viro   audit: validate c...
141
142
  	    krule->watch || krule->inode_f || krule->tree ||
  	    (f->op != Audit_equal && f->op != Audit_not_equal))
f368c07d7   Amy Griffis   [PATCH] audit: pa...
143
144
145
146
147
  		return -EINVAL;
  
  	krule->inode_f = f;
  	return 0;
  }
b915543b4   Al Viro   [PATCH] audit sys...
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
  static __u32 *classes[AUDIT_SYSCALL_CLASSES];
  
  int __init audit_register_class(int class, unsigned *list)
  {
  	__u32 *p = kzalloc(AUDIT_BITMASK_SIZE * sizeof(__u32), GFP_KERNEL);
  	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...
170
171
  int audit_match_class(int class, unsigned syscall)
  {
c926e4f43   Klaus Weidner   [PATCH] audit: fi...
172
  	if (unlikely(syscall >= AUDIT_BITMASK_SIZE * 32))
55669bfa1   Al Viro   [PATCH] audit: AU...
173
174
175
176
177
  		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...
178
  #ifdef CONFIG_AUDITSYSCALL
e54dc2431   Amy Griffis   [PATCH] audit sig...
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
  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...
215
  #endif
e54dc2431   Amy Griffis   [PATCH] audit sig...
216

93315ed6d   Amy Griffis   [PATCH] audit str...
217
218
219
220
221
  /* Common user-space to kernel rule translation. */
  static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule)
  {
  	unsigned listnr;
  	struct audit_entry *entry;
93315ed6d   Amy Griffis   [PATCH] audit str...
222
223
224
225
226
227
228
  	int i, err;
  
  	err = -EINVAL;
  	listnr = rule->flags & ~AUDIT_FILTER_PREPEND;
  	switch(listnr) {
  	default:
  		goto exit_err;
93315ed6d   Amy Griffis   [PATCH] audit str...
229
230
  #ifdef CONFIG_AUDITSYSCALL
  	case AUDIT_FILTER_ENTRY:
7ff68e53e   Eric Paris   audit: reject ent...
231
232
  		if (rule->action == AUDIT_ALWAYS)
  			goto exit_err;
93315ed6d   Amy Griffis   [PATCH] audit str...
233
234
235
  	case AUDIT_FILTER_EXIT:
  	case AUDIT_FILTER_TASK:
  #endif
7ff68e53e   Eric Paris   audit: reject ent...
236
237
  	case AUDIT_FILTER_USER:
  	case AUDIT_FILTER_TYPE:
93315ed6d   Amy Griffis   [PATCH] audit str...
238
239
  		;
  	}
014149cce   Al Viro   [PATCH] deprecate...
240
241
242
243
244
245
  	if (unlikely(rule->action == AUDIT_POSSIBLE)) {
  		printk(KERN_ERR "AUDIT_POSSIBLE is deprecated
  ");
  		goto exit_err;
  	}
  	if (rule->action != AUDIT_NEVER && rule->action != AUDIT_ALWAYS)
93315ed6d   Amy Griffis   [PATCH] audit str...
246
247
248
249
250
  		goto exit_err;
  	if (rule->field_count > AUDIT_MAX_FIELDS)
  		goto exit_err;
  
  	err = -ENOMEM;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
251
252
  	entry = audit_init_entry(rule->field_count);
  	if (!entry)
93315ed6d   Amy Griffis   [PATCH] audit str...
253
  		goto exit_err;
93315ed6d   Amy Griffis   [PATCH] audit str...
254
255
256
257
258
  
  	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...
259
260
261
  
  	for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
  		entry->rule.mask[i] = rule->mask[i];
b915543b4   Al Viro   [PATCH] audit sys...
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
  	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...
277
278
279
280
281
  	return entry;
  
  exit_err:
  	return ERR_PTR(err);
  }
5af75d8d5   Al Viro   audit: validate c...
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
  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...
301
  /* check if an audit field is valid */
62062cf8a   Eric Paris   audit: allow chec...
302
  static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
93315ed6d   Amy Griffis   [PATCH] audit str...
303
  {
62062cf8a   Eric Paris   audit: allow chec...
304
305
306
307
308
309
310
  	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...
311

ab61d38ed   Eric Paris   audit: make valid...
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  	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:
  		/* 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...
356
357
358
359
  	case AUDIT_LOGINUID_SET:
  		if ((f->val != 0) && (f->val != 1))
  			return -EINVAL;
  	/* FALL THROUGH */
ab61d38ed   Eric Paris   audit: make valid...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
  	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;
  	};
62062cf8a   Eric Paris   audit: allow chec...
377
  	return 0;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
378
  }
93315ed6d   Amy Griffis   [PATCH] audit str...
379
380
381
  /* Translate struct audit_rule_data to kernel's rule respresentation. */
  static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
  					       size_t datasz)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
382
  {
93315ed6d   Amy Griffis   [PATCH] audit str...
383
384
385
  	int err = 0;
  	struct audit_entry *entry;
  	void *bufp;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
386
  	size_t remain = datasz - sizeof(struct audit_rule_data);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
387
  	int i;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
388
  	char *str;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
389

93315ed6d   Amy Griffis   [PATCH] audit str...
390
391
392
  	entry = audit_to_entry_common((struct audit_rule *)data);
  	if (IS_ERR(entry))
  		goto exit_nofree;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
393

93315ed6d   Amy Griffis   [PATCH] audit str...
394
395
396
397
398
399
  	bufp = data->buf;
  	entry->rule.vers_ops = 2;
  	for (i = 0; i < data->field_count; i++) {
  		struct audit_field *f = &entry->rule.fields[i];
  
  		err = -EINVAL;
5af75d8d5   Al Viro   audit: validate c...
400
401
402
  
  		f->op = audit_to_op(data->fieldflags[i]);
  		if (f->op == Audit_bad)
93315ed6d   Amy Griffis   [PATCH] audit str...
403
  			goto exit_free;
93315ed6d   Amy Griffis   [PATCH] audit str...
404
  		f->type = data->fields[i];
3dc7e3153   Darrel Goeddel   [PATCH] support f...
405
  		f->val = data->values[i];
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
406
407
  		f->uid = INVALID_UID;
  		f->gid = INVALID_GID;
04305e4af   Ahmed S. Darwish   Audit: Final rena...
408
409
  		f->lsm_str = NULL;
  		f->lsm_rule = NULL;
62062cf8a   Eric Paris   audit: allow chec...
410

780a7654c   Eric W. Biederman   audit: Make testi...
411
  		/* Support legacy tests for a valid loginuid */
b9ce54c9f   Michal Simek   audit: Fix decima...
412
  		if ((f->type == AUDIT_LOGINUID) && (f->val == ~0U)) {
780a7654c   Eric W. Biederman   audit: Make testi...
413
414
415
  			f->type = AUDIT_LOGINUID_SET;
  			f->val = 0;
  		}
62062cf8a   Eric Paris   audit: allow chec...
416
417
418
419
420
  		err = audit_field_valid(entry, f);
  		if (err)
  			goto exit_free;
  
  		err = -EINVAL;
ab61d38ed   Eric Paris   audit: make valid...
421
  		switch (f->type) {
780a7654c   Eric W. Biederman   audit: Make testi...
422
  		case AUDIT_LOGINUID:
0a73dccc4   Al Viro   [PATCH] validate ...
423
424
425
426
  		case AUDIT_UID:
  		case AUDIT_EUID:
  		case AUDIT_SUID:
  		case AUDIT_FSUID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
427
  		case AUDIT_OBJ_UID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
428
429
430
431
  			f->uid = make_kuid(current_user_ns(), f->val);
  			if (!uid_valid(f->uid))
  				goto exit_free;
  			break;
0a73dccc4   Al Viro   [PATCH] validate ...
432
433
434
435
  		case AUDIT_GID:
  		case AUDIT_EGID:
  		case AUDIT_SGID:
  		case AUDIT_FSGID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
436
  		case AUDIT_OBJ_GID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
437
438
439
440
  			f->gid = make_kgid(current_user_ns(), f->val);
  			if (!gid_valid(f->gid))
  				goto exit_free;
  			break;
e54dc2431   Amy Griffis   [PATCH] audit sig...
441
442
443
  		case AUDIT_ARCH:
  			entry->rule.arch_f = f;
  			break;
3a6b9f85c   Darrel Goeddel   [PATCH] audit: re...
444
445
446
447
448
  		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...
449
450
451
452
453
  		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...
454
455
456
457
  			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...
458
  			err = security_audit_rule_init(f->type, f->op, str,
04305e4af   Ahmed S. Darwish   Audit: Final rena...
459
  						       (void **)&f->lsm_rule);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
460
461
462
  			/* Keep currently invalid fields around in case they
  			 * become valid after a policy reload. */
  			if (err == -EINVAL) {
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
463
  				printk(KERN_WARNING "audit rule for LSM "
3dc7e3153   Darrel Goeddel   [PATCH] support f...
464
465
466
467
468
469
470
471
  				       "\'%s\' is invalid
  ",  str);
  				err = 0;
  			}
  			if (err) {
  				kfree(str);
  				goto exit_free;
  			} else
04305e4af   Ahmed S. Darwish   Audit: Final rena...
472
  				f->lsm_str = str;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
473
  			break;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
474
475
476
477
478
479
480
481
482
483
484
485
  		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...
486
487
488
489
490
491
492
493
494
495
496
  		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...
497
498
499
500
501
  		case AUDIT_INODE:
  			err = audit_to_inode(&entry->rule, f);
  			if (err)
  				goto exit_free;
  			break;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
502
  		case AUDIT_FILTERKEY:
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
503
504
505
506
507
508
509
510
  			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;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
511
512
  		}
  	}
5af75d8d5   Al Viro   audit: validate c...
513
514
  	if (entry->rule.inode_f && entry->rule.inode_f->op == Audit_not_equal)
  		entry->rule.inode_f = NULL;
93315ed6d   Amy Griffis   [PATCH] audit str...
515
516
517
518
519
  
  exit_nofree:
  	return entry;
  
  exit_free:
373e0f340   Chen Gang   kernel/auditfilte...
520
521
522
523
  	if (entry->rule.watch)
  		audit_put_watch(entry->rule.watch); /* matches initial get */
  	if (entry->rule.tree)
  		audit_put_tree(entry->rule.tree); /* that's the temporary one */
93315ed6d   Amy Griffis   [PATCH] audit str...
524
525
526
527
528
  	audit_free_rule(entry);
  	return ERR_PTR(err);
  }
  
  /* Pack a filter field's string representation into data block. */
74c3cbe33   Al Viro   [PATCH] audit: wa...
529
  static inline size_t audit_pack_string(void **bufp, const char *str)
93315ed6d   Amy Griffis   [PATCH] audit str...
530
531
532
533
534
535
536
537
  {
  	size_t len = strlen(str);
  
  	memcpy(*bufp, str, len);
  	*bufp += len;
  
  	return len;
  }
93315ed6d   Amy Griffis   [PATCH] audit str...
538
539
540
541
542
543
544
545
546
  /* Translate kernel rule respresentation to struct audit_rule_data. */
  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...
547
  		return NULL;
93315ed6d   Amy Griffis   [PATCH] audit str...
548
549
550
551
552
553
554
555
556
557
  	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...
558
  		data->fieldflags[i] = audit_ops[f->op];
93315ed6d   Amy Griffis   [PATCH] audit str...
559
  		switch(f->type) {
3a6b9f85c   Darrel Goeddel   [PATCH] audit: re...
560
561
562
563
564
  		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...
565
566
567
568
569
  		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...
570
  			data->buflen += data->values[i] =
04305e4af   Ahmed S. Darwish   Audit: Final rena...
571
  				audit_pack_string(&bufp, f->lsm_str);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
572
  			break;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
573
574
  		case AUDIT_WATCH:
  			data->buflen += data->values[i] =
cfcad62c7   Eric Paris   audit: seperate a...
575
576
  				audit_pack_string(&bufp,
  						  audit_watch_path(krule->watch));
f368c07d7   Amy Griffis   [PATCH] audit: pa...
577
  			break;
74c3cbe33   Al Viro   [PATCH] audit: wa...
578
579
580
581
582
  		case AUDIT_DIR:
  			data->buflen += data->values[i] =
  				audit_pack_string(&bufp,
  						  audit_tree_path(krule->tree));
  			break;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
583
584
585
586
  		case AUDIT_FILTERKEY:
  			data->buflen += data->values[i] =
  				audit_pack_string(&bufp, krule->filterkey);
  			break;
93315ed6d   Amy Griffis   [PATCH] audit str...
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
  		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 ||
  	    a->listnr != b->listnr ||
  	    a->action != b->action ||
  	    a->field_count != b->field_count)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
606
607
608
  		return 1;
  
  	for (i = 0; i < a->field_count; i++) {
93315ed6d   Amy Griffis   [PATCH] audit str...
609
610
  		if (a->fields[i].type != b->fields[i].type ||
  		    a->fields[i].op != b->fields[i].op)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
611
  			return 1;
93315ed6d   Amy Griffis   [PATCH] audit str...
612
613
  
  		switch(a->fields[i].type) {
3a6b9f85c   Darrel Goeddel   [PATCH] audit: re...
614
615
616
617
618
  		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...
619
620
621
622
623
  		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...
624
  			if (strcmp(a->fields[i].lsm_str, b->fields[i].lsm_str))
3dc7e3153   Darrel Goeddel   [PATCH] support f...
625
626
  				return 1;
  			break;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
627
  		case AUDIT_WATCH:
cfcad62c7   Eric Paris   audit: seperate a...
628
629
  			if (strcmp(audit_watch_path(a->watch),
  				   audit_watch_path(b->watch)))
f368c07d7   Amy Griffis   [PATCH] audit: pa...
630
631
  				return 1;
  			break;
74c3cbe33   Al Viro   [PATCH] audit: wa...
632
633
634
635
636
  		case AUDIT_DIR:
  			if (strcmp(audit_tree_path(a->tree),
  				   audit_tree_path(b->tree)))
  				return 1;
  			break;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
637
638
639
640
641
  		case AUDIT_FILTERKEY:
  			/* both filterkeys exist based on above type compare */
  			if (strcmp(a->filterkey, b->filterkey))
  				return 1;
  			break;
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
  		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...
659
660
661
662
  		default:
  			if (a->fields[i].val != b->fields[i].val)
  				return 1;
  		}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
663
664
665
666
667
668
669
670
  	}
  
  	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...
671
  /* Duplicate LSM field information.  The lsm_rule is opaque, so must be
3dc7e3153   Darrel Goeddel   [PATCH] support f...
672
   * re-initialized. */
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
673
  static inline int audit_dupe_lsm_field(struct audit_field *df,
3dc7e3153   Darrel Goeddel   [PATCH] support f...
674
675
676
  					   struct audit_field *sf)
  {
  	int ret = 0;
04305e4af   Ahmed S. Darwish   Audit: Final rena...
677
  	char *lsm_str;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
678

04305e4af   Ahmed S. Darwish   Audit: Final rena...
679
680
681
  	/* our own copy of lsm_str */
  	lsm_str = kstrdup(sf->lsm_str, GFP_KERNEL);
  	if (unlikely(!lsm_str))
3e1fbd12c   Akinobu Mita   [PATCH] audit: fi...
682
  		return -ENOMEM;
04305e4af   Ahmed S. Darwish   Audit: Final rena...
683
  	df->lsm_str = lsm_str;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
684

04305e4af   Ahmed S. Darwish   Audit: Final rena...
685
686
687
  	/* 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...
688
689
690
  	/* Keep currently invalid fields around in case they
  	 * become valid after a policy reload. */
  	if (ret == -EINVAL) {
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
691
  		printk(KERN_WARNING "audit rule for LSM \'%s\' is "
04305e4af   Ahmed S. Darwish   Audit: Final rena...
692
693
  		       "invalid
  ", df->lsm_str);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
694
695
696
697
698
699
700
  		ret = 0;
  	}
  
  	return ret;
  }
  
  /* Duplicate an audit rule.  This will be a deep copy with the exception
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
701
   * of the watch - that pointer is carried over.  The LSM specific fields
3dc7e3153   Darrel Goeddel   [PATCH] support f...
702
   * will be updated in the copy.  The point is to be able to replace the old
f368c07d7   Amy Griffis   [PATCH] audit: pa...
703
704
705
   * 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...
706
  struct audit_entry *audit_dupe_rule(struct audit_krule *old)
3dc7e3153   Darrel Goeddel   [PATCH] support f...
707
708
709
710
  {
  	u32 fcount = old->field_count;
  	struct audit_entry *entry;
  	struct audit_krule *new;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
711
  	char *fk;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
712
713
714
715
716
717
718
719
720
721
722
723
724
  	int i, err = 0;
  
  	entry = audit_init_entry(fcount);
  	if (unlikely(!entry))
  		return ERR_PTR(-ENOMEM);
  
  	new = &entry->rule;
  	new->vers_ops = old->vers_ops;
  	new->flags = old->flags;
  	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...
725
  	new->prio = old->prio;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
726
  	new->buflen = old->buflen;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
727
  	new->inode_f = old->inode_f;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
728
  	new->field_count = old->field_count;
ae7b8f410   Eric Paris   Audit: clean up t...
729

74c3cbe33   Al Viro   [PATCH] audit: wa...
730
731
732
733
734
735
736
737
  	/*
  	 * 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...
738
  	memcpy(new->fields, old->fields, sizeof(struct audit_field) * fcount);
04305e4af   Ahmed S. Darwish   Audit: Final rena...
739
  	/* deep copy this information, updating the lsm_rule fields, because
3dc7e3153   Darrel Goeddel   [PATCH] support f...
740
741
742
  	 * 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...
743
744
745
746
747
  		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...
748
749
750
751
752
  		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...
753
  			err = audit_dupe_lsm_field(&new->fields[i],
3dc7e3153   Darrel Goeddel   [PATCH] support f...
754
  						       &old->fields[i]);
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
755
756
757
758
759
760
761
  			break;
  		case AUDIT_FILTERKEY:
  			fk = kstrdup(old->filterkey, GFP_KERNEL);
  			if (unlikely(!fk))
  				err = -ENOMEM;
  			else
  				new->filterkey = fk;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
762
763
764
765
766
767
  		}
  		if (err) {
  			audit_free_rule(entry);
  			return ERR_PTR(err);
  		}
  	}
ae7b8f410   Eric Paris   Audit: clean up t...
768
769
770
  	if (old->watch) {
  		audit_get_watch(old->watch);
  		new->watch = old->watch;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
771
  	}
3dc7e3153   Darrel Goeddel   [PATCH] support f...
772
773
  	return entry;
  }
f368c07d7   Amy Griffis   [PATCH] audit: pa...
774
775
776
  /* 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...
777
  					   struct list_head **p)
f368c07d7   Amy Griffis   [PATCH] audit: pa...
778
779
  {
  	struct audit_entry *e, *found = NULL;
36c4f1b18   Al Viro   clean up audit_ru...
780
  	struct list_head *list;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
781
  	int h;
36c4f1b18   Al Viro   clean up audit_ru...
782
783
784
785
  	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...
786
787
788
789
790
791
792
793
794
795
  		/* 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...
796
797
  	} else {
  		*p = list = &audit_filter_list[entry->rule.listnr];
f368c07d7   Amy Griffis   [PATCH] audit: pa...
798
799
800
801
802
803
804
805
806
807
808
  	}
  
  	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...
809
810
  static u64 prio_low = ~0ULL/2;
  static u64 prio_high = ~0ULL/2 - 1;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
811
  /* Add rule to given filterlist if not a duplicate. */
36c4f1b18   Al Viro   clean up audit_ru...
812
  static inline int audit_add_rule(struct audit_entry *entry)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
813
  {
93315ed6d   Amy Griffis   [PATCH] audit str...
814
  	struct audit_entry *e;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
815
  	struct audit_watch *watch = entry->rule.watch;
74c3cbe33   Al Viro   [PATCH] audit: wa...
816
  	struct audit_tree *tree = entry->rule.tree;
36c4f1b18   Al Viro   clean up audit_ru...
817
  	struct list_head *list;
ae7b8f410   Eric Paris   Audit: clean up t...
818
  	int err;
471a5c7c8   Al Viro   [PATCH] introduce...
819
820
821
822
823
824
825
826
  #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...
827

f368c07d7   Amy Griffis   [PATCH] audit: pa...
828
  	mutex_lock(&audit_filter_mutex);
36c4f1b18   Al Viro   clean up audit_ru...
829
  	e = audit_find_rule(entry, &list);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
830
  	if (e) {
35fe4d0b1   Eric Paris   Audit: move audit...
831
  		mutex_unlock(&audit_filter_mutex);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
832
  		err = -EEXIST;
74c3cbe33   Al Viro   [PATCH] audit: wa...
833
834
835
  		/* normally audit_add_tree_rule() will free it on failure */
  		if (tree)
  			audit_put_tree(tree);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
836
837
  		goto error;
  	}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
838

f368c07d7   Amy Griffis   [PATCH] audit: pa...
839
840
  	if (watch) {
  		/* audit_filter_mutex is dropped and re-taken during this call */
ae7b8f410   Eric Paris   Audit: clean up t...
841
  		err = audit_add_watch(&entry->rule, &list);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
842
843
  		if (err) {
  			mutex_unlock(&audit_filter_mutex);
2f992ee85   Chen Gang   kernel/auditfilte...
844
845
846
847
848
849
  			/*
  			 * normally audit_add_tree_rule() will free it
  			 * on failure
  			 */
  			if (tree)
  				audit_put_tree(tree);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
850
851
  			goto error;
  		}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
852
  	}
74c3cbe33   Al Viro   [PATCH] audit: wa...
853
854
855
856
857
858
859
  	if (tree) {
  		err = audit_add_tree_rule(&entry->rule);
  		if (err) {
  			mutex_unlock(&audit_filter_mutex);
  			goto error;
  		}
  	}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
860

0590b9335   Al Viro   fixing audit rule...
861
862
863
864
865
866
867
  	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...
868
  	if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
e45aa212e   Al Viro   audit rules order...
869
870
  		list_add(&entry->rule.list,
  			 &audit_rules_list[entry->rule.listnr]);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
871
  		list_add_rcu(&entry->list, list);
6a2bceec0   Amy Griffis   [PATCH] fix AUDIT...
872
  		entry->rule.flags &= ~AUDIT_FILTER_PREPEND;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
873
  	} else {
e45aa212e   Al Viro   audit rules order...
874
875
  		list_add_tail(&entry->rule.list,
  			      &audit_rules_list[entry->rule.listnr]);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
876
877
  		list_add_tail_rcu(&entry->list, list);
  	}
471a5c7c8   Al Viro   [PATCH] introduce...
878
879
880
  #ifdef CONFIG_AUDITSYSCALL
  	if (!dont_count)
  		audit_n_rules++;
e54dc2431   Amy Griffis   [PATCH] audit sig...
881
882
883
  
  	if (!audit_match_signal(entry))
  		audit_signals++;
471a5c7c8   Al Viro   [PATCH] introduce...
884
  #endif
f368c07d7   Amy Griffis   [PATCH] audit: pa...
885
  	mutex_unlock(&audit_filter_mutex);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
886

f368c07d7   Amy Griffis   [PATCH] audit: pa...
887
888
889
   	return 0;
  
  error:
f368c07d7   Amy Griffis   [PATCH] audit: pa...
890
891
892
  	if (watch)
  		audit_put_watch(watch); /* tmp watch, matches initial get */
  	return err;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
893
  }
f368c07d7   Amy Griffis   [PATCH] audit: pa...
894
  /* Remove an existing rule from filterlist. */
36c4f1b18   Al Viro   clean up audit_ru...
895
  static inline int audit_del_rule(struct audit_entry *entry)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
896
897
  {
  	struct audit_entry  *e;
cfcad62c7   Eric Paris   audit: seperate a...
898
  	struct audit_watch *watch = entry->rule.watch;
74c3cbe33   Al Viro   [PATCH] audit: wa...
899
  	struct audit_tree *tree = entry->rule.tree;
36c4f1b18   Al Viro   clean up audit_ru...
900
  	struct list_head *list;
36c4f1b18   Al Viro   clean up audit_ru...
901
  	int ret = 0;
471a5c7c8   Al Viro   [PATCH] introduce...
902
903
904
905
906
907
908
909
  #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...
910

f368c07d7   Amy Griffis   [PATCH] audit: pa...
911
  	mutex_lock(&audit_filter_mutex);
36c4f1b18   Al Viro   clean up audit_ru...
912
  	e = audit_find_rule(entry, &list);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
913
914
915
916
917
  	if (!e) {
  		mutex_unlock(&audit_filter_mutex);
  		ret = -ENOENT;
  		goto out;
  	}
cfcad62c7   Eric Paris   audit: seperate a...
918
  	if (e->rule.watch)
a05fb6cc5   Eric Paris   audit: do not get...
919
  		audit_remove_watch_rule(&e->rule);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
920

74c3cbe33   Al Viro   [PATCH] audit: wa...
921
922
  	if (e->rule.tree)
  		audit_remove_tree_rule(&e->rule);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
923
  	list_del_rcu(&e->list);
e45aa212e   Al Viro   audit rules order...
924
  	list_del(&e->rule.list);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
925
  	call_rcu(&e->rcu, audit_free_rule_rcu);
471a5c7c8   Al Viro   [PATCH] introduce...
926
927
928
  #ifdef CONFIG_AUDITSYSCALL
  	if (!dont_count)
  		audit_n_rules--;
e54dc2431   Amy Griffis   [PATCH] audit sig...
929
930
931
  
  	if (!audit_match_signal(entry))
  		audit_signals--;
471a5c7c8   Al Viro   [PATCH] introduce...
932
  #endif
f368c07d7   Amy Griffis   [PATCH] audit: pa...
933
  	mutex_unlock(&audit_filter_mutex);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
934
  out:
cfcad62c7   Eric Paris   audit: seperate a...
935
936
  	if (watch)
  		audit_put_watch(watch); /* match initial get */
74c3cbe33   Al Viro   [PATCH] audit: wa...
937
938
  	if (tree)
  		audit_put_tree(tree);	/* that's the temporary one */
f368c07d7   Amy Griffis   [PATCH] audit: pa...
939
940
  
  	return ret;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
941
  }
93315ed6d   Amy Griffis   [PATCH] audit str...
942
  /* List rules using struct audit_rule_data. */
9044e6bca   Al Viro   [PATCH] fix deadl...
943
  static void audit_list_rules(int pid, int seq, struct sk_buff_head *q)
93315ed6d   Amy Griffis   [PATCH] audit str...
944
  {
9044e6bca   Al Viro   [PATCH] fix deadl...
945
  	struct sk_buff *skb;
e45aa212e   Al Viro   audit rules order...
946
  	struct audit_krule *r;
93315ed6d   Amy Griffis   [PATCH] audit str...
947
  	int i;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
948
949
  	/* 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...
950
  	for (i=0; i<AUDIT_NR_FILTERS; i++) {
e45aa212e   Al Viro   audit rules order...
951
  		list_for_each_entry(r, &audit_rules_list[i], list) {
f368c07d7   Amy Griffis   [PATCH] audit: pa...
952
  			struct audit_rule_data *data;
e45aa212e   Al Viro   audit rules order...
953
  			data = audit_krule_to_data(r);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
954
955
956
957
  			if (unlikely(!data))
  				break;
  			skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 0, 1,
  					 data, sizeof(*data) + data->buflen);
9044e6bca   Al Viro   [PATCH] fix deadl...
958
959
  			if (skb)
  				skb_queue_tail(q, skb);
93315ed6d   Amy Griffis   [PATCH] audit str...
960
961
962
  			kfree(data);
  		}
  	}
9044e6bca   Al Viro   [PATCH] fix deadl...
963
964
965
  	skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 1, 1, NULL, 0);
  	if (skb)
  		skb_queue_tail(q, skb);
93315ed6d   Amy Griffis   [PATCH] audit str...
966
  }
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
967
  /* Log rule additions and removals */
dc9eb698f   Eric Paris   audit: stop pushi...
968
  static void audit_log_rule_change(char *action, struct audit_krule *rule, int res)
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
969
970
  {
  	struct audit_buffer *ab;
dc9eb698f   Eric Paris   audit: stop pushi...
971
972
  	uid_t loginuid = from_kuid(&init_user_ns, audit_get_loginuid(current));
  	u32 sessionid = audit_get_sessionid(current);
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
973

1a6b9f231   Eric Paris   [AUDIT] make audi...
974
975
  	if (!audit_enabled)
  		return;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
976
977
978
  	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
  	if (!ab)
  		return;
dc9eb698f   Eric Paris   audit: stop pushi...
979
  	audit_log_format(ab, "auid=%u ses=%u" ,loginuid, sessionid);
b122c3767   Eric Paris   audit: use a cons...
980
  	audit_log_task_context(ab);
9d9609851   Eric Paris   Audit: clean up a...
981
982
983
  	audit_log_format(ab, " op=");
  	audit_log_string(ab, action);
  	audit_log_key(ab, rule->filterkey);
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
984
985
986
  	audit_log_format(ab, " list=%d res=%d", rule->listnr, res);
  	audit_log_end(ab);
  }
fe7752bab   David Woodhouse   [PATCH] Fix audit...
987
988
989
990
  /**
   * audit_receive_filter - apply all rules to the specified message type
   * @type: audit message type
   * @pid: target pid for netlink audit messages
fe7752bab   David Woodhouse   [PATCH] Fix audit...
991
992
   * @seq: netlink audit message sequence (serial) number
   * @data: payload data
93315ed6d   Amy Griffis   [PATCH] audit str...
993
   * @datasz: size of payload data
fe7752bab   David Woodhouse   [PATCH] Fix audit...
994
   */
dc9eb698f   Eric Paris   audit: stop pushi...
995
  int audit_receive_filter(int type, int pid, int seq, void *data, size_t datasz)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
996
997
  {
  	struct task_struct *tsk;
9044e6bca   Al Viro   [PATCH] fix deadl...
998
  	struct audit_netlink_list *dest;
93315ed6d   Amy Griffis   [PATCH] audit str...
999
1000
  	int err = 0;
  	struct audit_entry *entry;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1001
1002
  
  	switch (type) {
93315ed6d   Amy Griffis   [PATCH] audit str...
1003
  	case AUDIT_LIST_RULES:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1004
1005
1006
1007
1008
  		/* 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 */
9ce34218a   Daniel Walker   whitespace fixes:...
1009

9044e6bca   Al Viro   [PATCH] fix deadl...
1010
  		dest = kmalloc(sizeof(struct audit_netlink_list), GFP_KERNEL);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1011
1012
  		if (!dest)
  			return -ENOMEM;
9044e6bca   Al Viro   [PATCH] fix deadl...
1013
1014
  		dest->pid = pid;
  		skb_queue_head_init(&dest->q);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1015

f368c07d7   Amy Griffis   [PATCH] audit: pa...
1016
  		mutex_lock(&audit_filter_mutex);
189009091   Eric Paris   audit: remove the...
1017
  		audit_list_rules(pid, seq, &dest->q);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1018
  		mutex_unlock(&audit_filter_mutex);
9044e6bca   Al Viro   [PATCH] fix deadl...
1019
1020
  
  		tsk = kthread_run(audit_send_list, dest, "audit_send_list");
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1021
  		if (IS_ERR(tsk)) {
9044e6bca   Al Viro   [PATCH] fix deadl...
1022
  			skb_queue_purge(&dest->q);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1023
1024
1025
1026
  			kfree(dest);
  			err = PTR_ERR(tsk);
  		}
  		break;
93315ed6d   Amy Griffis   [PATCH] audit str...
1027
  	case AUDIT_ADD_RULE:
189009091   Eric Paris   audit: remove the...
1028
  		entry = audit_data_to_entry(data, datasz);
93315ed6d   Amy Griffis   [PATCH] audit str...
1029
1030
  		if (IS_ERR(entry))
  			return PTR_ERR(entry);
36c4f1b18   Al Viro   clean up audit_ru...
1031
  		err = audit_add_rule(entry);
dc9eb698f   Eric Paris   audit: stop pushi...
1032
  		audit_log_rule_change("add rule", &entry->rule, !err);
5d3301088   Al Viro   [PATCH] add/remov...
1033
  		if (err)
93315ed6d   Amy Griffis   [PATCH] audit str...
1034
  			audit_free_rule(entry);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1035
  		break;
93315ed6d   Amy Griffis   [PATCH] audit str...
1036
  	case AUDIT_DEL_RULE:
189009091   Eric Paris   audit: remove the...
1037
  		entry = audit_data_to_entry(data, datasz);
93315ed6d   Amy Griffis   [PATCH] audit str...
1038
1039
  		if (IS_ERR(entry))
  			return PTR_ERR(entry);
36c4f1b18   Al Viro   clean up audit_ru...
1040
  		err = audit_del_rule(entry);
dc9eb698f   Eric Paris   audit: stop pushi...
1041
  		audit_log_rule_change("remove rule", &entry->rule, !err);
93315ed6d   Amy Griffis   [PATCH] audit str...
1042
  		audit_free_rule(entry);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1043
1044
1045
1046
1047
1048
1049
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	return err;
  }
5af75d8d5   Al Viro   audit: validate c...
1050
  int audit_comparator(u32 left, u32 op, u32 right)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1051
1052
  {
  	switch (op) {
5af75d8d5   Al Viro   audit: validate c...
1053
  	case Audit_equal:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1054
  		return (left == right);
5af75d8d5   Al Viro   audit: validate c...
1055
  	case Audit_not_equal:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1056
  		return (left != right);
5af75d8d5   Al Viro   audit: validate c...
1057
  	case Audit_lt:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1058
  		return (left < right);
5af75d8d5   Al Viro   audit: validate c...
1059
  	case Audit_le:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1060
  		return (left <= right);
5af75d8d5   Al Viro   audit: validate c...
1061
  	case Audit_gt:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1062
  		return (left > right);
5af75d8d5   Al Viro   audit: validate c...
1063
  	case Audit_ge:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1064
  		return (left >= right);
5af75d8d5   Al Viro   audit: validate c...
1065
  	case Audit_bitmask:
74f2345b6   Eric Paris   [PATCH] allow aud...
1066
  		return (left & right);
5af75d8d5   Al Viro   audit: validate c...
1067
  	case Audit_bittest:
74f2345b6   Eric Paris   [PATCH] allow aud...
1068
  		return ((left & right) == right);
5af75d8d5   Al Viro   audit: validate c...
1069
1070
1071
  	default:
  		BUG();
  		return 0;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1072
1073
  	}
  }
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
  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...
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
  /**
   * 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...
1148
1149
1150
1151
1152
1153
1154
1155
1156
  /**
   * 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...
1157
  {
e3d6b07b8   Jeff Layton   audit: optimize a...
1158
  	int dlen, pathlen;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1159
  	const char *p;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1160
  	dlen = strlen(dname);
29e9a3467   Eric Paris   audit: make audit...
1161
1162
  	pathlen = strlen(path);
  	if (pathlen < dlen)
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1163
  		return 1;
e3d6b07b8   Jeff Layton   audit: optimize a...
1164
  	parentlen = parentlen == AUDIT_NAME_FULL ? parent_len(path) : parentlen;
29e9a3467   Eric Paris   audit: make audit...
1165
  	if (pathlen - parentlen != dlen)
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1166
  		return 1;
29e9a3467   Eric Paris   audit: make audit...
1167
1168
  
  	p = path + parentlen;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1169

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

62062cf8a   Eric Paris   audit: allow chec...
1173
  static int audit_filter_user_rules(struct audit_krule *rule, int type,
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1174
1175
1176
1177
1178
  				   enum audit_state *state)
  {
  	int i;
  
  	for (i = 0; i < rule->field_count; i++) {
93315ed6d   Amy Griffis   [PATCH] audit str...
1179
  		struct audit_field *f = &rule->fields[i];
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1180
  		int result = 0;
c53fa1ed9   Patrick McHardy   netlink: kill log...
1181
  		u32 sid;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1182

93315ed6d   Amy Griffis   [PATCH] audit str...
1183
  		switch (f->type) {
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1184
  		case AUDIT_PID:
02276bda4   Eric W. Biederman   audit: Use curren...
1185
  			result = audit_comparator(task_pid_vnr(current), f->op, f->val);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1186
1187
  			break;
  		case AUDIT_UID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
1188
  			result = audit_uid_comparator(current_uid(), f->op, f->uid);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1189
1190
  			break;
  		case AUDIT_GID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
1191
  			result = audit_gid_comparator(current_gid(), f->op, f->gid);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1192
1193
  			break;
  		case AUDIT_LOGINUID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
1194
1195
  			result = audit_uid_comparator(audit_get_loginuid(current),
  						  f->op, f->uid);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1196
  			break;
780a7654c   Eric W. Biederman   audit: Make testi...
1197
1198
1199
1200
  		case AUDIT_LOGINUID_SET:
  			result = audit_comparator(audit_loginuid_set(current),
  						  f->op, f->val);
  			break;
62062cf8a   Eric Paris   audit: allow chec...
1201
1202
1203
  		case AUDIT_MSGTYPE:
  			result = audit_comparator(type, f->op, f->val);
  			break;
d29be158a   Miloslav Trmac   Audit: add suppor...
1204
1205
1206
1207
1208
  		case AUDIT_SUBJ_USER:
  		case AUDIT_SUBJ_ROLE:
  		case AUDIT_SUBJ_TYPE:
  		case AUDIT_SUBJ_SEN:
  		case AUDIT_SUBJ_CLR:
c53fa1ed9   Patrick McHardy   netlink: kill log...
1209
1210
1211
  			if (f->lsm_rule) {
  				security_task_getsecid(current, &sid);
  				result = security_audit_rule_match(sid,
d29be158a   Miloslav Trmac   Audit: add suppor...
1212
1213
1214
1215
  								   f->type,
  								   f->op,
  								   f->lsm_rule,
  								   NULL);
c53fa1ed9   Patrick McHardy   netlink: kill log...
1216
  			}
d29be158a   Miloslav Trmac   Audit: add suppor...
1217
  			break;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1218
1219
1220
1221
1222
1223
1224
  		}
  
  		if (!result)
  			return 0;
  	}
  	switch (rule->action) {
  	case AUDIT_NEVER:    *state = AUDIT_DISABLED;	    break;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1225
1226
1227
1228
  	case AUDIT_ALWAYS:   *state = AUDIT_RECORD_CONTEXT; break;
  	}
  	return 1;
  }
62062cf8a   Eric Paris   audit: allow chec...
1229
  int audit_filter_user(int type)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1230
  {
11f57cedc   Ingo Molnar   [PATCH] audit: fi...
1231
  	enum audit_state state = AUDIT_DISABLED;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1232
  	struct audit_entry *e;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1233
1234
1235
1236
  	int ret = 1;
  
  	rcu_read_lock();
  	list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) {
62062cf8a   Eric Paris   audit: allow chec...
1237
  		if (audit_filter_user_rules(&e->rule, type, &state)) {
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
  			if (state == AUDIT_DISABLED)
  				ret = 0;
  			break;
  		}
  	}
  	rcu_read_unlock();
  
  	return ret; /* Audit by default */
  }
  
  int audit_filter_type(int type)
  {
  	struct audit_entry *e;
  	int result = 0;
9ce34218a   Daniel Walker   whitespace fixes:...
1252

fe7752bab   David Woodhouse   [PATCH] Fix audit...
1253
1254
1255
1256
1257
1258
  	rcu_read_lock();
  	if (list_empty(&audit_filter_list[AUDIT_FILTER_TYPE]))
  		goto unlock_and_return;
  
  	list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TYPE],
  				list) {
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1259
  		int i;
93315ed6d   Amy Griffis   [PATCH] audit str...
1260
1261
1262
1263
  		for (i = 0; i < e->rule.field_count; i++) {
  			struct audit_field *f = &e->rule.fields[i];
  			if (f->type == AUDIT_MSGTYPE) {
  				result = audit_comparator(type, f->op, f->val);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
  				if (!result)
  					break;
  			}
  		}
  		if (result)
  			goto unlock_and_return;
  	}
  unlock_and_return:
  	rcu_read_unlock();
  	return result;
  }
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1275

e45aa212e   Al Viro   audit rules order...
1276
  static int update_lsm_rule(struct audit_krule *r)
1a9d0797b   Al Viro   audit_update_lsm_...
1277
  {
e45aa212e   Al Viro   audit rules order...
1278
  	struct audit_entry *entry = container_of(r, struct audit_entry, rule);
1a9d0797b   Al Viro   audit_update_lsm_...
1279
  	struct audit_entry *nentry;
1a9d0797b   Al Viro   audit_update_lsm_...
1280
  	int err = 0;
e45aa212e   Al Viro   audit rules order...
1281
  	if (!security_audit_rule_known(r))
1a9d0797b   Al Viro   audit_update_lsm_...
1282
  		return 0;
ae7b8f410   Eric Paris   Audit: clean up t...
1283
  	nentry = audit_dupe_rule(r);
1a9d0797b   Al Viro   audit_update_lsm_...
1284
1285
1286
1287
1288
  	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...
1289
  		if (r->watch)
e45aa212e   Al Viro   audit rules order...
1290
  			list_del(&r->rlist);
1a9d0797b   Al Viro   audit_update_lsm_...
1291
  		list_del_rcu(&entry->list);
e45aa212e   Al Viro   audit rules order...
1292
  		list_del(&r->list);
1a9d0797b   Al Viro   audit_update_lsm_...
1293
  	} else {
ae7b8f410   Eric Paris   Audit: clean up t...
1294
  		if (r->watch || r->tree)
e45aa212e   Al Viro   audit rules order...
1295
  			list_replace_init(&r->rlist, &nentry->rule.rlist);
1a9d0797b   Al Viro   audit_update_lsm_...
1296
  		list_replace_rcu(&entry->list, &nentry->list);
e45aa212e   Al Viro   audit rules order...
1297
  		list_replace(&r->list, &nentry->rule.list);
1a9d0797b   Al Viro   audit_update_lsm_...
1298
1299
1300
1301
1302
  	}
  	call_rcu(&entry->rcu, audit_free_rule_rcu);
  
  	return err;
  }
04305e4af   Ahmed S. Darwish   Audit: Final rena...
1303
  /* This function will re-initialize the lsm_rule field of all applicable rules.
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
1304
   * It will traverse the filter lists serarching for rules that contain LSM
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1305
   * specific filter fields.  When such a rule is found, it is copied, the
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
1306
   * LSM field is re-initialized, and the old rule is replaced with the
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1307
   * updated rule. */
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
1308
  int audit_update_lsm_rules(void)
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1309
  {
e45aa212e   Al Viro   audit rules order...
1310
  	struct audit_krule *r, *n;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1311
  	int i, err = 0;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1312
1313
  	/* audit_filter_mutex synchronizes the writers */
  	mutex_lock(&audit_filter_mutex);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1314
1315
  
  	for (i = 0; i < AUDIT_NR_FILTERS; i++) {
e45aa212e   Al Viro   audit rules order...
1316
1317
  		list_for_each_entry_safe(r, n, &audit_rules_list[i], list) {
  			int res = update_lsm_rule(r);
1a9d0797b   Al Viro   audit_update_lsm_...
1318
1319
  			if (!err)
  				err = res;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1320
1321
  		}
  	}
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1322
  	mutex_unlock(&audit_filter_mutex);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1323
1324
1325
  
  	return err;
  }