Blame view

kernel/auditfilter.c 36.1 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;
  }
93315ed6d   Amy Griffis   [PATCH] audit str...
301
302
303
304
305
306
  /* Translate struct audit_rule to kernel's rule respresentation.
   * Exists for backward compatibility with userspace. */
  static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
  {
  	struct audit_entry *entry;
  	int err = 0;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
307
  	int i;
93315ed6d   Amy Griffis   [PATCH] audit str...
308
309
310
311
312
313
  	entry = audit_to_entry_common(rule);
  	if (IS_ERR(entry))
  		goto exit_nofree;
  
  	for (i = 0; i < rule->field_count; i++) {
  		struct audit_field *f = &entry->rule.fields[i];
5af75d8d5   Al Viro   audit: validate c...
314
315
316
317
318
319
320
321
322
323
324
325
326
327
  		u32 n;
  
  		n = rule->fields[i] & (AUDIT_NEGATE|AUDIT_OPERATORS);
  
  		/* Support for legacy operators where
  		 * AUDIT_NEGATE bit signifies != and otherwise assumes == */
  		if (n & AUDIT_NEGATE)
  			f->op = Audit_not_equal;
  		else if (!n)
  			f->op = Audit_equal;
  		else
  			f->op = audit_to_op(n);
  
  		entry->rule.vers_ops = (n & AUDIT_OPERATORS) ? 2 : 1;
93315ed6d   Amy Griffis   [PATCH] audit str...
328

93315ed6d   Amy Griffis   [PATCH] audit str...
329
330
  		f->type = rule->fields[i] & ~(AUDIT_NEGATE|AUDIT_OPERATORS);
  		f->val = rule->values[i];
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
331
332
  		f->uid = INVALID_UID;
  		f->gid = INVALID_GID;
93315ed6d   Amy Griffis   [PATCH] audit str...
333

f368c07d7   Amy Griffis   [PATCH] audit: pa...
334
  		err = -EINVAL;
5af75d8d5   Al Viro   audit: validate c...
335
336
  		if (f->op == Audit_bad)
  			goto exit_free;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
337
  		switch(f->type) {
0a73dccc4   Al Viro   [PATCH] validate ...
338
  		default:
3dc7e3153   Darrel Goeddel   [PATCH] support f...
339
  			goto exit_free;
0a73dccc4   Al Viro   [PATCH] validate ...
340
341
342
343
  		case AUDIT_UID:
  		case AUDIT_EUID:
  		case AUDIT_SUID:
  		case AUDIT_FSUID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
344
345
346
347
348
349
350
351
352
  		case AUDIT_LOGINUID:
  			/* bit ops not implemented for uid comparisons */
  			if (f->op == Audit_bitmask || f->op == Audit_bittest)
  				goto exit_free;
  
  			f->uid = make_kuid(current_user_ns(), f->val);
  			if (!uid_valid(f->uid))
  				goto exit_free;
  			break;
0a73dccc4   Al Viro   [PATCH] validate ...
353
354
355
356
  		case AUDIT_GID:
  		case AUDIT_EGID:
  		case AUDIT_SGID:
  		case AUDIT_FSGID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
357
358
359
360
361
362
363
364
365
  			/* bit ops not implemented for gid comparisons */
  			if (f->op == Audit_bitmask || f->op == Audit_bittest)
  				goto exit_free;
  
  			f->gid = make_kgid(current_user_ns(), f->val);
  			if (!gid_valid(f->gid))
  				goto exit_free;
  			break;
  		case AUDIT_PID:
0a73dccc4   Al Viro   [PATCH] validate ...
366
  		case AUDIT_PERS:
0a73dccc4   Al Viro   [PATCH] validate ...
367
  		case AUDIT_MSGTYPE:
3b33ac318   Steve Grubb   [PATCH] fix ppid ...
368
  		case AUDIT_PPID:
0a73dccc4   Al Viro   [PATCH] validate ...
369
370
371
372
  		case AUDIT_DEVMAJOR:
  		case AUDIT_DEVMINOR:
  		case AUDIT_EXIT:
  		case AUDIT_SUCCESS:
74f2345b6   Eric Paris   [PATCH] allow aud...
373
  			/* bit ops are only useful on syscall args */
5af75d8d5   Al Viro   audit: validate c...
374
  			if (f->op == Audit_bitmask || f->op == Audit_bittest)
74f2345b6   Eric Paris   [PATCH] allow aud...
375
  				goto exit_free;
74f2345b6   Eric Paris   [PATCH] allow aud...
376
  			break;
0a73dccc4   Al Viro   [PATCH] validate ...
377
378
379
380
381
  		case AUDIT_ARG0:
  		case AUDIT_ARG1:
  		case AUDIT_ARG2:
  		case AUDIT_ARG3:
  			break;
4b8a311bb   Eric Paris   [PATCH] arch filt...
382
383
  		/* arch is only allowed to be = or != */
  		case AUDIT_ARCH:
5af75d8d5   Al Viro   audit: validate c...
384
  			if (f->op != Audit_not_equal && f->op != Audit_equal)
4b8a311bb   Eric Paris   [PATCH] arch filt...
385
  				goto exit_free;
e54dc2431   Amy Griffis   [PATCH] audit sig...
386
  			entry->rule.arch_f = f;
4b8a311bb   Eric Paris   [PATCH] arch filt...
387
  			break;
55669bfa1   Al Viro   [PATCH] audit: AU...
388
389
390
391
  		case AUDIT_PERM:
  			if (f->val & ~15)
  				goto exit_free;
  			break;
8b67dca94   Al Viro   [PATCH] new predi...
392
  		case AUDIT_FILETYPE:
5ef30ee53   Eric Paris   audit: make filet...
393
  			if (f->val & ~S_IFMT)
8b67dca94   Al Viro   [PATCH] new predi...
394
395
  				goto exit_free;
  			break;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
396
397
398
399
400
  		case AUDIT_INODE:
  			err = audit_to_inode(&entry->rule, f);
  			if (err)
  				goto exit_free;
  			break;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
401
  		}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
402
  	}
93315ed6d   Amy Griffis   [PATCH] audit str...
403

5af75d8d5   Al Viro   audit: validate c...
404
405
  	if (entry->rule.inode_f && entry->rule.inode_f->op == Audit_not_equal)
  		entry->rule.inode_f = NULL;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
406

93315ed6d   Amy Griffis   [PATCH] audit str...
407
408
409
410
411
412
  exit_nofree:
  	return entry;
  
  exit_free:
  	audit_free_rule(entry);
  	return ERR_PTR(err);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
413
  }
