Blame view

kernel/auditfilter.c 33.6 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

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

f368c07d7   Amy Griffis   [PATCH] audit: pa...
75
  	/* some rules don't have associated watches */
c28bb7da7   Zhenwen Xu   make the e->rule....
76
77
78
79
80
  	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...
81
82
  			kfree(f->lsm_str);
  			security_audit_rule_free(f->lsm_rule);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
83
  		}
c28bb7da7   Zhenwen Xu   make the e->rule....
84
85
  	kfree(erule->fields);
  	kfree(erule->filterkey);
93315ed6d   Amy Griffis   [PATCH] audit str...
86
87
  	kfree(e);
  }
74c3cbe33   Al Viro   [PATCH] audit: wa...
88
  void audit_free_rule_rcu(struct rcu_head *head)
93315ed6d   Amy Griffis   [PATCH] audit str...
89
90
91
92
  {
  	struct audit_entry *e = container_of(head, struct audit_entry, rcu);
  	audit_free_rule(e);
  }
3dc7e3153   Darrel Goeddel   [PATCH] support f...
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
  /* 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...
112
113
  /* Unpack a filter field's string representation from user-space
   * buffer. */
74c3cbe33   Al Viro   [PATCH] audit: wa...
114
  char *audit_unpack_string(void **bufp, size_t *remain, size_t len)
