Blame view

kernel/auditfilter.c 34.1 KB
1a59d1b8e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
fe7752bab   David Woodhouse   [PATCH] Fix audit...
2
3
4
5
6
  /* auditfilter.c -- filtering of audit events
   *
   * Copyright 2003-2004 Red Hat, Inc.
   * Copyright 2005 Hewlett-Packard Development Company, L.P.
   * Copyright 2005 IBM Corporation
fe7752bab   David Woodhouse   [PATCH] Fix audit...
7
   */
f952d10ff   Richard Guy Briggs   audit: Use more c...
8
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
fe7752bab   David Woodhouse   [PATCH] Fix audit...
9
10
11
  #include <linux/kernel.h>
  #include <linux/audit.h>
  #include <linux/kthread.h>
f368c07d7   Amy Griffis   [PATCH] audit: pa...
12
13
14
  #include <linux/mutex.h>
  #include <linux/fs.h>
  #include <linux/namei.h>
fe7752bab   David Woodhouse   [PATCH] Fix audit...
15
  #include <linux/netlink.h>
f368c07d7   Amy Griffis   [PATCH] audit: pa...
16
  #include <linux/sched.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
17
  #include <linux/slab.h>
2a862b32f   Ahmed S. Darwish   Audit: use new LS...
18
  #include <linux/security.h>
48095d991   Eric W. Biederman   audit: Use struct...
19
  #include <net/net_namespace.h>
6f285b19d   Eric W. Biederman   audit: Send repli...
20
  #include <net/sock.h>
fe7752bab   David Woodhouse   [PATCH] Fix audit...
21
  #include "audit.h"
f368c07d7   Amy Griffis   [PATCH] audit: pa...
22
23
24
25
  /*
   * Locking model:
   *
   * audit_filter_mutex:
725131efa   Scott Matheina   audit: fix commen...
26
27
28
29
30
31
32
   *		Synchronizes writes and blocking reads of audit's filterlist
   *		data.  Rcu is used to traverse the filterlist and access
   *		contents of structs audit_entry, audit_watch and opaque
   *		LSM rules during filtering.  If modified, these structures
   *		must be copied and replace their counterparts in the filterlist.
   *		An audit_parent struct is not accessed during filtering, so may
   *		be written directly provided audit_filter_mutex is held.
f368c07d7   Amy Griffis   [PATCH] audit: pa...
33
   */
f368c07d7   Amy Griffis   [PATCH] audit: pa...
34
  /* Audit filter lists, defined in <linux/audit.h> */
fe7752bab   David Woodhouse   [PATCH] Fix audit...
35
36
37
38
39
40
41
  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]),
42d5e3765   Richard Guy Briggs   audit: filter PAT...
42
43
  	LIST_HEAD_INIT(audit_filter_list[6]),
  #if AUDIT_NR_FILTERS != 7
fe7752bab   David Woodhouse   [PATCH] Fix audit...
44
45
46
  #error Fix audit_filter_list initialiser
  #endif
  };
e45aa212e   Al Viro   audit rules order...
47
48
49
50
51
52
53
  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]),
42d5e3765   Richard Guy Briggs   audit: filter PAT...
54
  	LIST_HEAD_INIT(audit_rules_list[6]),
e45aa212e   Al Viro   audit rules order...
55
  };
fe7752bab   David Woodhouse   [PATCH] Fix audit...
56

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

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

f368c07d7   Amy Griffis   [PATCH] audit: pa...
81
  	/* some rules don't have associated watches */
c28bb7da7   Zhenwen Xu   make the e->rule....
82
83
84
  	if (erule->watch)
  		audit_put_watch(erule->watch);
  	if (erule->fields)
219ca3942   Richard Guy Briggs   audit: use union ...
85
86
  		for (i = 0; i < erule->field_count; i++)
  			audit_free_lsm_field(&erule->fields[i]);
c28bb7da7   Zhenwen Xu   make the e->rule....
87
88
  	kfree(erule->fields);
  	kfree(erule->filterkey);
93315ed6d   Amy Griffis   [PATCH] audit str...
89
90
  	kfree(e);
  }
74c3cbe33   Al Viro   [PATCH] audit: wa...
91
  void audit_free_rule_rcu(struct rcu_head *head)
93315ed6d   Amy Griffis   [PATCH] audit str...
92
93
94
95
  {
  	struct audit_entry *e = container_of(head, struct audit_entry, rcu);
  	audit_free_rule(e);
  }
3dc7e3153   Darrel Goeddel   [PATCH] support f...
96
97
98
99
100
101
102
103
104
  /* Initialize an audit filterlist entry. */
  static inline struct audit_entry *audit_init_entry(u32 field_count)
  {
  	struct audit_entry *entry;
  	struct audit_field *fields;
  
  	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
  	if (unlikely(!entry))
  		return NULL;
bab5e2d65   Fabian Frederick   kernel/auditfilte...
105
  	fields = kcalloc(field_count, sizeof(*fields), GFP_KERNEL);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
106
107
108
109
110
111
112
113
  	if (unlikely(!fields)) {
  		kfree(entry);
  		return NULL;
  	}
  	entry->rule.fields = fields;
  
  	return entry;
  }
93315ed6d   Amy Griffis   [PATCH] audit str...
114
115
  /* Unpack a filter field's string representation from user-space
   * buffer. */
74c3cbe33   Al Viro   [PATCH] audit: wa...
116
  char *audit_unpack_string(void **bufp, size_t *remain, size_t len)
93315ed6d   Amy Griffis   [PATCH] audit str...
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
  {
  	char *str;
  
  	if (!*bufp || (len == 0) || (len > *remain))
  		return ERR_PTR(-EINVAL);
  
  	/* Of the currently implemented string fields, PATH_MAX
  	 * defines the longest valid length.
  	 */
  	if (len > PATH_MAX)
  		return ERR_PTR(-ENAMETOOLONG);
  
  	str = kmalloc(len + 1, GFP_KERNEL);
  	if (unlikely(!str))
  		return ERR_PTR(-ENOMEM);
  
  	memcpy(str, *bufp, len);
  	str[len] = 0;
  	*bufp += len;
  	*remain -= len;
  
  	return str;
  }
fd97646b0   Wei Yuan   audit: Fix typo i...
140
  /* Translate an inode field to kernel representation. */
f368c07d7   Amy Griffis   [PATCH] audit: pa...
141
142
143
144
  static inline int audit_to_inode(struct audit_krule *krule,
  				 struct audit_field *f)
  {
  	if (krule->listnr != AUDIT_FILTER_EXIT ||
3639f1706   Richard Guy Briggs   audit: put rule e...
145
  	    krule->inode_f || krule->watch || krule->tree ||
5af75d8d5   Al Viro   audit: validate c...
146
  	    (f->op != Audit_equal && f->op != Audit_not_equal))
f368c07d7   Amy Griffis   [PATCH] audit: pa...
147
148
149
150
151
  		return -EINVAL;
  
  	krule->inode_f = f;
  	return 0;
  }