93315ed6d   Amy Griffis   [PATCH] audit str...
414
415
416
  /* 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...
417
  {
93315ed6d   Amy Griffis   [PATCH] audit str...
418
419
420
  	int err = 0;
  	struct audit_entry *entry;
  	void *bufp;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
421
  	size_t remain = datasz - sizeof(struct audit_rule_data);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
422
  	int i;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
423
  	char *str;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
424

93315ed6d   Amy Griffis   [PATCH] audit str...
425
426
427
  	entry = audit_to_entry_common((struct audit_rule *)data);
  	if (IS_ERR(entry))
  		goto exit_nofree;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
428

93315ed6d   Amy Griffis   [PATCH] audit str...
429
430
431
432
433
434
  	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...
435
436
437
  
  		f->op = audit_to_op(data->fieldflags[i]);
  		if (f->op == Audit_bad)
93315ed6d   Amy Griffis   [PATCH] audit str...
438
  			goto exit_free;
93315ed6d   Amy Griffis   [PATCH] audit str...
439
  		f->type = data->fields[i];
3dc7e3153   Darrel Goeddel   [PATCH] support f...
440
  		f->val = data->values[i];
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
441
442
  		f->uid = INVALID_UID;
  		f->gid = INVALID_GID;
04305e4af   Ahmed S. Darwish   Audit: Final rena...
443
444
  		f->lsm_str = NULL;
  		f->lsm_rule = NULL;
93315ed6d   Amy Griffis   [PATCH] audit str...
445
  		switch(f->type) {
0a73dccc4   Al Viro   [PATCH] validate ...
446
447
448
449
  		case AUDIT_UID:
  		case AUDIT_EUID:
  		case AUDIT_SUID:
  		case AUDIT_FSUID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
450
451
452
453
454
455
456
457
458
459
  		case AUDIT_LOGINUID:
  		case AUDIT_OBJ_UID:
  			/* bit ops not implemented for uid comparisons */
  			if (f->op == Audit_bitmask || f->op == Audit_bittest)
  				goto exit_free;
  
  			f->uid = make_kuid(current_user_ns(), f->val);
  			if (!uid_valid(f->uid))
  				goto exit_free;
  			break;
0a73dccc4   Al Viro   [PATCH] validate ...
460
461
462
463
  		case AUDIT_GID:
  		case AUDIT_EGID:
  		case AUDIT_SGID:
  		case AUDIT_FSGID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
464
465
466
467
468
469
470
471
472
473
  		case AUDIT_OBJ_GID:
  			/* bit ops not implemented for gid comparisons */
  			if (f->op == Audit_bitmask || f->op == Audit_bittest)
  				goto exit_free;
  
  			f->gid = make_kgid(current_user_ns(), f->val);
  			if (!gid_valid(f->gid))
  				goto exit_free;
  			break;
  		case AUDIT_PID:
0a73dccc4   Al Viro   [PATCH] validate ...
474
  		case AUDIT_PERS:
0a73dccc4   Al Viro   [PATCH] validate ...
475
476
477
478
479
480
481
482
483
484
485
  		case AUDIT_MSGTYPE:
  		case AUDIT_PPID:
  		case AUDIT_DEVMAJOR:
  		case AUDIT_DEVMINOR:
  		case AUDIT_EXIT:
  		case AUDIT_SUCCESS:
  		case AUDIT_ARG0:
  		case AUDIT_ARG1:
  		case AUDIT_ARG2:
  		case AUDIT_ARG3:
  			break;
e54dc2431   Amy Griffis   [PATCH] audit sig...
486
487
488
  		case AUDIT_ARCH:
  			entry->rule.arch_f = f;
  			break;
3a6b9f85c   Darrel Goeddel   [PATCH] audit: re...
489
490
491
492
493
  		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...
494
495
496
497
498
  		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...
499
500
501
502
  			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...
503
  			err = security_audit_rule_init(f->type, f->op, str,
04305e4af   Ahmed S. Darwish   Audit: Final rena...
504
  						       (void **)&f->lsm_rule);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
505
506
507
  			/* Keep currently invalid fields around in case they
  			 * become valid after a policy reload. */
  			if (err == -EINVAL) {
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
508
  				printk(KERN_WARNING "audit rule for LSM "
3dc7e3153   Darrel Goeddel   [PATCH] support f...
509
510
511
512
513
514
515
516
  				       "\'%s\' is invalid
  ",  str);
  				err = 0;
  			}
  			if (err) {
  				kfree(str);
  				goto exit_free;
  			} else
04305e4af   Ahmed S. Darwish   Audit: Final rena...
517
  				f->lsm_str = str;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
518
  			break;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
519
520
521
522
523
524
525
526
527
528
529
530
  		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...
531
532
533
534
535
536
537
538
539
540
541
  		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...
542
543
544
545
546
  		case AUDIT_INODE:
  			err = audit_to_inode(&entry->rule, f);
  			if (err)
  				goto exit_free;
  			break;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
547
  		case AUDIT_FILTERKEY:
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
548
549
550
551
552
553
554
555
  			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;
55669bfa1   Al Viro   [PATCH] audit: AU...
556
557
558
559
  		case AUDIT_PERM:
  			if (f->val & ~15)
  				goto exit_free;
  			break;
8b67dca94   Al Viro   [PATCH] new predi...
560
  		case AUDIT_FILETYPE:
5ef30ee53   Eric Paris   audit: make filet...
561
  			if (f->val & ~S_IFMT)
8b67dca94   Al Viro   [PATCH] new predi...
562
563
  				goto exit_free;
  			break;
02d86a568   Eric Paris   audit: allow inte...
564
565
566
567
  		case AUDIT_FIELD_COMPARE:
  			if (f->val > AUDIT_MAX_FIELD_COMPARE)
  				goto exit_free;
  			break;
0a73dccc4   Al Viro   [PATCH] validate ...
568
569
  		default:
  			goto exit_free;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
570
571
  		}
  	}
