Blame view

kernel/auditfilter.c 33.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
  /* 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
39
40
41
  /*
   * 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...
42
   * 		LSM rules during filtering.  If modified, these structures
f368c07d7   Amy Griffis   [PATCH] audit: pa...
43
44
45
46
   * 		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...
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;
  }
f368c07d7   Amy Griffis   [PATCH] audit: pa...
151
152
153
154
155
  /* 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 ||
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
392
  	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...
393
  	return 0;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
394
  }
93315ed6d   Amy Griffis   [PATCH] audit str...
395
396
397
  /* 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...
398
  {
93315ed6d   Amy Griffis   [PATCH] audit str...
399
400
401
  	int err = 0;
  	struct audit_entry *entry;
  	void *bufp;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
402
  	size_t remain = datasz - sizeof(struct audit_rule_data);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
403
  	int i;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
404
  	char *str;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
405

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

93315ed6d   Amy Griffis   [PATCH] audit str...
410
411
412
413
414
415
  	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...
416
417
418
  
  		f->op = audit_to_op(data->fieldflags[i]);
  		if (f->op == Audit_bad)
93315ed6d   Amy Griffis   [PATCH] audit str...
419
  			goto exit_free;
93315ed6d   Amy Griffis   [PATCH] audit str...
420
  		f->type = data->fields[i];
3dc7e3153   Darrel Goeddel   [PATCH] support f...
421
  		f->val = data->values[i];
62062cf8a   Eric Paris   audit: allow chec...
422

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

04305e4af   Ahmed S. Darwish   Audit: Final rena...
700
701
702
  	/* our own copy of lsm_str */
  	lsm_str = kstrdup(sf->lsm_str, GFP_KERNEL);
  	if (unlikely(!lsm_str))
3e1fbd12c   Akinobu Mita   [PATCH] audit: fi...
703
  		return -ENOMEM;
04305e4af   Ahmed S. Darwish   Audit: Final rena...
704
  	df->lsm_str = lsm_str;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
705

04305e4af   Ahmed S. Darwish   Audit: Final rena...
706
707
708
  	/* 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...
709
710
711
  	/* 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...
712
713
714
  		pr_warn("audit rule for LSM \'%s\' is invalid
  ",
  			df->lsm_str);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
715
716
717
718
719
720
721
  		ret = 0;
  	}
  
  	return ret;
  }
  
  /* Duplicate an audit rule.  This will be a deep copy with the exception
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
722
   * of the watch - that pointer is carried over.  The LSM specific fields
3dc7e3153   Darrel Goeddel   [PATCH] support f...
723
   * will be updated in the copy.  The point is to be able to replace the old
f368c07d7   Amy Griffis   [PATCH] audit: pa...
724
725
726
   * 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...
727
  struct audit_entry *audit_dupe_rule(struct audit_krule *old)
3dc7e3153   Darrel Goeddel   [PATCH] support f...
728
729
730
731
  {
  	u32 fcount = old->field_count;
  	struct audit_entry *entry;
  	struct audit_krule *new;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
732
  	char *fk;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
733
734
735
736
737
738
739
740
741
  	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;
041d7b98f   Richard Guy Briggs   audit: restore AU...
742
  	new->pflags = old->pflags;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
743
744
745
746
  	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...
747
  	new->prio = old->prio;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
748
  	new->buflen = old->buflen;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
749
  	new->inode_f = old->inode_f;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
750
  	new->field_count = old->field_count;
ae7b8f410   Eric Paris   Audit: clean up t...
751

74c3cbe33   Al Viro   [PATCH] audit: wa...
752
753
754
755
756
757
758
759
  	/*
  	 * 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...
760
  	memcpy(new->fields, old->fields, sizeof(struct audit_field) * fcount);
04305e4af   Ahmed S. Darwish   Audit: Final rena...
761
  	/* deep copy this information, updating the lsm_rule fields, because
3dc7e3153   Darrel Goeddel   [PATCH] support f...
762
763
764
  	 * 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...
765
766
767
768
769
  		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...
770
771
772
773
774
  		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...
775
  			err = audit_dupe_lsm_field(&new->fields[i],
3dc7e3153   Darrel Goeddel   [PATCH] support f...
776
  						       &old->fields[i]);
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
777
778
779
780
781
782
783
  			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...
784
785
786
787
788
789
  		}
  		if (err) {
  			audit_free_rule(entry);
  			return ERR_PTR(err);
  		}
  	}
ae7b8f410   Eric Paris   Audit: clean up t...
790
791
792
  	if (old->watch) {
  		audit_get_watch(old->watch);
  		new->watch = old->watch;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
793
  	}
3dc7e3153   Darrel Goeddel   [PATCH] support f...
794
795
  	return entry;
  }
f368c07d7   Amy Griffis   [PATCH] audit: pa...
796
797
798
  /* 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...
799
  					   struct list_head **p)
f368c07d7   Amy Griffis   [PATCH] audit: pa...
800
801
  {
  	struct audit_entry *e, *found = NULL;
36c4f1b18   Al Viro   clean up audit_ru...
802
  	struct list_head *list;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
803
  	int h;
36c4f1b18   Al Viro   clean up audit_ru...
804
805
806
807
  	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...
808
809
810
811
812
813
814
815
816
817
  		/* 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...
818
819
  	} else {
  		*p = list = &audit_filter_list[entry->rule.listnr];
f368c07d7   Amy Griffis   [PATCH] audit: pa...
820
821
822
823
824
825
826
827
828
829
830
  	}
  
  	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...
831
832
  static u64 prio_low = ~0ULL/2;
  static u64 prio_high = ~0ULL/2 - 1;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
833
  /* Add rule to given filterlist if not a duplicate. */