93315ed6d   Amy Griffis   [PATCH] audit str...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
  {
  	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...
138
139
140
141
142
  /* 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...
143
144
  	    krule->watch || krule->inode_f || krule->tree ||
  	    (f->op != Audit_equal && f->op != Audit_not_equal))
f368c07d7   Amy Griffis   [PATCH] audit: pa...
145
146
147
148
149
  		return -EINVAL;
  
  	krule->inode_f = f;
  	return 0;
  }
b915543b4   Al Viro   [PATCH] audit sys...
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  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...
172
173
  int audit_match_class(int class, unsigned syscall)
  {
c926e4f43   Klaus Weidner   [PATCH] audit: fi...
174
  	if (unlikely(syscall >= AUDIT_BITMASK_SIZE * 32))
55669bfa1   Al Viro   [PATCH] audit: AU...
175
176
177
178
179
  		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...
180
  #ifdef CONFIG_AUDITSYSCALL
e54dc2431   Amy Griffis   [PATCH] audit sig...
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
215
216
  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...
217
  #endif
e54dc2431   Amy Griffis   [PATCH] audit sig...
218

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

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

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

93315ed6d   Amy Griffis   [PATCH] audit str...
397
398
399
400
401
402
  	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...
403
404
405
  
  		f->op = audit_to_op(data->fieldflags[i]);
  		if (f->op == Audit_bad)
93315ed6d   Amy Griffis   [PATCH] audit str...
406
  			goto exit_free;
93315ed6d   Amy Griffis   [PATCH] audit str...
407
  		f->type = data->fields[i];
3dc7e3153   Darrel Goeddel   [PATCH] support f...
408
  		f->val = data->values[i];
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
409
410
  		f->uid = INVALID_UID;
  		f->gid = INVALID_GID;
04305e4af   Ahmed S. Darwish   Audit: Final rena...
411
412
  		f->lsm_str = NULL;
  		f->lsm_rule = NULL;
62062cf8a   Eric Paris   audit: allow chec...
413

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

04305e4af   Ahmed S. Darwish   Audit: Final rena...
694
695
696
  	/* our own copy of lsm_str */
  	lsm_str = kstrdup(sf->lsm_str, GFP_KERNEL);
  	if (unlikely(!lsm_str))
3e1fbd12c   Akinobu Mita   [PATCH] audit: fi...
697
  		return -ENOMEM;
04305e4af   Ahmed S. Darwish   Audit: Final rena...
698
  	df->lsm_str = lsm_str;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
699

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

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

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

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

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

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

f368c07d7   Amy Griffis   [PATCH] audit: pa...
926
  	mutex_lock(&audit_filter_mutex);
36c4f1b18   Al Viro   clean up audit_ru...
927
  	e = audit_find_rule(entry, &list);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
928
929
930
931
932
  	if (!e) {
  		mutex_unlock(&audit_filter_mutex);
  		ret = -ENOENT;
  		goto out;
  	}
cfcad62c7   Eric Paris   audit: seperate a...
933
  	if (e->rule.watch)
a05fb6cc5   Eric Paris   audit: do not get...
934
  		audit_remove_watch_rule(&e->rule);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
935

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

1a6b9f231   Eric Paris   [AUDIT] make audi...
990
991
  	if (!audit_enabled)
  		return;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
992
993
994
  	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
  	if (!ab)
  		return;
dc9eb698f   Eric Paris   audit: stop pushi...
995
  	audit_log_format(ab, "auid=%u ses=%u" ,loginuid, sessionid);
b122c3767   Eric Paris   audit: use a cons...
996
  	audit_log_task_context(ab);
9d9609851   Eric Paris   Audit: clean up a...
997
998
999
  	audit_log_format(ab, " op=");
  	audit_log_string(ab, action);
  	audit_log_key(ab, rule->filterkey);
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
1000
1001
1002
  	audit_log_format(ab, " list=%d res=%d", rule->listnr, res);
  	audit_log_end(ab);
  }
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1003
  /**
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1004
   * audit_rule_change - apply all rules to the specified message type
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1005
   * @type: audit message type
f9441639e   Richard Guy Briggs   audit: fix netlin...
1006
   * @portid: target port id for netlink audit messages
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1007
1008
   * @seq: netlink audit message sequence (serial) number
   * @data: payload data
93315ed6d   Amy Griffis   [PATCH] audit str...
1009
   * @datasz: size of payload data
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1010
   */
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1011
1012
  int audit_rule_change(int type, __u32 portid, int seq, void *data,
  			size_t datasz)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1013
  {
93315ed6d   Amy Griffis   [PATCH] audit str...
1014
1015
  	int err = 0;
  	struct audit_entry *entry;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1016
1017
  
  	switch (type) {
93315ed6d   Amy Griffis   [PATCH] audit str...
1018
  	case AUDIT_ADD_RULE:
189009091   Eric Paris   audit: remove the...
1019
  		entry = audit_data_to_entry(data, datasz);
93315ed6d   Amy Griffis   [PATCH] audit str...
1020
1021
  		if (IS_ERR(entry))
  			return PTR_ERR(entry);
36c4f1b18   Al Viro   clean up audit_ru...
1022
  		err = audit_add_rule(entry);
dc9eb698f   Eric Paris   audit: stop pushi...
1023
  		audit_log_rule_change("add rule", &entry->rule, !err);
5d3301088   Al Viro   [PATCH] add/remov...
1024
  		if (err)
93315ed6d   Amy Griffis   [PATCH] audit str...
1025
  			audit_free_rule(entry);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1026
  		break;
93315ed6d   Amy Griffis   [PATCH] audit str...
1027
  	case AUDIT_DEL_RULE:
189009091   Eric Paris   audit: remove the...
1028
  		entry = audit_data_to_entry(data, datasz);
93315ed6d   Amy Griffis   [PATCH] audit str...
1029
1030
  		if (IS_ERR(entry))
  			return PTR_ERR(entry);
36c4f1b18   Al Viro   clean up audit_ru...
1031
  		err = audit_del_rule(entry);
dc9eb698f   Eric Paris   audit: stop pushi...
1032
  		audit_log_rule_change("remove rule", &entry->rule, !err);
93315ed6d   Amy Griffis   [PATCH] audit str...
1033
  		audit_free_rule(entry);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1034
1035
1036
1037
1038
1039
1040
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	return err;
  }
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1041
1042
  /**
   * audit_list_rules_send - list the audit rules
d211f177b   Eric W. Biederman   audit: Update kdo...
1043
   * @request_skb: skb of request we are replying to (used to target the reply)
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1044
1045
   * @seq: netlink audit message sequence (serial) number
   */
6f285b19d   Eric W. Biederman   audit: Send repli...
1046
  int audit_list_rules_send(struct sk_buff *request_skb, int seq)
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1047
  {
6f285b19d   Eric W. Biederman   audit: Send repli...
1048
1049
  	u32 portid = NETLINK_CB(request_skb).portid;
  	struct net *net = sock_net(NETLINK_CB(request_skb).sk);
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
  	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...
1063
  	dest->net = get_net(net);
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1064
  	dest->portid = portid;
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
  	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...
1080
  int audit_comparator(u32 left, u32 op, u32 right)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1081
1082
  {
  	switch (op) {
5af75d8d5   Al Viro   audit: validate c...
1083
  	case Audit_equal:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1084
  		return (left == right);
5af75d8d5   Al Viro   audit: validate c...
1085
  	case Audit_not_equal:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1086
  		return (left != right);
5af75d8d5   Al Viro   audit: validate c...
1087
  	case Audit_lt:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1088
  		return (left < right);
5af75d8d5   Al Viro   audit: validate c...
1089
  	case Audit_le:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1090
  		return (left <= right);
5af75d8d5   Al Viro   audit: validate c...
1091
  	case Audit_gt:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1092
  		return (left > right);
5af75d8d5   Al Viro   audit: validate c...
1093
  	case Audit_ge:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1094
  		return (left >= right);
5af75d8d5   Al Viro   audit: validate c...
1095
  	case Audit_bitmask:
74f2345b6   Eric Paris   [PATCH] allow aud...
1096
  		return (left & right);
5af75d8d5   Al Viro   audit: validate c...
1097
  	case Audit_bittest:
74f2345b6   Eric Paris   [PATCH] allow aud...
1098
  		return ((left & right) == right);
5af75d8d5   Al Viro   audit: validate c...
1099
1100
1101
  	default:
  		BUG();
  		return 0;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1102
1103
  	}
  }
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
1104
1105
1106
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
  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...
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
  /**
   * 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...
1178
1179
1180
1181
1182
1183
1184
1185
1186
  /**
   * 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...
1187
  {
e3d6b07b8   Jeff Layton   audit: optimize a...
1188
  	int dlen, pathlen;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1189
  	const char *p;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1190
  	dlen = strlen(dname);
29e9a3467   Eric Paris   audit: make audit...
1191
1192
  	pathlen = strlen(path);
  	if (pathlen < dlen)
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1193
  		return 1;
e3d6b07b8   Jeff Layton   audit: optimize a...
1194
  	parentlen = parentlen == AUDIT_NAME_FULL ? parent_len(path) : parentlen;
29e9a3467   Eric Paris   audit: make audit...
1195
  	if (pathlen - parentlen != dlen)
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1196
  		return 1;
29e9a3467   Eric Paris   audit: make audit...
1197
1198
  
  	p = path + parentlen;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1199

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

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

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

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

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