5af75d8d5   Al Viro   audit: validate c...
572
573
  	if (entry->rule.inode_f && entry->rule.inode_f->op == Audit_not_equal)
  		entry->rule.inode_f = NULL;
93315ed6d   Amy Griffis   [PATCH] audit str...
574
575
576
577
578
579
580
581
582
583
  
  exit_nofree:
  	return entry;
  
  exit_free:
  	audit_free_rule(entry);
  	return ERR_PTR(err);
  }
  
  /* Pack a filter field's string representation into data block. */
74c3cbe33   Al Viro   [PATCH] audit: wa...
584
  static inline size_t audit_pack_string(void **bufp, const char *str)
93315ed6d   Amy Griffis   [PATCH] audit str...
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
  {
  	size_t len = strlen(str);
  
  	memcpy(*bufp, str, len);
  	*bufp += len;
  
  	return len;
  }
  
  /* Translate kernel rule respresentation to struct audit_rule.
   * Exists for backward compatibility with userspace. */
  static struct audit_rule *audit_krule_to_rule(struct audit_krule *krule)
  {
  	struct audit_rule *rule;
  	int i;
4668edc33   Burman Yan   [PATCH] kernel co...
600
  	rule = kzalloc(sizeof(*rule), GFP_KERNEL);
93315ed6d   Amy Griffis   [PATCH] audit str...
601
  	if (unlikely(!rule))
0a3b483e8   Amy Griffis   [PATCH] fix audit...
602
  		return NULL;
93315ed6d   Amy Griffis   [PATCH] audit str...
603
604
605
606
607
608
609
610
611
  
  	rule->flags = krule->flags | krule->listnr;
  	rule->action = krule->action;
  	rule->field_count = krule->field_count;
  	for (i = 0; i < rule->field_count; i++) {
  		rule->values[i] = krule->fields[i].val;
  		rule->fields[i] = krule->fields[i].type;
  
  		if (krule->vers_ops == 1) {
5af75d8d5   Al Viro   audit: validate c...
612
  			if (krule->fields[i].op == Audit_not_equal)
93315ed6d   Amy Griffis   [PATCH] audit str...
613
614
  				rule->fields[i] |= AUDIT_NEGATE;
  		} else {
5af75d8d5   Al Viro   audit: validate c...
615
  			rule->fields[i] |= audit_ops[krule->fields[i].op];
93315ed6d   Amy Griffis   [PATCH] audit str...
616
617
618
619
620
621
  		}
  	}
  	for (i = 0; i < AUDIT_BITMASK_SIZE; i++) rule->mask[i] = krule->mask[i];
  
  	return rule;
  }
fe7752bab   David Woodhouse   [PATCH] Fix audit...
622