36c4f1b18   Al Viro   clean up audit_ru...
834
  static inline int audit_add_rule(struct audit_entry *entry)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
835
  {
93315ed6d   Amy Griffis   [PATCH] audit str...
836
  	struct audit_entry *e;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
837
  	struct audit_watch *watch = entry->rule.watch;
74c3cbe33   Al Viro   [PATCH] audit: wa...
838
  	struct audit_tree *tree = entry->rule.tree;
36c4f1b18   Al Viro   clean up audit_ru...
839
  	struct list_head *list;
ae7b8f410   Eric Paris   Audit: clean up t...
840
  	int err;
471a5c7c8   Al Viro   [PATCH] introduce...
841
842
843
844
845
846
847
848
  #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...
849

f368c07d7   Amy Griffis   [PATCH] audit: pa...
850
  	mutex_lock(&audit_filter_mutex);
36c4f1b18   Al Viro   clean up audit_ru...
851
  	e = audit_find_rule(entry, &list);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
852
  	if (e) {
35fe4d0b1   Eric Paris   Audit: move audit...
853
  		mutex_unlock(&audit_filter_mutex);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
854
  		err = -EEXIST;
74c3cbe33   Al Viro   [PATCH] audit: wa...
855
856
857
  		/* normally audit_add_tree_rule() will free it on failure */
  		if (tree)
  			audit_put_tree(tree);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
858
859
  		goto error;
  	}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
860

f368c07d7   Amy Griffis   [PATCH] audit: pa...
861
862
  	if (watch) {
  		/* audit_filter_mutex is dropped and re-taken during this call */
ae7b8f410   Eric Paris   Audit: clean up t...
863
  		err = audit_add_watch(&entry->rule, &list);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
864
865
  		if (err) {
  			mutex_unlock(&audit_filter_mutex);
2f992ee85   Chen Gang   kernel/auditfilte...
866
867
868
869
870
871
  			/*
  			 * normally audit_add_tree_rule() will free it
  			 * on failure
  			 */
  			if (tree)
  				audit_put_tree(tree);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
872
873
  			goto error;
  		}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
874
  	}
74c3cbe33   Al Viro   [PATCH] audit: wa...
875
876
877
878
879
880
881
  	if (tree) {
  		err = audit_add_tree_rule(&entry->rule);
  		if (err) {
  			mutex_unlock(&audit_filter_mutex);
  			goto error;
  		}
  	}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
882

0590b9335   Al Viro   fixing audit rule...
883
884
885
886
887
888
889
  	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...
890
  	if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
e45aa212e   Al Viro   audit rules order...
891
892
  		list_add(&entry->rule.list,
  			 &audit_rules_list[entry->rule.listnr]);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
893
  		list_add_rcu(&entry->list, list);
6a2bceec0   Amy Griffis   [PATCH] fix AUDIT...
894
  		entry->rule.flags &= ~AUDIT_FILTER_PREPEND;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
895
  	} else {
e45aa212e   Al Viro   audit rules order...
896
897
  		list_add_tail(&entry->rule.list,
  			      &audit_rules_list[entry->rule.listnr]);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
898
899
  		list_add_tail_rcu(&entry->list, list);
  	}