b915543b4   Al Viro   [PATCH] audit sys...
152
153
154
155
  static __u32 *classes[AUDIT_SYSCALL_CLASSES];
  
  int __init audit_register_class(int class, unsigned *list)
  {
bab5e2d65   Fabian Frederick   kernel/auditfilte...
156
  	__u32 *p = kcalloc(AUDIT_BITMASK_SIZE, sizeof(__u32), GFP_KERNEL);
b915543b4   Al Viro   [PATCH] audit sys...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  	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...
174
175
  int audit_match_class(int class, unsigned syscall)
  {
c926e4f43   Klaus Weidner   [PATCH] audit: fi...
176
  	if (unlikely(syscall >= AUDIT_BITMASK_SIZE * 32))
55669bfa1   Al Viro   [PATCH] audit: AU...
177
178
179
180
181
  		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...
182
  #ifdef CONFIG_AUDITSYSCALL
e54dc2431   Amy Griffis   [PATCH] audit sig...
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
217
218
  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...
219
  #endif
e54dc2431   Amy Griffis   [PATCH] audit sig...
220

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

ecc68904a   Richard Guy Briggs   audit: re-structu...
332
333
334
335
336
337
338
339
340
341
  	/* Check for valid field type and op */
  	switch (f->type) {
  	case AUDIT_ARG0:
  	case AUDIT_ARG1:
  	case AUDIT_ARG2:
  	case AUDIT_ARG3:
  	case AUDIT_PERS: /* <uapi/linux/personality.h> */
  	case AUDIT_DEVMINOR:
  		/* all ops are valid */
  		break;
ab61d38ed   Eric Paris   audit: make valid...
342
343
344
345
346
347
348
349
350
351
352
353
  	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:
ab61d38ed   Eric Paris   audit: make valid...
354
355
356
  	case AUDIT_MSGTYPE:
  	case AUDIT_PPID:
  	case AUDIT_DEVMAJOR:
ab61d38ed   Eric Paris   audit: make valid...
357
358
  	case AUDIT_EXIT:
  	case AUDIT_SUCCESS:
78122037b   Eric Paris   audit: do not rej...
359
  	case AUDIT_INODE:
8fae47705   Richard Guy Briggs   audit: add suppor...
360
  	case AUDIT_SESSIONID:
ecc68904a   Richard Guy Briggs   audit: re-structu...
361
362
363
364
  	case AUDIT_SUBJ_SEN:
  	case AUDIT_SUBJ_CLR:
  	case AUDIT_OBJ_LEV_LOW:
  	case AUDIT_OBJ_LEV_HIGH:
bf361231c   Richard Guy Briggs   audit: add saddr_...
365
  	case AUDIT_SADDR_FAM:
ab61d38ed   Eric Paris   audit: make valid...
366
367
368
369
  		/* bit ops are only useful on syscall args */
  		if (f->op == Audit_bitmask || f->op == Audit_bittest)
  			return -EINVAL;
  		break;
ab61d38ed   Eric Paris   audit: make valid...
370
371
372
  	case AUDIT_SUBJ_USER:
  	case AUDIT_SUBJ_ROLE:
  	case AUDIT_SUBJ_TYPE:
ab61d38ed   Eric Paris   audit: make valid...
373
374
375
  	case AUDIT_OBJ_USER:
  	case AUDIT_OBJ_ROLE:
  	case AUDIT_OBJ_TYPE:
ab61d38ed   Eric Paris   audit: make valid...
376
377
378
  	case AUDIT_WATCH:
  	case AUDIT_DIR:
  	case AUDIT_FILTERKEY:
780a7654c   Eric W. Biederman   audit: Make testi...
379
  	case AUDIT_LOGINUID_SET:
ab61d38ed   Eric Paris   audit: make valid...
380
  	case AUDIT_ARCH:
42d5e3765   Richard Guy Briggs   audit: filter PAT...
381
  	case AUDIT_FSTYPE:
ecc68904a   Richard Guy Briggs   audit: re-structu...
382
383
384
385
386
  	case AUDIT_PERM:
  	case AUDIT_FILETYPE:
  	case AUDIT_FIELD_COMPARE:
  	case AUDIT_EXE:
  		/* only equal and not equal valid ops */
ab61d38ed   Eric Paris   audit: make valid...
387
388
389
  		if (f->op != Audit_not_equal && f->op != Audit_equal)
  			return -EINVAL;
  		break;
ecc68904a   Richard Guy Briggs   audit: re-structu...
390
391
392
393
394
395
396
397
398
399
400
  	default:
  		/* field not recognized */
  		return -EINVAL;
  	}
  
  	/* Check for select valid field values */
  	switch (f->type) {
  	case AUDIT_LOGINUID_SET:
  		if ((f->val != 0) && (f->val != 1))
  			return -EINVAL;
  		break;
ab61d38ed   Eric Paris   audit: make valid...
401
402
403
404
405
406
407
408
409
410
411
412
  	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;
bf361231c   Richard Guy Briggs   audit: add saddr_...
413
414
  	case AUDIT_SADDR_FAM:
  		if (f->val >= AF_MAX)
34d99af52   Richard Guy Briggs   audit: implement ...
415
  			return -EINVAL;
34d99af52   Richard Guy Briggs   audit: implement ...
416
  		break;
ecc68904a   Richard Guy Briggs   audit: re-structu...
417
  	default:
34d99af52   Richard Guy Briggs   audit: implement ...
418
  		break;
b7a84deaf   Nicholas Mc Guire   audit: remove unn...
419
  	}
ecc68904a   Richard Guy Briggs   audit: re-structu...
420

62062cf8a   Eric Paris   audit: allow chec...
421
  	return 0;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
422
  }
fd97646b0   Wei Yuan   audit: Fix typo i...
423
  /* Translate struct audit_rule_data to kernel's rule representation. */
93315ed6d   Amy Griffis   [PATCH] audit str...
424
425
  static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
  					       size_t datasz)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