93315ed6d   Amy Griffis   [PATCH] audit str...
623
624
625
626
627
628
629
630
631
  /* 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...
632
  		return NULL;
93315ed6d   Amy Griffis   [PATCH] audit str...
633
634
635
636
637
638
639
640
641
642
  	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...
643
  		data->fieldflags[i] = audit_ops[f->op];
93315ed6d   Amy Griffis   [PATCH] audit str...
644
  		switch(f->type) {
3a6b9f85c   Darrel Goeddel   [PATCH] audit: re...
645
646
647
648
649
  		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...
650
651
652
653
654
  		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...
655
  			data->buflen += data->values[i] =
04305e4af   Ahmed S. Darwish   Audit: Final rena...
656
  				audit_pack_string(&bufp, f->lsm_str);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
657
  			break;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
658
659
  		case AUDIT_WATCH:
  			data->buflen += data->values[i] =
cfcad62c7   Eric Paris   audit: seperate a...
660
661
  				audit_pack_string(&bufp,
  						  audit_watch_path(krule->watch));
f368c07d7   Amy Griffis   [PATCH] audit: pa...
662
  			break;
74c3cbe33   Al Viro   [PATCH] audit: wa...
663
664
665
666
667
  		case AUDIT_DIR:
  			data->buflen += data->values[i] =
  				audit_pack_string(&bufp,
  						  audit_tree_path(krule->tree));
  			break;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
668
669
670
671
  		case AUDIT_FILTERKEY:
  			data->buflen += data->values[i] =
  				audit_pack_string(&bufp, krule->filterkey);
  			break;
93315ed6d   Amy Griffis   [PATCH] audit str...
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
  		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...
691
692
693
  		return 1;
  
  	for (i = 0; i < a->field_count; i++) {
93315ed6d   Amy Griffis   [PATCH] audit str...
694
695
  		if (a->fields[i].type != b->fields[i].type ||
  		    a->fields[i].op != b->fields[i].op)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
696
  			return 1;
93315ed6d   Amy Griffis   [PATCH] audit str...
697
698
  
  		switch(a->fields[i].type) {
3a6b9f85c   Darrel Goeddel   [PATCH] audit: re...
699
700
701
702
703
  		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...
704
705
706
707
708
  		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...
709
  			if (strcmp(a->fields[i].lsm_str, b->fields[i].lsm_str))
3dc7e3153   Darrel Goeddel   [PATCH] support f...
710
711
  				return 1;
  			break;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
712
  		case AUDIT_WATCH:
cfcad62c7   Eric Paris   audit: seperate a...
713
714
  			if (strcmp(audit_watch_path(a->watch),
  				   audit_watch_path(b->watch)))
f368c07d7   Amy Griffis   [PATCH] audit: pa...
715
716
  				return 1;
  			break;
74c3cbe33   Al Viro   [PATCH] audit: wa...
717
718
719
720
721
  		case AUDIT_DIR:
  			if (strcmp(audit_tree_path(a->tree),
  				   audit_tree_path(b->tree)))
  				return 1;
  			break;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
722
723
724
725
726
  		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...
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
  		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...
744
745
746
747
  		default:
  			if (a->fields[i].val != b->fields[i].val)
  				return 1;
  		}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
748
749
750
751
752
753
754
755
  	}
  
  	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...
756
  /* Duplicate LSM field information.  The lsm_rule is opaque, so must be
3dc7e3153   Darrel Goeddel   [PATCH] support f...
757
   * re-initialized. */
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
758
  static inline int audit_dupe_lsm_field(struct audit_field *df,
3dc7e3153   Darrel Goeddel   [PATCH] support f...
759
760
761
  					   struct audit_field *sf)
  {
  	int ret = 0;
04305e4af   Ahmed S. Darwish   Audit: Final rena...
762
  	char *lsm_str;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
763

04305e4af   Ahmed S. Darwish   Audit: Final rena...
764
765
766
  	/* our own copy of lsm_str */
  	lsm_str = kstrdup(sf->lsm_str, GFP_KERNEL);
  	if (unlikely(!lsm_str))
3e1fbd12c   Akinobu Mita   [PATCH] audit: fi...
767
  		return -ENOMEM;
04305e4af   Ahmed S. Darwish   Audit: Final rena...
768
  	df->lsm_str = lsm_str;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
769

04305e4af   Ahmed S. Darwish   Audit: Final rena...
770
771
772
  	/* 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...
773
774
775
  	/* Keep currently invalid fields around in case they
  	 * become valid after a policy reload. */
  	if (ret == -EINVAL) {
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
776
  		printk(KERN_WARNING "audit rule for LSM \'%s\' is "
04305e4af   Ahmed S. Darwish   Audit: Final rena...
777
778
  		       "invalid
  ", df->lsm_str);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
779
780
781
782
783
784
785
  		ret = 0;
  	}
  
  	return ret;
  }
  
  /* Duplicate an audit rule.  This will be a deep copy with the exception
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
786
   * of the watch - that pointer is carried over.  The LSM specific fields
3dc7e3153   Darrel Goeddel   [PATCH] support f...
787
   * will be updated in the copy.  The point is to be able to replace the old
f368c07d7   Amy Griffis   [PATCH] audit: pa...
788
789
790
   * 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...
791
  struct audit_entry *audit_dupe_rule(struct audit_krule *old)
3dc7e3153   Darrel Goeddel   [PATCH] support f...
792
793
794
795
  {
  	u32 fcount = old->field_count;
  	struct audit_entry *entry;
  	struct audit_krule *new;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
796
  	char *fk;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
797
798
799
800
801
802
803
804
805
806
807
808
809
  	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...
810
  	new->prio = old->prio;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
811
  	new->buflen = old->buflen;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
812
  	new->inode_f = old->inode_f;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
813
  	new->field_count = old->field_count;
ae7b8f410   Eric Paris   Audit: clean up t...
814

74c3cbe33   Al Viro   [PATCH] audit: wa...
815
816
817
818
819
820
821
822
  	/*
  	 * 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...
823
  	memcpy(new->fields, old->fields, sizeof(struct audit_field) * fcount);
04305e4af   Ahmed S. Darwish   Audit: Final rena...
824
  	/* deep copy this information, updating the lsm_rule fields, because
3dc7e3153   Darrel Goeddel   [PATCH] support f...
825
826
827
  	 * 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...
828
829
830
831
832
  		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...
833
834
835
836
837
  		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...
838
  			err = audit_dupe_lsm_field(&new->fields[i],
3dc7e3153   Darrel Goeddel   [PATCH] support f...
839
  						       &old->fields[i]);
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
840
841
842
843
844
845
846
  			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...
847
848
849
850
851
852
  		}
  		if (err) {
  			audit_free_rule(entry);
  			return ERR_PTR(err);
  		}
  	}
ae7b8f410   Eric Paris   Audit: clean up t...
853
854
855
  	if (old->watch) {
  		audit_get_watch(old->watch);
  		new->watch = old->watch;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
856
  	}
3dc7e3153   Darrel Goeddel   [PATCH] support f...
857
858
  	return entry;
  }
f368c07d7   Amy Griffis   [PATCH] audit: pa...
859
860
861
  /* 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...
862
  					   struct list_head **p)
f368c07d7   Amy Griffis   [PATCH] audit: pa...
863
864
  {
  	struct audit_entry *e, *found = NULL;
36c4f1b18   Al Viro   clean up audit_ru...
865
  	struct list_head *list;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
866
  	int h;
36c4f1b18   Al Viro   clean up audit_ru...
867
868
869
870
  	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...
871
872
873
874
875
876
877
878
879
880
  		/* 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...
881
882
  	} else {
  		*p = list = &audit_filter_list[entry->rule.listnr];
f368c07d7   Amy Griffis   [PATCH] audit: pa...
883
884
885
886
887
888
889
890
891
892
893
  	}
  
  	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...
894
895
  static u64 prio_low = ~0ULL/2;
  static u64 prio_high = ~0ULL/2 - 1;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
896
  /* Add rule to given filterlist if not a duplicate. */
36c4f1b18   Al Viro   clean up audit_ru...
897
  static inline int audit_add_rule(struct audit_entry *entry)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
898
  {
93315ed6d   Amy Griffis   [PATCH] audit str...
899
  	struct audit_entry *e;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
900
  	struct audit_watch *watch = entry->rule.watch;
74c3cbe33   Al Viro   [PATCH] audit: wa...
901
  	struct audit_tree *tree = entry->rule.tree;
36c4f1b18   Al Viro   clean up audit_ru...
902
  	struct list_head *list;
ae7b8f410   Eric Paris   Audit: clean up t...
903
  	int err;
471a5c7c8   Al Viro   [PATCH] introduce...
904
905
906
907
908
909
910
911
  #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...
912

f368c07d7   Amy Griffis   [PATCH] audit: pa...
913
  	mutex_lock(&audit_filter_mutex);
36c4f1b18   Al Viro   clean up audit_ru...
914
  	e = audit_find_rule(entry, &list);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
915
  	if (e) {
35fe4d0b1   Eric Paris   Audit: move audit...
916
  		mutex_unlock(&audit_filter_mutex);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
917
  		err = -EEXIST;
74c3cbe33   Al Viro   [PATCH] audit: wa...
918
919
920
  		/* normally audit_add_tree_rule() will free it on failure */
  		if (tree)
  			audit_put_tree(tree);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
921
922
  		goto error;
  	}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
923

f368c07d7   Amy Griffis   [PATCH] audit: pa...
924
925
  	if (watch) {
  		/* audit_filter_mutex is dropped and re-taken during this call */
ae7b8f410   Eric Paris   Audit: clean up t...
926
  		err = audit_add_watch(&entry->rule, &list);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
927
928
929
930
  		if (err) {
  			mutex_unlock(&audit_filter_mutex);
  			goto error;
  		}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
931
  	}
74c3cbe33   Al Viro   [PATCH] audit: wa...
932
933
934
935
936
937
938
  	if (tree) {
  		err = audit_add_tree_rule(&entry->rule);
  		if (err) {
  			mutex_unlock(&audit_filter_mutex);
  			goto error;
  		}
  	}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
939

0590b9335   Al Viro   fixing audit rule...
940
941
942
943
944
945
946
  	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...
947
  	if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
e45aa212e   Al Viro   audit rules order...
948
949
  		list_add(&entry->rule.list,
  			 &audit_rules_list[entry->rule.listnr]);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
950
  		list_add_rcu(&entry->list, list);
6a2bceec0   Amy Griffis   [PATCH] fix AUDIT...
951
  		entry->rule.flags &= ~AUDIT_FILTER_PREPEND;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
952
  	} else {
e45aa212e   Al Viro   audit rules order...
953
954
  		list_add_tail(&entry->rule.list,
  			      &audit_rules_list[entry->rule.listnr]);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
955
956
  		list_add_tail_rcu(&entry->list, list);
  	}
471a5c7c8   Al Viro   [PATCH] introduce...
957
958
959
  #ifdef CONFIG_AUDITSYSCALL
  	if (!dont_count)
  		audit_n_rules++;
e54dc2431   Amy Griffis   [PATCH] audit sig...
960
961
962
  
  	if (!audit_match_signal(entry))
  		audit_signals++;
471a5c7c8   Al Viro   [PATCH] introduce...
963
  #endif
f368c07d7   Amy Griffis   [PATCH] audit: pa...
964
  	mutex_unlock(&audit_filter_mutex);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
965

f368c07d7   Amy Griffis   [PATCH] audit: pa...
966
967
968
   	return 0;
  
  error:
f368c07d7   Amy Griffis   [PATCH] audit: pa...
969
970
971
  	if (watch)
  		audit_put_watch(watch); /* tmp watch, matches initial get */
  	return err;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
972
  }