471a5c7c8   Al Viro   [PATCH] introduce...
900
901
902
  #ifdef CONFIG_AUDITSYSCALL
  	if (!dont_count)
  		audit_n_rules++;
e54dc2431   Amy Griffis   [PATCH] audit sig...
903
904
905
  
  	if (!audit_match_signal(entry))
  		audit_signals++;
471a5c7c8   Al Viro   [PATCH] introduce...
906
  #endif
f368c07d7   Amy Griffis   [PATCH] audit: pa...
907
  	mutex_unlock(&audit_filter_mutex);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
908

f368c07d7   Amy Griffis   [PATCH] audit: pa...
909
910
911
   	return 0;
  
  error:
f368c07d7   Amy Griffis   [PATCH] audit: pa...
912
913
914
  	if (watch)
  		audit_put_watch(watch); /* tmp watch, matches initial get */
  	return err;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
915
  }
f368c07d7   Amy Griffis   [PATCH] audit: pa...
916
  /* Remove an existing rule from filterlist. */
36c4f1b18   Al Viro   clean up audit_ru...
917
  static inline int audit_del_rule(struct audit_entry *entry)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
918
919
  {
  	struct audit_entry  *e;
cfcad62c7   Eric Paris   audit: seperate a...
920
  	struct audit_watch *watch = entry->rule.watch;
74c3cbe33   Al Viro   [PATCH] audit: wa...
921
  	struct audit_tree *tree = entry->rule.tree;
36c4f1b18   Al Viro   clean up audit_ru...
922
  	struct list_head *list;
36c4f1b18   Al Viro   clean up audit_ru...
923
  	int ret = 0;
471a5c7c8   Al Viro   [PATCH] introduce...
924
925
926
927
928
929
930
931
  #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...
932

f368c07d7   Amy Griffis   [PATCH] audit: pa...
933
  	mutex_lock(&audit_filter_mutex);
36c4f1b18   Al Viro   clean up audit_ru...
934
  	e = audit_find_rule(entry, &list);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
935
936
937
938
939
  	if (!e) {
  		mutex_unlock(&audit_filter_mutex);
  		ret = -ENOENT;
  		goto out;
  	}
cfcad62c7   Eric Paris   audit: seperate a...
940
  	if (e->rule.watch)
a05fb6cc5   Eric Paris   audit: do not get...
941
  		audit_remove_watch_rule(&e->rule);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
942

74c3cbe33   Al Viro   [PATCH] audit: wa...
943
944
  	if (e->rule.tree)
  		audit_remove_tree_rule(&e->rule);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
945
  	list_del_rcu(&e->list);
e45aa212e   Al Viro   audit rules order...
946
  	list_del(&e->rule.list);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
947
  	call_rcu(&e->rcu, audit_free_rule_rcu);
471a5c7c8   Al Viro   [PATCH] introduce...
948
949
950
  #ifdef CONFIG_AUDITSYSCALL
  	if (!dont_count)
  		audit_n_rules--;
e54dc2431   Amy Griffis   [PATCH] audit sig...
951
952
953
  
  	if (!audit_match_signal(entry))
  		audit_signals--;
471a5c7c8   Al Viro   [PATCH] introduce...
954
  #endif
f368c07d7   Amy Griffis   [PATCH] audit: pa...
955
  	mutex_unlock(&audit_filter_mutex);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
956
  out:
cfcad62c7   Eric Paris   audit: seperate a...
957
958
  	if (watch)
  		audit_put_watch(watch); /* match initial get */
74c3cbe33   Al Viro   [PATCH] audit: wa...
959
960
  	if (tree)
  		audit_put_tree(tree);	/* that's the temporary one */
f368c07d7   Amy Griffis   [PATCH] audit: pa...
961
962
  
  	return ret;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
963
  }
93315ed6d   Amy Griffis   [PATCH] audit str...
964
  /* List rules using struct audit_rule_data. */
f9441639e   Richard Guy Briggs   audit: fix netlin...
965
  static void audit_list_rules(__u32 portid, int seq, struct sk_buff_head *q)