426
  {
93315ed6d   Amy Griffis   [PATCH] audit str...
427
428
429
  	int err = 0;
  	struct audit_entry *entry;
  	void *bufp;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
430
  	size_t remain = datasz - sizeof(struct audit_rule_data);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
431
  	int i;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
432
  	char *str;
34d99af52   Richard Guy Briggs   audit: implement ...
433
  	struct audit_fsnotify_mark *audit_mark;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
434

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

93315ed6d   Amy Griffis   [PATCH] audit str...
439
  	bufp = data->buf;
93315ed6d   Amy Griffis   [PATCH] audit str...
440
441
  	for (i = 0; i < data->field_count; i++) {
  		struct audit_field *f = &entry->rule.fields[i];
2ad3e17eb   Paul Moore   audit: fix error ...
442
  		u32 f_val;
93315ed6d   Amy Griffis   [PATCH] audit str...
443
444
  
  		err = -EINVAL;
5af75d8d5   Al Viro   audit: validate c...
445
446
447
  
  		f->op = audit_to_op(data->fieldflags[i]);
  		if (f->op == Audit_bad)
93315ed6d   Amy Griffis   [PATCH] audit str...
448
  			goto exit_free;
93315ed6d   Amy Griffis   [PATCH] audit str...
449
  		f->type = data->fields[i];
2ad3e17eb   Paul Moore   audit: fix error ...
450
  		f_val = data->values[i];
62062cf8a   Eric Paris   audit: allow chec...
451

780a7654c   Eric W. Biederman   audit: Make testi...
452
  		/* Support legacy tests for a valid loginuid */
2ad3e17eb   Paul Moore   audit: fix error ...
453
  		if ((f->type == AUDIT_LOGINUID) && (f_val == AUDIT_UID_UNSET)) {
780a7654c   Eric W. Biederman   audit: Make testi...
454
  			f->type = AUDIT_LOGINUID_SET;
2ad3e17eb   Paul Moore   audit: fix error ...
455
  			f_val = 0;
041d7b98f   Richard Guy Briggs   audit: restore AU...
456
  			entry->rule.pflags |= AUDIT_LOGINUID_LEGACY;
f1dc4867f   Richard Guy Briggs   audit: anchor all...
457
  		}
62062cf8a   Eric Paris   audit: allow chec...
458
459
460
461
462
  		err = audit_field_valid(entry, f);
  		if (err)
  			goto exit_free;
  
  		err = -EINVAL;
ab61d38ed   Eric Paris   audit: make valid...
463
  		switch (f->type) {
780a7654c   Eric W. Biederman   audit: Make testi...
464
  		case AUDIT_LOGINUID:
0a73dccc4   Al Viro   [PATCH] validate ...
465
466
467
468
  		case AUDIT_UID:
  		case AUDIT_EUID:
  		case AUDIT_SUID:
  		case AUDIT_FSUID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
469
  		case AUDIT_OBJ_UID:
2ad3e17eb   Paul Moore   audit: fix error ...
470
  			f->uid = make_kuid(current_user_ns(), f_val);
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
471
472
473
  			if (!uid_valid(f->uid))
  				goto exit_free;
  			break;
0a73dccc4   Al Viro   [PATCH] validate ...
474
475
476
477
  		case AUDIT_GID:
  		case AUDIT_EGID:
  		case AUDIT_SGID:
  		case AUDIT_FSGID:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
478
  		case AUDIT_OBJ_GID:
2ad3e17eb   Paul Moore   audit: fix error ...
479
  			f->gid = make_kgid(current_user_ns(), f_val);
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
480
481
482
  			if (!gid_valid(f->gid))
  				goto exit_free;
  			break;
e54dc2431   Amy Griffis   [PATCH] audit sig...
483
  		case AUDIT_ARCH:
2ad3e17eb   Paul Moore   audit: fix error ...
484
  			f->val = f_val;
e54dc2431   Amy Griffis   [PATCH] audit sig...
485
486
  			entry->rule.arch_f = f;
  			break;
3a6b9f85c   Darrel Goeddel   [PATCH] audit: re...
487
488
489
490
491
  		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...
492
493
494
495
496
  		case AUDIT_OBJ_USER:
  		case AUDIT_OBJ_ROLE:
  		case AUDIT_OBJ_TYPE:
  		case AUDIT_OBJ_LEV_LOW:
  		case AUDIT_OBJ_LEV_HIGH:
2ad3e17eb   Paul Moore   audit: fix error ...
497
498
499
  			str = audit_unpack_string(&bufp, &remain, f_val);
  			if (IS_ERR(str)) {
  				err = PTR_ERR(str);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
500
  				goto exit_free;
2ad3e17eb   Paul Moore   audit: fix error ...
501
502
503
  			}
  			entry->rule.buflen += f_val;
  			f->lsm_str = str;
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
504
  			err = security_audit_rule_init(f->type, f->op, str,
04305e4af   Ahmed S. Darwish   Audit: Final rena...
505
  						       (void **)&f->lsm_rule);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
506
507
508
  			/* 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...
509
510
511
  				pr_warn("audit rule for LSM \'%s\' is invalid
  ",
  					str);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
512
  				err = 0;
2ad3e17eb   Paul Moore   audit: fix error ...
513
  			} else if (err)
3dc7e3153   Darrel Goeddel   [PATCH] support f...
514
  				goto exit_free;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
515
  			break;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
516
  		case AUDIT_WATCH:
2ad3e17eb   Paul Moore   audit: fix error ...
517
518
519
  			str = audit_unpack_string(&bufp, &remain, f_val);
  			if (IS_ERR(str)) {
  				err = PTR_ERR(str);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
520
  				goto exit_free;
2ad3e17eb   Paul Moore   audit: fix error ...
521
522
  			}
  			err = audit_to_watch(&entry->rule, str, f_val, f->op);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
523
524
525
526
  			if (err) {
  				kfree(str);
  				goto exit_free;
  			}
2ad3e17eb   Paul Moore   audit: fix error ...
527
  			entry->rule.buflen += f_val;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
528
  			break;
74c3cbe33   Al Viro   [PATCH] audit: wa...
529
  		case AUDIT_DIR:
2ad3e17eb   Paul Moore   audit: fix error ...
530
531
532
  			str = audit_unpack_string(&bufp, &remain, f_val);
  			if (IS_ERR(str)) {
  				err = PTR_ERR(str);
74c3cbe33   Al Viro   [PATCH] audit: wa...
533
  				goto exit_free;
2ad3e17eb   Paul Moore   audit: fix error ...
534
  			}
74c3cbe33   Al Viro   [PATCH] audit: wa...
535
536
537
538
  			err = audit_make_tree(&entry->rule, str, f->op);
  			kfree(str);
  			if (err)
  				goto exit_free;
2ad3e17eb   Paul Moore   audit: fix error ...
539
  			entry->rule.buflen += f_val;
74c3cbe33   Al Viro   [PATCH] audit: wa...
540
  			break;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
541
  		case AUDIT_INODE:
2ad3e17eb   Paul Moore   audit: fix error ...
542
  			f->val = f_val;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
543
544
545
546
  			err = audit_to_inode(&entry->rule, f);
  			if (err)
  				goto exit_free;
  			break;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
547
  		case AUDIT_FILTERKEY:
2ad3e17eb   Paul Moore   audit: fix error ...
548
  			if (entry->rule.filterkey || f_val > AUDIT_MAX_KEY_LEN)
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
549
  				goto exit_free;
2ad3e17eb   Paul Moore   audit: fix error ...
550
551
552
  			str = audit_unpack_string(&bufp, &remain, f_val);
  			if (IS_ERR(str)) {
  				err = PTR_ERR(str);
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
553
  				goto exit_free;
2ad3e17eb   Paul Moore   audit: fix error ...
554
555
  			}
  			entry->rule.buflen += f_val;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
556
557
  			entry->rule.filterkey = str;
  			break;
34d99af52   Richard Guy Briggs   audit: implement ...
558
  		case AUDIT_EXE:
2ad3e17eb   Paul Moore   audit: fix error ...
559
  			if (entry->rule.exe || f_val > PATH_MAX)
34d99af52   Richard Guy Briggs   audit: implement ...
560
  				goto exit_free;
2ad3e17eb   Paul Moore   audit: fix error ...
561
  			str = audit_unpack_string(&bufp, &remain, f_val);
34d99af52   Richard Guy Briggs   audit: implement ...
562
563
564
565
  			if (IS_ERR(str)) {
  				err = PTR_ERR(str);
  				goto exit_free;
  			}
2ad3e17eb   Paul Moore   audit: fix error ...
566
  			audit_mark = audit_alloc_mark(&entry->rule, str, f_val);
34d99af52   Richard Guy Briggs   audit: implement ...
567
568
569
570
571
  			if (IS_ERR(audit_mark)) {
  				kfree(str);
  				err = PTR_ERR(audit_mark);
  				goto exit_free;
  			}
2ad3e17eb   Paul Moore   audit: fix error ...
572
  			entry->rule.buflen += f_val;
34d99af52   Richard Guy Briggs   audit: implement ...
573
574
  			entry->rule.exe = audit_mark;
  			break;
2ad3e17eb   Paul Moore   audit: fix error ...
575
576
577
  		default:
  			f->val = f_val;
  			break;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
578
579
  		}
  	}
5af75d8d5   Al Viro   audit: validate c...
580
581
  	if (entry->rule.inode_f && entry->rule.inode_f->op == Audit_not_equal)
  		entry->rule.inode_f = NULL;
93315ed6d   Amy Griffis   [PATCH] audit str...
582
583
584
585
586
  
  exit_nofree:
  	return entry;
  
  exit_free:
373e0f340   Chen Gang   kernel/auditfilte...
587
588
  	if (entry->rule.tree)
  		audit_put_tree(entry->rule.tree); /* that's the temporary one */
34d99af52   Richard Guy Briggs   audit: implement ...
589
590
  	if (entry->rule.exe)
  		audit_remove_mark(entry->rule.exe); /* that's the template one */
93315ed6d   Amy Griffis   [PATCH] audit str...
591
592
593
594
595
  	audit_free_rule(entry);
  	return ERR_PTR(err);
  }
  
  /* Pack a filter field's string representation into data block. */
74c3cbe33   Al Viro   [PATCH] audit: wa...
596
  static inline size_t audit_pack_string(void **bufp, const char *str)
93315ed6d   Amy Griffis   [PATCH] audit str...
597
598
599
600
601
602
603
604
  {
  	size_t len = strlen(str);
  
  	memcpy(*bufp, str, len);
  	*bufp += len;
  
  	return len;
  }
fd97646b0   Wei Yuan   audit: Fix typo i...
605
  /* Translate kernel rule representation to struct audit_rule_data. */
93315ed6d   Amy Griffis   [PATCH] audit str...
606
607
608
609
610
611
612
613
  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...
614
  		return NULL;
93315ed6d   Amy Griffis   [PATCH] audit str...
615
616
617
618
619
620
621
622
623
624
  	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...
625
  		data->fieldflags[i] = audit_ops[f->op];
93315ed6d   Amy Griffis   [PATCH] audit str...
626
  		switch(f->type) {
3a6b9f85c   Darrel Goeddel   [PATCH] audit: re...
627
628
629
630
631
  		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...
632
633
634
635
636
  		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...
637
  			data->buflen += data->values[i] =
04305e4af   Ahmed S. Darwish   Audit: Final rena...
638
  				audit_pack_string(&bufp, f->lsm_str);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
639
  			break;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
640
641
  		case AUDIT_WATCH:
  			data->buflen += data->values[i] =
cfcad62c7   Eric Paris   audit: seperate a...
642
643
  				audit_pack_string(&bufp,
  						  audit_watch_path(krule->watch));
f368c07d7   Amy Griffis   [PATCH] audit: pa...
644
  			break;
74c3cbe33   Al Viro   [PATCH] audit: wa...
645
646
647
648
649
  		case AUDIT_DIR:
  			data->buflen += data->values[i] =
  				audit_pack_string(&bufp,
  						  audit_tree_path(krule->tree));
  			break;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
650
651
652
653
  		case AUDIT_FILTERKEY:
  			data->buflen += data->values[i] =
  				audit_pack_string(&bufp, krule->filterkey);
  			break;
34d99af52   Richard Guy Briggs   audit: implement ...
654
655
656
657
  		case AUDIT_EXE:
  			data->buflen += data->values[i] =
  				audit_pack_string(&bufp, audit_mark_path(krule->exe));
  			break;
041d7b98f   Richard Guy Briggs   audit: restore AU...
658
659
660
661
662
663
  		case AUDIT_LOGINUID_SET:
  			if (krule->pflags & AUDIT_LOGINUID_LEGACY && !f->val) {
  				data->fields[i] = AUDIT_LOGINUID;
  				data->values[i] = AUDIT_UID_UNSET;
  				break;
  			}
df561f668   Gustavo A. R. Silva   treewide: Use fal...
664
  			fallthrough;	/* if set */
93315ed6d   Amy Griffis   [PATCH] audit str...
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
  		default:
  			data->values[i] = f->val;
  		}
  	}
  	for (i = 0; i < AUDIT_BITMASK_SIZE; i++) data->mask[i] = krule->mask[i];
  
  	return data;
  }
  
  /* Compare two rules in kernel format.  Considered success if rules
   * don't match. */
  static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
  {
  	int i;
  
  	if (a->flags != b->flags ||
041d7b98f   Richard Guy Briggs   audit: restore AU...
681
  	    a->pflags != b->pflags ||
93315ed6d   Amy Griffis   [PATCH] audit str...
682
683
684
  	    a->listnr != b->listnr ||
  	    a->action != b->action ||
  	    a->field_count != b->field_count)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
685
686
687
  		return 1;
  
  	for (i = 0; i < a->field_count; i++) {
93315ed6d   Amy Griffis   [PATCH] audit str...
688
689
  		if (a->fields[i].type != b->fields[i].type ||
  		    a->fields[i].op != b->fields[i].op)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
690
  			return 1;
93315ed6d   Amy Griffis   [PATCH] audit str...
691
692
  
  		switch(a->fields[i].type) {
3a6b9f85c   Darrel Goeddel   [PATCH] audit: re...
693
694
695
696
697
  		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...
698
699
700
701
702
  		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...
703
  			if (strcmp(a->fields[i].lsm_str, b->fields[i].lsm_str))
3dc7e3153   Darrel Goeddel   [PATCH] support f...
704
705
  				return 1;
  			break;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
706
  		case AUDIT_WATCH:
cfcad62c7   Eric Paris   audit: seperate a...
707
708
  			if (strcmp(audit_watch_path(a->watch),
  				   audit_watch_path(b->watch)))
f368c07d7   Amy Griffis   [PATCH] audit: pa...
709
710
  				return 1;
  			break;
74c3cbe33   Al Viro   [PATCH] audit: wa...
711
712
713
714
715
  		case AUDIT_DIR:
  			if (strcmp(audit_tree_path(a->tree),
  				   audit_tree_path(b->tree)))
  				return 1;
  			break;
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
716
717
718
719
720
  		case AUDIT_FILTERKEY:
  			/* both filterkeys exist based on above type compare */
  			if (strcmp(a->filterkey, b->filterkey))
  				return 1;
  			break;
34d99af52   Richard Guy Briggs   audit: implement ...
721
722
723
724
725
726
  		case AUDIT_EXE:
  			/* both paths exist based on above type compare */
  			if (strcmp(audit_mark_path(a->exe),
  				   audit_mark_path(b->exe)))
  				return 1;
  			break;
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
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) {
f952d10ff   Richard Guy Briggs   audit: Use more c...
776
777
778
  		pr_warn("audit rule for LSM \'%s\' is 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
  	int i, err = 0;
  
  	entry = audit_init_entry(fcount);
  	if (unlikely(!entry))
  		return ERR_PTR(-ENOMEM);
  
  	new = &entry->rule;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
804
  	new->flags = old->flags;
041d7b98f   Richard Guy Briggs   audit: restore AU...
805
  	new->pflags = old->pflags;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
806
807
808
809
  	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;
34d99af52   Richard Guy Briggs   audit: implement ...
847
848
849
850
  			break;
  		case AUDIT_EXE:
  			err = audit_dupe_exe(new, old);
  			break;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
851
852
  		}
  		if (err) {
34d99af52   Richard Guy Briggs   audit: implement ...
853
854
  			if (new->exe)
  				audit_remove_mark(new->exe);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
855
856
857
858
  			audit_free_rule(entry);
  			return ERR_PTR(err);
  		}
  	}
ae7b8f410   Eric Paris   Audit: clean up t...
859
860
861
  	if (old->watch) {
  		audit_get_watch(old->watch);
  		new->watch = old->watch;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
862
  	}
3dc7e3153   Darrel Goeddel   [PATCH] support f...
863
864
  	return entry;
  }
f368c07d7   Amy Griffis   [PATCH] audit: pa...
865
866
867
  /* 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...
868
  					   struct list_head **p)
f368c07d7   Amy Griffis   [PATCH] audit: pa...
869
870
  {
  	struct audit_entry *e, *found = NULL;
36c4f1b18   Al Viro   clean up audit_ru...
871
  	struct list_head *list;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
872
  	int h;
36c4f1b18   Al Viro   clean up audit_ru...
873
874
875
876
  	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...
877
878
879
880
881
882
883
884
885
886
  		/* 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...
887
888
  	} else {
  		*p = list = &audit_filter_list[entry->rule.listnr];
f368c07d7   Amy Griffis   [PATCH] audit: pa...
889
890
891
892
893
894
895
896
897
898
899
  	}
  
  	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...
900
901
  static u64 prio_low = ~0ULL/2;
  static u64 prio_high = ~0ULL/2 - 1;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
902
  /* Add rule to given filterlist if not a duplicate. */
36c4f1b18   Al Viro   clean up audit_ru...
903
  static inline int audit_add_rule(struct audit_entry *entry)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
904
  {
93315ed6d   Amy Griffis   [PATCH] audit str...
905
  	struct audit_entry *e;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
906
  	struct audit_watch *watch = entry->rule.watch;
74c3cbe33   Al Viro   [PATCH] audit: wa...
907
  	struct audit_tree *tree = entry->rule.tree;
36c4f1b18   Al Viro   clean up audit_ru...
908
  	struct list_head *list;
ae9d2fb48   Paul Moore   audit: fix uninit...
909
  	int err = 0;
471a5c7c8   Al Viro   [PATCH] introduce...
910
911
  #ifdef CONFIG_AUDITSYSCALL
  	int dont_count = 0;
42d5e3765   Richard Guy Briggs   audit: filter PAT...
912
913
914
  	/* If any of these, don't count towards total */
  	switch(entry->rule.listnr) {
  	case AUDIT_FILTER_USER:
d904ac032   Richard Guy Briggs   audit: rename FIL...
915
  	case AUDIT_FILTER_EXCLUDE:
42d5e3765   Richard Guy Briggs   audit: filter PAT...
916
  	case AUDIT_FILTER_FS:
471a5c7c8   Al Viro   [PATCH] introduce...
917
  		dont_count = 1;
42d5e3765   Richard Guy Briggs   audit: filter PAT...
918
  	}
471a5c7c8   Al Viro   [PATCH] introduce...
919
  #endif
f368c07d7   Amy Griffis   [PATCH] audit: pa...
920

f368c07d7   Amy Griffis   [PATCH] audit: pa...
921
  	mutex_lock(&audit_filter_mutex);
36c4f1b18   Al Viro   clean up audit_ru...
922
  	e = audit_find_rule(entry, &list);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
923
  	if (e) {
35fe4d0b1   Eric Paris   Audit: move audit...
924
  		mutex_unlock(&audit_filter_mutex);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
925
  		err = -EEXIST;
74c3cbe33   Al Viro   [PATCH] audit: wa...
926
927
928
  		/* normally audit_add_tree_rule() will free it on failure */
  		if (tree)
  			audit_put_tree(tree);
f8259b262   Richard Guy Briggs   audit: eliminate ...
929
  		return err;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
930
  	}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
931

f368c07d7   Amy Griffis   [PATCH] audit: pa...
932
933
  	if (watch) {
  		/* audit_filter_mutex is dropped and re-taken during this call */
ae7b8f410   Eric Paris   Audit: clean up t...
934
  		err = audit_add_watch(&entry->rule, &list);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
935
936
  		if (err) {
  			mutex_unlock(&audit_filter_mutex);
2f992ee85   Chen Gang   kernel/auditfilte...
937
938
939
940
941
942
  			/*
  			 * normally audit_add_tree_rule() will free it
  			 * on failure
  			 */
  			if (tree)
  				audit_put_tree(tree);
f8259b262   Richard Guy Briggs   audit: eliminate ...
943
  			return err;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
944
  		}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
945
  	}
74c3cbe33   Al Viro   [PATCH] audit: wa...
946
947
948
949
  	if (tree) {
  		err = audit_add_tree_rule(&entry->rule);
  		if (err) {
  			mutex_unlock(&audit_filter_mutex);
f8259b262   Richard Guy Briggs   audit: eliminate ...
950
  			return err;
74c3cbe33   Al Viro   [PATCH] audit: wa...
951
952
  		}
  	}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
953

0590b9335   Al Viro   fixing audit rule...
954
955
956
957
958
959
960
  	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...
961
  	if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
e45aa212e   Al Viro   audit rules order...
962
963
  		list_add(&entry->rule.list,
  			 &audit_rules_list[entry->rule.listnr]);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
964
  		list_add_rcu(&entry->list, list);
6a2bceec0   Amy Griffis   [PATCH] fix AUDIT...
965
  		entry->rule.flags &= ~AUDIT_FILTER_PREPEND;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
966
  	} else {
e45aa212e   Al Viro   audit rules order...
967
968
  		list_add_tail(&entry->rule.list,
  			      &audit_rules_list[entry->rule.listnr]);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
969
970
  		list_add_tail_rcu(&entry->list, list);
  	}
471a5c7c8   Al Viro   [PATCH] introduce...
971
972
973
  #ifdef CONFIG_AUDITSYSCALL
  	if (!dont_count)
  		audit_n_rules++;
e54dc2431   Amy Griffis   [PATCH] audit sig...
974
975
976
  
  	if (!audit_match_signal(entry))
  		audit_signals++;
471a5c7c8   Al Viro   [PATCH] introduce...
977
  #endif
f368c07d7   Amy Griffis   [PATCH] audit: pa...
978
  	mutex_unlock(&audit_filter_mutex);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
979

f368c07d7   Amy Griffis   [PATCH] audit: pa...
980
  	return err;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
981
  }