f368c07d7   Amy Griffis   [PATCH] audit: pa...
973
  /* Remove an existing rule from filterlist. */
36c4f1b18   Al Viro   clean up audit_ru...
974
  static inline int audit_del_rule(struct audit_entry *entry)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
975
976
  {
  	struct audit_entry  *e;
cfcad62c7   Eric Paris   audit: seperate a...
977
  	struct audit_watch *watch = entry->rule.watch;
74c3cbe33   Al Viro   [PATCH] audit: wa...
978
  	struct audit_tree *tree = entry->rule.tree;
36c4f1b18   Al Viro   clean up audit_ru...
979
  	struct list_head *list;
36c4f1b18   Al Viro   clean up audit_ru...
980
  	int ret = 0;
471a5c7c8   Al Viro   [PATCH] introduce...
981
982
983
984
985
986
987
988
  #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...
989

f368c07d7   Amy Griffis   [PATCH] audit: pa...
990
  	mutex_lock(&audit_filter_mutex);
36c4f1b18   Al Viro   clean up audit_ru...
991
  	e = audit_find_rule(entry, &list);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
992
993
994
995
996
  	if (!e) {
  		mutex_unlock(&audit_filter_mutex);
  		ret = -ENOENT;
  		goto out;
  	}
cfcad62c7   Eric Paris   audit: seperate a...
997
  	if (e->rule.watch)
a05fb6cc5   Eric Paris   audit: do not get...
998
  		audit_remove_watch_rule(&e->rule);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
999

74c3cbe33   Al Viro   [PATCH] audit: wa...
1000
1001
  	if (e->rule.tree)
  		audit_remove_tree_rule(&e->rule);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1002
  	list_del_rcu(&e->list);
e45aa212e   Al Viro   audit rules order...
1003
  	list_del(&e->rule.list);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1004
  	call_rcu(&e->rcu, audit_free_rule_rcu);
471a5c7c8   Al Viro   [PATCH] introduce...
1005
1006
1007
  #ifdef CONFIG_AUDITSYSCALL
  	if (!dont_count)
  		audit_n_rules--;
e54dc2431   Amy Griffis   [PATCH] audit sig...
1008
1009
1010
  
  	if (!audit_match_signal(entry))
  		audit_signals--;
471a5c7c8   Al Viro   [PATCH] introduce...
1011
  #endif
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1012
  	mutex_unlock(&audit_filter_mutex);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1013
  out:
cfcad62c7   Eric Paris   audit: seperate a...
1014
1015
  	if (watch)
  		audit_put_watch(watch); /* match initial get */
74c3cbe33   Al Viro   [PATCH] audit: wa...
1016
1017
  	if (tree)
  		audit_put_tree(tree);	/* that's the temporary one */
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1018
1019
  
  	return ret;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1020
  }
93315ed6d   Amy Griffis   [PATCH] audit str...
1021
1022
  /* List rules using struct audit_rule.  Exists for backward
   * compatibility with userspace. */