93315ed6d   Amy Griffis   [PATCH] audit str...
966
  {
9044e6bca   Al Viro   [PATCH] fix deadl...
967
  	struct sk_buff *skb;
e45aa212e   Al Viro   audit rules order...
968
  	struct audit_krule *r;
93315ed6d   Amy Griffis   [PATCH] audit str...
969
  	int i;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
970
971
  	/* 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...
972
  	for (i=0; i<AUDIT_NR_FILTERS; i++) {
e45aa212e   Al Viro   audit rules order...
973
  		list_for_each_entry(r, &audit_rules_list[i], list) {
f368c07d7   Amy Griffis   [PATCH] audit: pa...
974
  			struct audit_rule_data *data;
e45aa212e   Al Viro   audit rules order...
975
  			data = audit_krule_to_data(r);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
976
977
  			if (unlikely(!data))
  				break;
f9441639e   Richard Guy Briggs   audit: fix netlin...
978
979
980
  			skb = audit_make_reply(portid, seq, AUDIT_LIST_RULES,
  					       0, 1, data,
  					       sizeof(*data) + data->buflen);
9044e6bca   Al Viro   [PATCH] fix deadl...
981
982
  			if (skb)
  				skb_queue_tail(q, skb);
93315ed6d   Amy Griffis   [PATCH] audit str...
983
984
985
  			kfree(data);
  		}
  	}
f9441639e   Richard Guy Briggs   audit: fix netlin...
986
  	skb = audit_make_reply(portid, seq, AUDIT_LIST_RULES, 1, 1, NULL, 0);
9044e6bca   Al Viro   [PATCH] fix deadl...
987
988
  	if (skb)
  		skb_queue_tail(q, skb);
93315ed6d   Amy Griffis   [PATCH] audit str...
989
  }
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
990
  /* Log rule additions and removals */
dc9eb698f   Eric Paris   audit: stop pushi...
991
  static void audit_log_rule_change(char *action, struct audit_krule *rule, int res)
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
992
993
  {
  	struct audit_buffer *ab;
dc9eb698f   Eric Paris   audit: stop pushi...
994
  	uid_t loginuid = from_kuid(&init_user_ns, audit_get_loginuid(current));
4440e8548   Eric Paris   audit: convert al...
995
  	unsigned int sessionid = audit_get_sessionid(current);
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
996

1a6b9f231   Eric Paris   [AUDIT] make audi...
997
998
  	if (!audit_enabled)
  		return;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
999
1000
1001
  	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
  	if (!ab)
  		return;
dc9eb698f   Eric Paris   audit: stop pushi...
1002
  	audit_log_format(ab, "auid=%u ses=%u" ,loginuid, sessionid);
b122c3767   Eric Paris   audit: use a cons...
1003
  	audit_log_task_context(ab);
9d9609851   Eric Paris   Audit: clean up a...
1004
1005
1006
  	audit_log_format(ab, " op=");
  	audit_log_string(ab, action);
  	audit_log_key(ab, rule->filterkey);
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
1007
1008
1009
  	audit_log_format(ab, " list=%d res=%d", rule->listnr, res);
  	audit_log_end(ab);
  }
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1010
  /**
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1011
   * audit_rule_change - apply all rules to the specified message type
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1012
   * @type: audit message type
f9441639e   Richard Guy Briggs   audit: fix netlin...
1013
   * @portid: target port id for netlink audit messages
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1014
1015
   * @seq: netlink audit message sequence (serial) number
   * @data: payload data
93315ed6d   Amy Griffis   [PATCH] audit str...
1016
   * @datasz: size of payload data
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1017
   */
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1018
1019
  int audit_rule_change(int type, __u32 portid, int seq, void *data,
  			size_t datasz)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1020
  {
93315ed6d   Amy Griffis   [PATCH] audit str...
1021
1022
  	int err = 0;
  	struct audit_entry *entry;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1023

e85322d21   Richard Guy Briggs   audit: cull redun...
1024
1025
1026
  	entry = audit_data_to_entry(data, datasz);
  	if (IS_ERR(entry))
  		return PTR_ERR(entry);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1027
  	switch (type) {
93315ed6d   Amy Griffis   [PATCH] audit str...
1028
  	case AUDIT_ADD_RULE:
36c4f1b18   Al Viro   clean up audit_ru...
1029
  		err = audit_add_rule(entry);
e7df61f4d   Burn Alting   audit: invalid op...
1030
  		audit_log_rule_change("add_rule", &entry->rule, !err);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1031
  		break;
93315ed6d   Amy Griffis   [PATCH] audit str...
1032
  	case AUDIT_DEL_RULE:
36c4f1b18   Al Viro   clean up audit_ru...
1033
  		err = audit_del_rule(entry);
e7df61f4d   Burn Alting   audit: invalid op...
1034
  		audit_log_rule_change("remove_rule", &entry->rule, !err);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1035
1036
  		break;
  	default:
739c95038   Eric Paris   audit: WARN if au...
1037
1038
  		err = -EINVAL;
  		WARN_ON(1);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1039
  	}
e85322d21   Richard Guy Briggs   audit: cull redun...
1040
1041
  	if (err || type == AUDIT_DEL_RULE)
  		audit_free_rule(entry);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1042
1043
  	return err;
  }
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1044
1045
  /**
   * audit_list_rules_send - list the audit rules
d211f177b   Eric W. Biederman   audit: Update kdo...
1046
   * @request_skb: skb of request we are replying to (used to target the reply)
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1047
1048
   * @seq: netlink audit message sequence (serial) number
   */
6f285b19d   Eric W. Biederman   audit: Send repli...
1049
  int audit_list_rules_send(struct sk_buff *request_skb, int seq)
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1050
  {
6f285b19d   Eric W. Biederman   audit: Send repli...
1051
1052
  	u32 portid = NETLINK_CB(request_skb).portid;
  	struct net *net = sock_net(NETLINK_CB(request_skb).sk);
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
  	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...
1066
  	dest->net = get_net(net);
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1067
  	dest->portid = portid;
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
  	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...
1083
  int audit_comparator(u32 left, u32 op, u32 right)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1084
1085
  {
  	switch (op) {
5af75d8d5   Al Viro   audit: validate c...
1086
  	case Audit_equal:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1087
  		return (left == right);
5af75d8d5   Al Viro   audit: validate c...
1088
  	case Audit_not_equal:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1089
  		return (left != right);
5af75d8d5   Al Viro   audit: validate c...
1090
  	case Audit_lt:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1091
  		return (left < right);
5af75d8d5   Al Viro   audit: validate c...
1092
  	case Audit_le:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1093
  		return (left <= right);
5af75d8d5   Al Viro   audit: validate c...
1094
  	case Audit_gt:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1095
  		return (left > right);
5af75d8d5   Al Viro   audit: validate c...
1096
  	case Audit_ge:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1097
  		return (left >= right);
5af75d8d5   Al Viro   audit: validate c...
1098
  	case Audit_bitmask:
74f2345b6   Eric Paris   [PATCH] allow aud...
1099
  		return (left & right);
5af75d8d5   Al Viro   audit: validate c...
1100
  	case Audit_bittest:
74f2345b6   Eric Paris   [PATCH] allow aud...
1101
  		return ((left & right) == right);
5af75d8d5   Al Viro   audit: validate c...
1102
1103
1104
  	default:
  		BUG();
  		return 0;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1105
1106
  	}
  }
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
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
1148
1149
1150
1151
  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...
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
  /**
   * 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...
1181
1182
1183
1184
1185
1186
1187
1188
1189
  /**
   * 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...
1190
  {
e3d6b07b8   Jeff Layton   audit: optimize a...
1191
  	int dlen, pathlen;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1192
  	const char *p;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1193
  	dlen = strlen(dname);
29e9a3467   Eric Paris   audit: make audit...
1194
1195
  	pathlen = strlen(path);
  	if (pathlen < dlen)
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1196
  		return 1;
e3d6b07b8   Jeff Layton   audit: optimize a...
1197
  	parentlen = parentlen == AUDIT_NAME_FULL ? parent_len(path) : parentlen;
29e9a3467   Eric Paris   audit: make audit...
1198
  	if (pathlen - parentlen != dlen)
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1199
  		return 1;
29e9a3467   Eric Paris   audit: make audit...
1200
1201
  
  	p = path + parentlen;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1202

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

62062cf8a   Eric Paris   audit: allow chec...
1206
  static int audit_filter_user_rules(struct audit_krule *rule, int type,
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1207
1208
1209
1210
1211
  				   enum audit_state *state)
  {
  	int i;
  
  	for (i = 0; i < rule->field_count; i++) {
93315ed6d   Amy Griffis   [PATCH] audit str...
1212
  		struct audit_field *f = &rule->fields[i];
f1dc4867f   Richard Guy Briggs   audit: anchor all...
1213
  		pid_t pid;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1214
  		int result = 0;
c53fa1ed9   Patrick McHardy   netlink: kill log...
1215
  		u32 sid;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1216

93315ed6d   Amy Griffis   [PATCH] audit str...
1217
  		switch (f->type) {
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1218
  		case AUDIT_PID:
f1dc4867f   Richard Guy Briggs   audit: anchor all...
1219
1220
  			pid = task_pid_nr(current);
  			result = audit_comparator(pid, f->op, f->val);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1221
1222
  			break;
  		case AUDIT_UID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
1223
  			result = audit_uid_comparator(current_uid(), f->op, f->uid);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1224
1225
  			break;
  		case AUDIT_GID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
1226
  			result = audit_gid_comparator(current_gid(), f->op, f->gid);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1227
1228
  			break;
  		case AUDIT_LOGINUID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
1229
1230
  			result = audit_uid_comparator(audit_get_loginuid(current),
  						  f->op, f->uid);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1231
  			break;
780a7654c   Eric W. Biederman   audit: Make testi...
1232
1233
1234
1235
  		case AUDIT_LOGINUID_SET:
  			result = audit_comparator(audit_loginuid_set(current),
  						  f->op, f->val);
  			break;
62062cf8a   Eric Paris   audit: allow chec...
1236
1237
1238
  		case AUDIT_MSGTYPE:
  			result = audit_comparator(type, f->op, f->val);
  			break;
d29be158a   Miloslav Trmac   Audit: add suppor...
1239
1240
1241
1242
1243
  		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...
1244
1245
1246
  			if (f->lsm_rule) {
  				security_task_getsecid(current, &sid);
  				result = security_audit_rule_match(sid,
d29be158a   Miloslav Trmac   Audit: add suppor...
1247
1248
1249
1250
  								   f->type,
  								   f->op,
  								   f->lsm_rule,
  								   NULL);
c53fa1ed9   Patrick McHardy   netlink: kill log...
1251
  			}
d29be158a   Miloslav Trmac   Audit: add suppor...
1252
  			break;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1253
1254
1255
1256
1257
1258
1259
  		}
  
  		if (!result)
  			return 0;
  	}
  	switch (rule->action) {
  	case AUDIT_NEVER:    *state = AUDIT_DISABLED;	    break;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1260
1261
1262
1263
  	case AUDIT_ALWAYS:   *state = AUDIT_RECORD_CONTEXT; break;
  	}
  	return 1;
  }
62062cf8a   Eric Paris   audit: allow chec...
1264
  int audit_filter_user(int type)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1265
  {
11f57cedc   Ingo Molnar   [PATCH] audit: fi...
1266
  	enum audit_state state = AUDIT_DISABLED;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1267
  	struct audit_entry *e;
724e4fcc8   Richard Guy Briggs   audit: log on err...
1268
1269
1270
  	int rc, ret;
  
  	ret = 1; /* Audit by default */
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1271
1272
1273
  
  	rcu_read_lock();
  	list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) {
724e4fcc8   Richard Guy Briggs   audit: log on err...
1274
1275
1276
  		rc = audit_filter_user_rules(&e->rule, type, &state);
  		if (rc) {
  			if (rc > 0 && state == AUDIT_DISABLED)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1277
1278
1279
1280
1281
  				ret = 0;
  			break;
  		}
  	}
  	rcu_read_unlock();
724e4fcc8   Richard Guy Briggs   audit: log on err...
1282
  	return ret;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1283
1284
1285
1286
1287
1288
  }
  
  int audit_filter_type(int type)
  {
  	struct audit_entry *e;
  	int result = 0;
9ce34218a   Daniel Walker   whitespace fixes:...
1289

fe7752bab   David Woodhouse   [PATCH] Fix audit...
1290
1291
1292
1293
1294
1295
  	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...
1296
  		int i;
93315ed6d   Amy Griffis   [PATCH] audit str...
1297
1298
1299
1300
  		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...
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
  				if (!result)
  					break;
  			}
  		}
  		if (result)
  			goto unlock_and_return;
  	}
  unlock_and_return:
  	rcu_read_unlock();
  	return result;
  }
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1312

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