f368c07d7   Amy Griffis   [PATCH] audit: pa...
982
  /* Remove an existing rule from filterlist. */
7f4929428   Richard Guy Briggs   audit: clean simp...
983
  int audit_del_rule(struct audit_entry *entry)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
984
985
  {
  	struct audit_entry  *e;
74c3cbe33   Al Viro   [PATCH] audit: wa...
986
  	struct audit_tree *tree = entry->rule.tree;
36c4f1b18   Al Viro   clean up audit_ru...
987
  	struct list_head *list;
36c4f1b18   Al Viro   clean up audit_ru...
988
  	int ret = 0;
471a5c7c8   Al Viro   [PATCH] introduce...
989
990
  #ifdef CONFIG_AUDITSYSCALL
  	int dont_count = 0;
42d5e3765   Richard Guy Briggs   audit: filter PAT...
991
992
993
  	/* If any of these, don't count towards total */
  	switch(entry->rule.listnr) {
  	case AUDIT_FILTER_USER:
d904ac032   Richard Guy Briggs   audit: rename FIL...
994
  	case AUDIT_FILTER_EXCLUDE:
42d5e3765   Richard Guy Briggs   audit: filter PAT...
995
  	case AUDIT_FILTER_FS:
471a5c7c8   Al Viro   [PATCH] introduce...
996
  		dont_count = 1;
42d5e3765   Richard Guy Briggs   audit: filter PAT...
997
  	}
471a5c7c8   Al Viro   [PATCH] introduce...
998
  #endif
f368c07d7   Amy Griffis   [PATCH] audit: pa...
999

f368c07d7   Amy Griffis   [PATCH] audit: pa...
1000
  	mutex_lock(&audit_filter_mutex);
36c4f1b18   Al Viro   clean up audit_ru...
1001
  	e = audit_find_rule(entry, &list);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1002
  	if (!e) {
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1003
1004
1005
  		ret = -ENOENT;
  		goto out;
  	}
cfcad62c7   Eric Paris   audit: seperate a...
1006
  	if (e->rule.watch)
a05fb6cc5   Eric Paris   audit: do not get...
1007
  		audit_remove_watch_rule(&e->rule);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1008

74c3cbe33   Al Viro   [PATCH] audit: wa...
1009
1010
  	if (e->rule.tree)
  		audit_remove_tree_rule(&e->rule);
34d99af52   Richard Guy Briggs   audit: implement ...
1011
1012
  	if (e->rule.exe)
  		audit_remove_mark_rule(&e->rule);
471a5c7c8   Al Viro   [PATCH] introduce...
1013
1014
1015
  #ifdef CONFIG_AUDITSYSCALL
  	if (!dont_count)
  		audit_n_rules--;
e54dc2431   Amy Griffis   [PATCH] audit sig...
1016
1017
1018
  
  	if (!audit_match_signal(entry))
  		audit_signals--;
471a5c7c8   Al Viro   [PATCH] introduce...
1019
  #endif
8c85fc9ae   Richard Guy Briggs   audit: make audit...
1020
1021
1022
1023
  
  	list_del_rcu(&e->list);
  	list_del(&e->rule.list);
  	call_rcu(&e->rcu, audit_free_rule_rcu);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1024

f368c07d7   Amy Griffis   [PATCH] audit: pa...
1025
  out:
8c85fc9ae   Richard Guy Briggs   audit: make audit...
1026
  	mutex_unlock(&audit_filter_mutex);
74c3cbe33   Al Viro   [PATCH] audit: wa...
1027
1028
  	if (tree)
  		audit_put_tree(tree);	/* that's the temporary one */
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1029
1030
  
  	return ret;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1031
  }