9044e6bca   Al Viro   [PATCH] fix deadl...
1023
  static void audit_list(int pid, int seq, struct sk_buff_head *q)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1024
  {
9044e6bca   Al Viro   [PATCH] fix deadl...
1025
  	struct sk_buff *skb;
e45aa212e   Al Viro   audit rules order...
1026
  	struct audit_krule *r;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1027
  	int i;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1028
1029
  	/* This is a blocking read, so use audit_filter_mutex instead of rcu
  	 * iterator to sync with list writers. */
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1030
  	for (i=0; i<AUDIT_NR_FILTERS; i++) {
e45aa212e   Al Viro   audit rules order...
1031
  		list_for_each_entry(r, &audit_rules_list[i], list) {
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1032
  			struct audit_rule *rule;
e45aa212e   Al Viro   audit rules order...
1033
  			rule = audit_krule_to_rule(r);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1034
1035
1036
1037
1038
1039
1040
1041
1042
  			if (unlikely(!rule))
  				break;
  			skb = audit_make_reply(pid, seq, AUDIT_LIST, 0, 1,
  					 rule, sizeof(*rule));
  			if (skb)
  				skb_queue_tail(q, skb);
  			kfree(rule);
  		}
  	}
9044e6bca   Al Viro   [PATCH] fix deadl...
1043
1044
1045
  	skb = audit_make_reply(pid, seq, AUDIT_LIST, 1, 1, NULL, 0);
  	if (skb)
  		skb_queue_tail(q, skb);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1046
  }
93315ed6d   Amy Griffis   [PATCH] audit str...
1047
  /* List rules using struct audit_rule_data. */
9044e6bca   Al Viro   [PATCH] fix deadl...
1048
  static void audit_list_rules(int pid, int seq, struct sk_buff_head *q)