93315ed6d   Amy Griffis   [PATCH] audit str...
1032
  /* List rules using struct audit_rule_data. */
45a0642b4   Paul Moore   audit: kernel gen...
1033
  static void audit_list_rules(int seq, struct sk_buff_head *q)
93315ed6d   Amy Griffis   [PATCH] audit str...
1034
  {
9044e6bca   Al Viro   [PATCH] fix deadl...
1035
  	struct sk_buff *skb;
e45aa212e   Al Viro   audit rules order...
1036
  	struct audit_krule *r;
93315ed6d   Amy Griffis   [PATCH] audit str...
1037
  	int i;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1038
1039
  	/* 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...
1040
  	for (i=0; i<AUDIT_NR_FILTERS; i++) {
e45aa212e   Al Viro   audit rules order...
1041
  		list_for_each_entry(r, &audit_rules_list[i], list) {
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1042
  			struct audit_rule_data *data;
e45aa212e   Al Viro   audit rules order...
1043
  			data = audit_krule_to_data(r);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1044
1045
  			if (unlikely(!data))
  				break;
45a0642b4   Paul Moore   audit: kernel gen...
1046
1047
  			skb = audit_make_reply(seq, AUDIT_LIST_RULES, 0, 1,
  					       data,
f9441639e   Richard Guy Briggs   audit: fix netlin...
1048
  					       sizeof(*data) + data->buflen);
9044e6bca   Al Viro   [PATCH] fix deadl...
1049
1050
  			if (skb)
  				skb_queue_tail(q, skb);
93315ed6d   Amy Griffis   [PATCH] audit str...
1051
1052
1053
  			kfree(data);
  		}
  	}
45a0642b4   Paul Moore   audit: kernel gen...
1054
  	skb = audit_make_reply(seq, AUDIT_LIST_RULES, 1, 1, NULL, 0);
9044e6bca   Al Viro   [PATCH] fix deadl...
1055
1056
  	if (skb)
  		skb_queue_tail(q, skb);
93315ed6d   Amy Griffis   [PATCH] audit str...
1057
  }
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
1058
  /* Log rule additions and removals */
dc9eb698f   Eric Paris   audit: stop pushi...
1059
  static void audit_log_rule_change(char *action, struct audit_krule *rule, int res)
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
1060
1061
  {
  	struct audit_buffer *ab;
1a6b9f231   Eric Paris   [AUDIT] make audi...
1062
1063
  	if (!audit_enabled)
  		return;
626abcd13   Richard Guy Briggs   audit: add syscal...
1064
  	ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_CONFIG_CHANGE);
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
1065
1066
  	if (!ab)
  		return;
5c5b8d8be   Richard Guy Briggs   audit: use existi...
1067
  	audit_log_session_info(ab);
b122c3767   Eric Paris   audit: use a cons...
1068
  	audit_log_task_context(ab);
c1e8f06d7   Steve Grubb   audit: fix format...
1069
  	audit_log_format(ab, " op=%s", action);
9d9609851   Eric Paris   Audit: clean up a...
1070
  	audit_log_key(ab, rule->filterkey);
5adc8a6ad   Amy Griffis   [PATCH] add rule ...
1071
1072
1073
  	audit_log_format(ab, " list=%d res=%d", rule->listnr, res);
  	audit_log_end(ab);
  }
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1074
  /**
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1075
   * audit_rule_change - apply all rules to the specified message type
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1076
   * @type: audit message type
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1077
1078
   * @seq: netlink audit message sequence (serial) number
   * @data: payload data
93315ed6d   Amy Griffis   [PATCH] audit str...
1079
   * @datasz: size of payload data
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1080
   */
45a0642b4   Paul Moore   audit: kernel gen...
1081
  int audit_rule_change(int type, int seq, void *data, size_t datasz)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1082
  {
93315ed6d   Amy Griffis   [PATCH] audit str...
1083
1084
  	int err = 0;
  	struct audit_entry *entry;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1085
1086
  
  	switch (type) {
93315ed6d   Amy Griffis   [PATCH] audit str...
1087
  	case AUDIT_ADD_RULE:
70c4cf17e   Wenwen Wang   audit: fix a memo...
1088
1089
1090
  		entry = audit_data_to_entry(data, datasz);
  		if (IS_ERR(entry))
  			return PTR_ERR(entry);
36c4f1b18   Al Viro   clean up audit_ru...
1091
  		err = audit_add_rule(entry);
e7df61f4d   Burn Alting   audit: invalid op...
1092
  		audit_log_rule_change("add_rule", &entry->rule, !err);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1093
  		break;
93315ed6d   Amy Griffis   [PATCH] audit str...
1094
  	case AUDIT_DEL_RULE:
70c4cf17e   Wenwen Wang   audit: fix a memo...
1095
1096
1097
  		entry = audit_data_to_entry(data, datasz);
  		if (IS_ERR(entry))
  			return PTR_ERR(entry);
36c4f1b18   Al Viro   clean up audit_ru...
1098
  		err = audit_del_rule(entry);
e7df61f4d   Burn Alting   audit: invalid op...
1099
  		audit_log_rule_change("remove_rule", &entry->rule, !err);
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1100
1101
  		break;
  	default:
739c95038   Eric Paris   audit: WARN if au...
1102
  		WARN_ON(1);
70c4cf17e   Wenwen Wang   audit: fix a memo...
1103
  		return -EINVAL;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1104
  	}
34d99af52   Richard Guy Briggs   audit: implement ...
1105
1106
1107
  	if (err || type == AUDIT_DEL_RULE) {
  		if (entry->rule.exe)
  			audit_remove_mark(entry->rule.exe);
e85322d21   Richard Guy Briggs   audit: cull redun...
1108
  		audit_free_rule(entry);
34d99af52   Richard Guy Briggs   audit: implement ...
1109
  	}
e85322d21   Richard Guy Briggs   audit: cull redun...
1110

fe7752bab   David Woodhouse   [PATCH] Fix audit...
1111
1112
  	return err;
  }
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1113
1114
  /**
   * audit_list_rules_send - list the audit rules
d211f177b   Eric W. Biederman   audit: Update kdo...
1115
   * @request_skb: skb of request we are replying to (used to target the reply)
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1116
1117
   * @seq: netlink audit message sequence (serial) number
   */