93315ed6d   Amy Griffis   [PATCH] audit str...
1049
  {
9044e6bca   Al Viro   [PATCH] fix deadl...
1050
  	struct sk_buff *skb;
e45aa212e   Al Viro   audit rules order...
1051
  	struct audit_krule *r;
93315ed6d   Amy Griffis   [PATCH] audit str...
1052
  	int i;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1053
1054
  	/* 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...
1055
  	for (i=0; i<AUDIT_NR_FILTERS; i++) {
e45aa212e   Al Viro   audit rules order...
1056
  		list_for_each_entry(r, &audit_rules_list[i], list) {
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1057
  			struct audit_rule_data *data;
e45aa212e   Al Viro   audit rules order...
1058
  			data = audit_krule_to_data(r);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1059
1060
1061
1062
  			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...
1063
1064
  			if (skb)
  				skb_queue_tail(q, skb);
93315ed6d   Amy Griffis   [PATCH] audit str...
1065
1066
1067
  			kfree(data);
  		}
  	}
9044e6bca   Al Viro   [PATCH] fix deadl...
1068
1069
1070
  	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...
1071
  }
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
1072
  /* Log rule additions and removals */
e1760bd5f   Eric W. Biederman   userns: Convert t...
1073
  static void audit_log_rule_change(kuid_t loginuid, u32 sessionid, u32 sid,
2532386f4   Eric Paris   Audit: collect se...
1074
1075
  				  char *action, struct audit_krule *rule,
  				  int res)
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
1076
1077
  {
  	struct audit_buffer *ab;
1a6b9f231   Eric Paris   [AUDIT] make audi...
1078
1079
  	if (!audit_enabled)
  		return;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
1080
1081
1082
  	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
  	if (!ab)
  		return;
e1760bd5f   Eric W. Biederman   userns: Convert t...
1083
1084
  	audit_log_format(ab, "auid=%u ses=%u",
  			 from_kuid(&init_user_ns, loginuid), sessionid);
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
1085
1086
1087
  	if (sid) {
  		char *ctx = NULL;
  		u32 len;
2a862b32f   Ahmed S. Darwish   Audit: use new LS...
1088
  		if (security_secid_to_secctx(sid, &ctx, &len))
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
1089
  			audit_log_format(ab, " ssid=%u", sid);
2a862b32f   Ahmed S. Darwish   Audit: use new LS...
1090
  		else {
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
1091
  			audit_log_format(ab, " subj=%s", ctx);
2a862b32f   Ahmed S. Darwish   Audit: use new LS...
1092
1093
  			security_release_secctx(ctx, len);
  		}
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
1094
  	}
9d9609851   Eric Paris   Audit: clean up a...
1095
1096
1097
  	audit_log_format(ab, " op=");
  	audit_log_string(ab, action);
  	audit_log_key(ab, rule->filterkey);
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
1098
1099
1100
  	audit_log_format(ab, " list=%d res=%d", rule->listnr, res);
  	audit_log_end(ab);
  }
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1101
1102
1103
1104
1105
1106
1107
  /**
   * audit_receive_filter - apply all rules to the specified message type
   * @type: audit message type
   * @pid: target pid for netlink audit messages
   * @uid: target uid for netlink audit messages
   * @seq: netlink audit message sequence (serial) number
   * @data: payload data
93315ed6d   Amy Griffis   [PATCH] audit str...
1108
   * @datasz: size of payload data
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1109
   * @loginuid: loginuid of sender
9f0aecdd1   Randy Dunlap   [PATCH] audit: fi...
1110
   * @sessionid: sessionid for netlink audit message
ce29b682e   Steve Grubb   [PATCH] More user...
1111
   * @sid: SE Linux Security ID of sender
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1112
   */
017143fec   Eric W. Biederman   audit: Remove the...
1113
  int audit_receive_filter(int type, int pid, int seq, void *data,
e1760bd5f   Eric W. Biederman   userns: Convert t...
1114
  			 size_t datasz, kuid_t loginuid, u32 sessionid, u32 sid)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1115
1116
  {
  	struct task_struct *tsk;
9044e6bca   Al Viro   [PATCH] fix deadl...
1117
  	struct audit_netlink_list *dest;
93315ed6d   Amy Griffis   [PATCH] audit str...
1118
1119
  	int err = 0;
  	struct audit_entry *entry;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1120
1121
1122
  
  	switch (type) {
  	case AUDIT_LIST:
93315ed6d   Amy Griffis   [PATCH] audit str...
1123
  	case AUDIT_LIST_RULES:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1124
1125
1126
1127
1128
  		/* 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:...
1129

9044e6bca   Al Viro   [PATCH] fix deadl...
1130
  		dest = kmalloc(sizeof(struct audit_netlink_list), GFP_KERNEL);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1131
1132
  		if (!dest)
  			return -ENOMEM;
9044e6bca   Al Viro   [PATCH] fix deadl...
1133
1134
  		dest->pid = pid;
  		skb_queue_head_init(&dest->q);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1135

f368c07d7   Amy Griffis   [PATCH] audit: pa...
1136
  		mutex_lock(&audit_filter_mutex);
93315ed6d   Amy Griffis   [PATCH] audit str...
1137
  		if (type == AUDIT_LIST)
9044e6bca   Al Viro   [PATCH] fix deadl...
1138
  			audit_list(pid, seq, &dest->q);
93315ed6d   Amy Griffis   [PATCH] audit str...
1139
  		else
9044e6bca   Al Viro   [PATCH] fix deadl...
1140
  			audit_list_rules(pid, seq, &dest->q);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1141
  		mutex_unlock(&audit_filter_mutex);
9044e6bca   Al Viro   [PATCH] fix deadl...
1142
1143
  
  		tsk = kthread_run(audit_send_list, dest, "audit_send_list");
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1144
  		if (IS_ERR(tsk)) {
9044e6bca   Al Viro   [PATCH] fix deadl...
1145
  			skb_queue_purge(&dest->q);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1146
1147
1148
1149
1150
  			kfree(dest);
  			err = PTR_ERR(tsk);
  		}
  		break;
  	case AUDIT_ADD:
93315ed6d   Amy Griffis   [PATCH] audit str...
1151
1152
1153
1154
1155
1156
1157
  	case AUDIT_ADD_RULE:
  		if (type == AUDIT_ADD)
  			entry = audit_rule_to_entry(data);
  		else
  			entry = audit_data_to_entry(data, datasz);
  		if (IS_ERR(entry))
  			return PTR_ERR(entry);
36c4f1b18   Al Viro   clean up audit_ru...
1158
  		err = audit_add_rule(entry);
9d9609851   Eric Paris   Audit: clean up a...
1159
  		audit_log_rule_change(loginuid, sessionid, sid, "add rule",
2532386f4   Eric Paris   Audit: collect se...
1160
  				      &entry->rule, !err);
5d3301088   Al Viro   [PATCH] add/remov...
1161
1162
  
  		if (err)
93315ed6d   Amy Griffis   [PATCH] audit str...
1163
  			audit_free_rule(entry);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1164
1165
  		break;
  	case AUDIT_DEL:
93315ed6d   Amy Griffis   [PATCH] audit str...
1166
1167
1168
1169
1170
1171
1172
  	case AUDIT_DEL_RULE:
  		if (type == AUDIT_DEL)
  			entry = audit_rule_to_entry(data);
  		else
  			entry = audit_data_to_entry(data, datasz);
  		if (IS_ERR(entry))
  			return PTR_ERR(entry);
36c4f1b18   Al Viro   clean up audit_ru...
1173
  		err = audit_del_rule(entry);
9d9609851   Eric Paris   Audit: clean up a...
1174
  		audit_log_rule_change(loginuid, sessionid, sid, "remove rule",
2532386f4   Eric Paris   Audit: collect se...
1175
  				      &entry->rule, !err);
5d3301088   Al Viro   [PATCH] add/remov...
1176

93315ed6d   Amy Griffis   [PATCH] audit str...
1177
  		audit_free_rule(entry);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1178
1179
1180
1181
1182
1183
1184
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	return err;
  }
5af75d8d5   Al Viro   audit: validate c...
1185
  int audit_comparator(u32 left, u32 op, u32 right)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1186
1187
  {
  	switch (op) {
5af75d8d5   Al Viro   audit: validate c...
1188
  	case Audit_equal:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1189
  		return (left == right);
5af75d8d5   Al Viro   audit: validate c...
1190
  	case Audit_not_equal:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1191
  		return (left != right);
5af75d8d5   Al Viro   audit: validate c...
1192
  	case Audit_lt:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1193
  		return (left < right);
5af75d8d5   Al Viro   audit: validate c...
1194
  	case Audit_le:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1195
  		return (left <= right);
5af75d8d5   Al Viro   audit: validate c...
1196
  	case Audit_gt:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1197
  		return (left > right);
5af75d8d5   Al Viro   audit: validate c...
1198
  	case Audit_ge:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1199
  		return (left >= right);
5af75d8d5   Al Viro   audit: validate c...
1200
  	case Audit_bitmask:
74f2345b6   Eric Paris   [PATCH] allow aud...
1201
  		return (left & right);
5af75d8d5   Al Viro   audit: validate c...
1202
  	case Audit_bittest:
74f2345b6   Eric Paris   [PATCH] allow aud...
1203
  		return ((left & right) == right);
5af75d8d5   Al Viro   audit: validate c...
1204
1205
1206
  	default:
  		BUG();
  		return 0;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1207
1208
  	}
  }
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
  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...
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
  /**
   * 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...
1283
1284
1285
1286
1287
1288
1289
1290
1291
  /**
   * 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...
1292
  {
e3d6b07b8   Jeff Layton   audit: optimize a...
1293
  	int dlen, pathlen;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1294
  	const char *p;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1295
  	dlen = strlen(dname);
29e9a3467   Eric Paris   audit: make audit...
1296
1297
  	pathlen = strlen(path);
  	if (pathlen < dlen)
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1298
  		return 1;
e3d6b07b8   Jeff Layton   audit: optimize a...
1299
  	parentlen = parentlen == AUDIT_NAME_FULL ? parent_len(path) : parentlen;
29e9a3467   Eric Paris   audit: make audit...
1300
  	if (pathlen - parentlen != dlen)
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1301
  		return 1;
29e9a3467   Eric Paris   audit: make audit...
1302
1303
  
  	p = path + parentlen;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1304

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

02276bda4   Eric W. Biederman   audit: Use curren...
1308
  static int audit_filter_user_rules(struct audit_krule *rule,
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1309
1310
1311
1312
1313
  				   enum audit_state *state)
  {
  	int i;
  
  	for (i = 0; i < rule->field_count; i++) {
93315ed6d   Amy Griffis   [PATCH] audit str...
1314
  		struct audit_field *f = &rule->fields[i];
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1315
  		int result = 0;
c53fa1ed9   Patrick McHardy   netlink: kill log...
1316
  		u32 sid;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1317

93315ed6d   Amy Griffis   [PATCH] audit str...
1318
  		switch (f->type) {
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1319
  		case AUDIT_PID:
02276bda4   Eric W. Biederman   audit: Use curren...
1320
  			result = audit_comparator(task_pid_vnr(current), f->op, f->val);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1321
1322
  			break;
  		case AUDIT_UID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
1323
  			result = audit_uid_comparator(current_uid(), f->op, f->uid);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1324
1325
  			break;
  		case AUDIT_GID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
1326
  			result = audit_gid_comparator(current_gid(), f->op, f->gid);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1327
1328
  			break;
  		case AUDIT_LOGINUID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
1329
1330
  			result = audit_uid_comparator(audit_get_loginuid(current),
  						  f->op, f->uid);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1331
  			break;
d29be158a   Miloslav Trmac   Audit: add suppor...
1332
1333
1334
1335
1336
  		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...
1337
1338
1339
  			if (f->lsm_rule) {
  				security_task_getsecid(current, &sid);
  				result = security_audit_rule_match(sid,
d29be158a   Miloslav Trmac   Audit: add suppor...
1340
1341
1342
1343
  								   f->type,
  								   f->op,
  								   f->lsm_rule,
  								   NULL);
c53fa1ed9   Patrick McHardy   netlink: kill log...
1344
  			}
d29be158a   Miloslav Trmac   Audit: add suppor...
1345
  			break;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1346
1347
1348
1349
1350
1351
1352
  		}
  
  		if (!result)
  			return 0;
  	}
  	switch (rule->action) {
  	case AUDIT_NEVER:    *state = AUDIT_DISABLED;	    break;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1353
1354
1355
1356
  	case AUDIT_ALWAYS:   *state = AUDIT_RECORD_CONTEXT; break;
  	}
  	return 1;
  }
02276bda4   Eric W. Biederman   audit: Use curren...
1357
  int audit_filter_user(void)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1358
  {
11f57cedc   Ingo Molnar   [PATCH] audit: fi...
1359
  	enum audit_state state = AUDIT_DISABLED;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1360
  	struct audit_entry *e;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1361
1362
1363
1364
  	int ret = 1;
  
  	rcu_read_lock();
  	list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) {
02276bda4   Eric W. Biederman   audit: Use curren...
1365
  		if (audit_filter_user_rules(&e->rule, &state)) {
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
  			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:...
1380

fe7752bab   David Woodhouse   [PATCH] Fix audit...
1381
1382
1383
1384
1385
1386
  	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...
1387
  		int i;
93315ed6d   Amy Griffis   [PATCH] audit str...
1388
1389
1390
1391
  		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...
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
  				if (!result)
  					break;
  			}
  		}
  		if (result)
  			goto unlock_and_return;
  	}
  unlock_and_return:
  	rcu_read_unlock();
  	return result;
  }
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1403

e45aa212e   Al Viro   audit rules order...
1404
  static int update_lsm_rule(struct audit_krule *r)
1a9d0797b   Al Viro   audit_update_lsm_...
1405
  {
e45aa212e   Al Viro   audit rules order...
1406
  	struct audit_entry *entry = container_of(r, struct audit_entry, rule);
1a9d0797b   Al Viro   audit_update_lsm_...
1407
  	struct audit_entry *nentry;
1a9d0797b   Al Viro   audit_update_lsm_...
1408
  	int err = 0;
e45aa212e   Al Viro   audit rules order...
1409
  	if (!security_audit_rule_known(r))
1a9d0797b   Al Viro   audit_update_lsm_...
1410
  		return 0;
ae7b8f410   Eric Paris   Audit: clean up t...
1411
  	nentry = audit_dupe_rule(r);
1a9d0797b   Al Viro   audit_update_lsm_...
1412
1413
1414
1415
1416
  	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...
1417
  		if (r->watch)
e45aa212e   Al Viro   audit rules order...
1418
  			list_del(&r->rlist);
1a9d0797b   Al Viro   audit_update_lsm_...
1419
  		list_del_rcu(&entry->list);
e45aa212e   Al Viro   audit rules order...
1420
  		list_del(&r->list);
1a9d0797b   Al Viro   audit_update_lsm_...
1421
  	} else {
ae7b8f410   Eric Paris   Audit: clean up t...
1422
  		if (r->watch || r->tree)
e45aa212e   Al Viro   audit rules order...
1423
  			list_replace_init(&r->rlist, &nentry->rule.rlist);
1a9d0797b   Al Viro   audit_update_lsm_...
1424
  		list_replace_rcu(&entry->list, &nentry->list);
e45aa212e   Al Viro   audit rules order...
1425
  		list_replace(&r->list, &nentry->rule.list);
1a9d0797b   Al Viro   audit_update_lsm_...
1426
1427
1428
1429
1430
  	}
  	call_rcu(&entry->rcu, audit_free_rule_rcu);
  
  	return err;
  }
04305e4af   Ahmed S. Darwish   Audit: Final rena...
1431
  /* This function will re-initialize the lsm_rule field of all applicable rules.
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
1432
   * It will traverse the filter lists serarching for rules that contain LSM
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1433
   * specific filter fields.  When such a rule is found, it is copied, the
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
1434
   * LSM field is re-initialized, and the old rule is replaced with the
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1435
   * updated rule. */
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
1436
  int audit_update_lsm_rules(void)
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1437
  {
e45aa212e   Al Viro   audit rules order...
1438
  	struct audit_krule *r, *n;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1439
  	int i, err = 0;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1440
1441
  	/* audit_filter_mutex synchronizes the writers */
  	mutex_lock(&audit_filter_mutex);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1442
1443
  
  	for (i = 0; i < AUDIT_NR_FILTERS; i++) {
e45aa212e   Al Viro   audit rules order...
1444
1445
  		list_for_each_entry_safe(r, n, &audit_rules_list[i], list) {
  			int res = update_lsm_rule(r);
1a9d0797b   Al Viro   audit_update_lsm_...
1446
1447
  			if (!err)
  				err = res;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1448
1449
  		}
  	}
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1450
  	mutex_unlock(&audit_filter_mutex);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1451
1452
1453
  
  	return err;
  }