6f285b19d   Eric W. Biederman   audit: Send repli...
1118
  int audit_list_rules_send(struct sk_buff *request_skb, int seq)
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1119
1120
1121
  {
  	struct task_struct *tsk;
  	struct audit_netlink_list *dest;
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1122
1123
1124
1125
1126
1127
  
  	/* 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 */
3054d0671   Paul Moore   audit: fix a net ...
1128
  	dest = kmalloc(sizeof(*dest), GFP_KERNEL);
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1129
1130
  	if (!dest)
  		return -ENOMEM;
3054d0671   Paul Moore   audit: fix a net ...
1131
1132
  	dest->net = get_net(sock_net(NETLINK_CB(request_skb).sk));
  	dest->portid = NETLINK_CB(request_skb).portid;
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1133
1134
1135
  	skb_queue_head_init(&dest->q);
  
  	mutex_lock(&audit_filter_mutex);
45a0642b4   Paul Moore   audit: kernel gen...
1136
  	audit_list_rules(seq, &dest->q);
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1137
  	mutex_unlock(&audit_filter_mutex);
3054d0671   Paul Moore   audit: fix a net ...
1138
  	tsk = kthread_run(audit_send_list_thread, dest, "audit_send_list");
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1139
1140
  	if (IS_ERR(tsk)) {
  		skb_queue_purge(&dest->q);
3054d0671   Paul Moore   audit: fix a net ...
1141
  		put_net(dest->net);
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1142
  		kfree(dest);
3054d0671   Paul Moore   audit: fix a net ...
1143
  		return PTR_ERR(tsk);
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1144
  	}
3054d0671   Paul Moore   audit: fix a net ...
1145
  	return 0;
ce0d9f046   Richard Guy Briggs   audit: refactor a...
1146
  }
5af75d8d5   Al Viro   audit: validate c...
1147
  int audit_comparator(u32 left, u32 op, u32 right)
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1148
1149
  {
  	switch (op) {
5af75d8d5   Al Viro   audit: validate c...
1150
  	case Audit_equal:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1151
  		return (left == right);
5af75d8d5   Al Viro   audit: validate c...
1152
  	case Audit_not_equal:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1153
  		return (left != right);
5af75d8d5   Al Viro   audit: validate c...
1154
  	case Audit_lt:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1155
  		return (left < right);
5af75d8d5   Al Viro   audit: validate c...
1156
  	case Audit_le:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1157
  		return (left <= right);
5af75d8d5   Al Viro   audit: validate c...
1158
  	case Audit_gt:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1159
  		return (left > right);
5af75d8d5   Al Viro   audit: validate c...
1160
  	case Audit_ge:
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1161
  		return (left >= right);
5af75d8d5   Al Viro   audit: validate c...
1162
  	case Audit_bitmask:
74f2345b6   Eric Paris   [PATCH] allow aud...
1163
  		return (left & right);
5af75d8d5   Al Viro   audit: validate c...
1164
  	case Audit_bittest:
74f2345b6   Eric Paris   [PATCH] allow aud...
1165
  		return ((left & right) == right);
5af75d8d5   Al Viro   audit: validate c...
1166
  	default:
5af75d8d5   Al Viro   audit: validate c...
1167
  		return 0;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1168
1169
  	}
  }
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
  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:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
  		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:
ca57ec0f0   Eric W. Biederman   audit: Add typesp...
1210
1211
1212
  		return 0;
  	}
  }
bfcec7087   Jeff Layton   audit: set the na...
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
  /**
   * 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...
1242
1243
1244
1245
1246
1247
1248
1249
  /**
   * 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.
   */
795d673af   Al Viro   audit_compare_dna...
1250
  int audit_compare_dname_path(const struct qstr *dname, const char *path, int parentlen)
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1251
  {
e3d6b07b8   Jeff Layton   audit: optimize a...
1252
  	int dlen, pathlen;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1253
  	const char *p;
795d673af   Al Viro   audit_compare_dna...
1254
  	dlen = dname->len;
29e9a3467   Eric Paris   audit: make audit...
1255
1256
  	pathlen = strlen(path);
  	if (pathlen < dlen)
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1257
  		return 1;
e3d6b07b8   Jeff Layton   audit: optimize a...
1258
  	parentlen = parentlen == AUDIT_NAME_FULL ? parent_len(path) : parentlen;
29e9a3467   Eric Paris   audit: make audit...
1259
  	if (pathlen - parentlen != dlen)
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1260
  		return 1;
29e9a3467   Eric Paris   audit: make audit...
1261
1262
  
  	p = path + parentlen;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1263

795d673af   Al Viro   audit_compare_dna...
1264
  	return strncmp(p, dname->name, dlen);
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1265
  }
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1266

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

fe7752bab   David Woodhouse   [PATCH] Fix audit...
1272
  	rcu_read_lock();
86b2efbe3   Richard Guy Briggs   audit: add fields...
1273
1274
  	list_for_each_entry_rcu(e, &audit_filter_list[listtype], list) {
  		int i, result = 0;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1275

93315ed6d   Amy Griffis   [PATCH] audit str...
1276
1277
  		for (i = 0; i < e->rule.field_count; i++) {
  			struct audit_field *f = &e->rule.fields[i];
86b2efbe3   Richard Guy Briggs   audit: add fields...
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
  			pid_t pid;
  			u32 sid;
  
  			switch (f->type) {
  			case AUDIT_PID:
  				pid = task_pid_nr(current);
  				result = audit_comparator(pid, f->op, f->val);
  				break;
  			case AUDIT_UID:
  				result = audit_uid_comparator(current_uid(), f->op, f->uid);
  				break;
  			case AUDIT_GID:
  				result = audit_gid_comparator(current_gid(), f->op, f->gid);
  				break;
  			case AUDIT_LOGINUID:
  				result = audit_uid_comparator(audit_get_loginuid(current),
  							      f->op, f->uid);
  				break;
  			case AUDIT_LOGINUID_SET:
  				result = audit_comparator(audit_loginuid_set(current),
  							  f->op, f->val);
  				break;
  			case AUDIT_MSGTYPE:
  				result = audit_comparator(msgtype, f->op, f->val);
  				break;
  			case AUDIT_SUBJ_USER:
  			case AUDIT_SUBJ_ROLE:
  			case AUDIT_SUBJ_TYPE:
  			case AUDIT_SUBJ_SEN:
  			case AUDIT_SUBJ_CLR:
  				if (f->lsm_rule) {
  					security_task_getsecid(current, &sid);
  					result = security_audit_rule_match(sid,
90462a5bd   Richard Guy Briggs   audit: remove unu...
1311
  						   f->type, f->op, f->lsm_rule);
86b2efbe3   Richard Guy Briggs   audit: add fields...
1312
1313
  				}
  				break;
29c1372d6   Ondrej Mosnáček   audit: allow othe...
1314
1315
1316
1317
1318
  			case AUDIT_EXE:
  				result = audit_exe_compare(current, e->rule.exe);
  				if (f->op == Audit_not_equal)
  					result = !result;
  				break;
86b2efbe3   Richard Guy Briggs   audit: add fields...
1319
1320
  			default:
  				goto unlock_and_return;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1321
  			}
86b2efbe3   Richard Guy Briggs   audit: add fields...
1322
1323
1324
1325
1326
1327
  			if (result < 0) /* error */
  				goto unlock_and_return;
  			if (!result)
  				break;
  		}
  		if (result > 0) {
d904ac032   Richard Guy Briggs   audit: rename FIL...
1328
  			if (e->rule.action == AUDIT_NEVER || listtype == AUDIT_FILTER_EXCLUDE)
86b2efbe3   Richard Guy Briggs   audit: add fields...
1329
1330
  				ret = 0;
  			break;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1331
  		}
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1332
1333
1334
  	}
  unlock_and_return:
  	rcu_read_unlock();
86b2efbe3   Richard Guy Briggs   audit: add fields...
1335
  	return ret;
fe7752bab   David Woodhouse   [PATCH] Fix audit...
1336
  }
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1337

e45aa212e   Al Viro   audit rules order...
1338
  static int update_lsm_rule(struct audit_krule *r)
1a9d0797b   Al Viro   audit_update_lsm_...
1339
  {
e45aa212e   Al Viro   audit rules order...
1340
  	struct audit_entry *entry = container_of(r, struct audit_entry, rule);
1a9d0797b   Al Viro   audit_update_lsm_...
1341
  	struct audit_entry *nentry;
1a9d0797b   Al Viro   audit_update_lsm_...
1342
  	int err = 0;
e45aa212e   Al Viro   audit rules order...
1343
  	if (!security_audit_rule_known(r))
1a9d0797b   Al Viro   audit_update_lsm_...
1344
  		return 0;
ae7b8f410   Eric Paris   Audit: clean up t...
1345
  	nentry = audit_dupe_rule(r);
34d99af52   Richard Guy Briggs   audit: implement ...
1346
1347
  	if (entry->rule.exe)
  		audit_remove_mark(entry->rule.exe);
1a9d0797b   Al Viro   audit_update_lsm_...
1348
1349
1350
1351
1352
  	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...
1353
  		if (r->watch)
e45aa212e   Al Viro   audit rules order...
1354
  			list_del(&r->rlist);
1a9d0797b   Al Viro   audit_update_lsm_...
1355
  		list_del_rcu(&entry->list);
e45aa212e   Al Viro   audit rules order...
1356
  		list_del(&r->list);
1a9d0797b   Al Viro   audit_update_lsm_...
1357
  	} else {
ae7b8f410   Eric Paris   Audit: clean up t...
1358
  		if (r->watch || r->tree)
e45aa212e   Al Viro   audit rules order...
1359
  			list_replace_init(&r->rlist, &nentry->rule.rlist);
1a9d0797b   Al Viro   audit_update_lsm_...
1360
  		list_replace_rcu(&entry->list, &nentry->list);
e45aa212e   Al Viro   audit rules order...
1361
  		list_replace(&r->list, &nentry->rule.list);
1a9d0797b   Al Viro   audit_update_lsm_...
1362
1363
1364
1365
1366
  	}
  	call_rcu(&entry->rcu, audit_free_rule_rcu);
  
  	return err;
  }
04305e4af   Ahmed S. Darwish   Audit: Final rena...
1367
  /* This function will re-initialize the lsm_rule field of all applicable rules.
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
1368
   * It will traverse the filter lists serarching for rules that contain LSM
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1369
   * specific filter fields.  When such a rule is found, it is copied, the
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
1370
   * LSM field is re-initialized, and the old rule is replaced with the
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1371
   * updated rule. */
d7a96f3a1   Ahmed S. Darwish   Audit: internally...
1372
  int audit_update_lsm_rules(void)
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1373
  {
e45aa212e   Al Viro   audit rules order...
1374
  	struct audit_krule *r, *n;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1375
  	int i, err = 0;
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1376
1377
  	/* audit_filter_mutex synchronizes the writers */
  	mutex_lock(&audit_filter_mutex);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1378
1379
  
  	for (i = 0; i < AUDIT_NR_FILTERS; i++) {
e45aa212e   Al Viro   audit rules order...
1380
1381
  		list_for_each_entry_safe(r, n, &audit_rules_list[i], list) {
  			int res = update_lsm_rule(r);
1a9d0797b   Al Viro   audit_update_lsm_...
1382
1383
  			if (!err)
  				err = res;
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1384
1385
  		}
  	}
f368c07d7   Amy Griffis   [PATCH] audit: pa...
1386
  	mutex_unlock(&audit_filter_mutex);
3dc7e3153   Darrel Goeddel   [PATCH] support f...
1387
1388
1389
  
  	return err;
  }