Blame view

security/selinux/avc.c 21.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
  /*
   * Implementation of the kernel access vector cache (AVC).
   *
   * Authors:  Stephen Smalley, <sds@epoch.ncsc.mil>
95fff33b8   Eric Paris   SELinux: one litt...
5
   *	     James Morris <jmorris@redhat.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
   *
   * Update:   KaiGai, Kohei <kaigai@ak.jp.nec.com>
95fff33b8   Eric Paris   SELinux: one litt...
8
   *	Replaced the avc_lock spinlock by RCU.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
13
   *
   * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
   *
   *	This program is free software; you can redistribute it and/or modify
   *	it under the terms of the GNU General Public License version 2,
95fff33b8   Eric Paris   SELinux: one litt...
14
   *	as published by the Free Software Foundation.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
   */
  #include <linux/types.h>
  #include <linux/stddef.h>
  #include <linux/kernel.h>
  #include <linux/slab.h>
  #include <linux/fs.h>
  #include <linux/dcache.h>
  #include <linux/init.h>
  #include <linux/skbuff.h>
  #include <linux/percpu.h>
  #include <net/sock.h>
  #include <linux/un.h>
  #include <net/af_unix.h>
  #include <linux/ip.h>
  #include <linux/audit.h>
  #include <linux/ipv6.h>
  #include <net/ipv6.h>
  #include "avc.h"
  #include "avc_ss.h"
c6d3aaa4e   Stephen Smalley   selinux: dynamic ...
34
  #include "classmap.h"
5c4589987   Chad Sellers   SELinux: export o...
35

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
39
40
  #define AVC_CACHE_SLOTS			512
  #define AVC_DEF_CACHE_THRESHOLD		512
  #define AVC_CACHE_RECLAIM		16
  
  #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
95fff33b8   Eric Paris   SELinux: one litt...
41
  #define avc_cache_stats_incr(field)				\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
46
47
48
49
50
51
52
53
54
  do {								\
  	per_cpu(avc_cache_stats, get_cpu()).field++;		\
  	put_cpu();						\
  } while (0)
  #else
  #define avc_cache_stats_incr(field)	do {} while (0)
  #endif
  
  struct avc_entry {
  	u32			ssid;
  	u32			tsid;
  	u16			tclass;
  	struct av_decision	avd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
58
  };
  
  struct avc_node {
  	struct avc_entry	ae;
26036651c   Eric Paris   SELinux: convert ...
59
  	struct hlist_node	list; /* anchored in avc_cache->slots[i] */
95fff33b8   Eric Paris   SELinux: one litt...
60
  	struct rcu_head		rhead;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
63
  };
  
  struct avc_cache {
26036651c   Eric Paris   SELinux: convert ...
64
  	struct hlist_head	slots[AVC_CACHE_SLOTS]; /* head for avc_node->list */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
67
68
69
70
71
72
  	spinlock_t		slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */
  	atomic_t		lru_hint;	/* LRU hint for reclaim scan */
  	atomic_t		active_nodes;
  	u32			latest_notif;	/* latest revocation notification */
  };
  
  struct avc_callback_node {
  	int (*callback) (u32 event, u32 ssid, u32 tsid,
95fff33b8   Eric Paris   SELinux: one litt...
73
74
  			 u16 tclass, u32 perms,
  			 u32 *out_retained);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
  	u32 events;
  	u32 ssid;
  	u32 tsid;
  	u16 tclass;
  	u32 perms;
  	struct avc_callback_node *next;
  };
  
  /* Exported via selinufs */
  unsigned int avc_cache_threshold = AVC_DEF_CACHE_THRESHOLD;
  
  #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
  DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 };
  #endif
  
  static struct avc_cache avc_cache;
  static struct avc_callback_node *avc_callbacks;
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
92
  static struct kmem_cache *avc_node_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
95
96
97
98
99
100
101
102
103
  
  static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
  {
  	return (ssid ^ (tsid<<2) ^ (tclass<<4)) & (AVC_CACHE_SLOTS - 1);
  }
  
  /**
   * avc_dump_av - Display an access vector in human-readable form.
   * @tclass: target security class
   * @av: access vector
   */
44c2d9bdd   KaiGai Kohei   Add audit message...
104
  static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  {
c6d3aaa4e   Stephen Smalley   selinux: dynamic ...
106
107
  	const char **perms;
  	int i, perm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
110
111
112
  
  	if (av == 0) {
  		audit_log_format(ab, " null");
  		return;
  	}
c6d3aaa4e   Stephen Smalley   selinux: dynamic ...
113
  	perms = secclass_map[tclass-1].perms;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
116
117
  
  	audit_log_format(ab, " {");
  	i = 0;
  	perm = 1;
c6d3aaa4e   Stephen Smalley   selinux: dynamic ...
118
  	while (i < (sizeof(av) * 8)) {
0bce95279   Eric Paris   SELinux: print de...
119
  		if ((perm & av) && perms[i]) {
c6d3aaa4e   Stephen Smalley   selinux: dynamic ...
120
  			audit_log_format(ab, " %s", perms[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
124
125
  			av &= ~perm;
  		}
  		i++;
  		perm <<= 1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  	if (av)
  		audit_log_format(ab, " 0x%x", av);
  
  	audit_log_format(ab, " }");
  }
  
  /**
   * avc_dump_query - Display a SID pair and a class in human-readable form.
   * @ssid: source security identifier
   * @tsid: target security identifier
   * @tclass: target security class
   */
  static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tclass)
  {
  	int rc;
  	char *scontext;
  	u32 scontext_len;
95fff33b8   Eric Paris   SELinux: one litt...
143
  	rc = security_sid_to_context(ssid, &scontext, &scontext_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
147
148
149
150
151
152
153
154
155
156
157
  	if (rc)
  		audit_log_format(ab, "ssid=%d", ssid);
  	else {
  		audit_log_format(ab, "scontext=%s", scontext);
  		kfree(scontext);
  	}
  
  	rc = security_sid_to_context(tsid, &scontext, &scontext_len);
  	if (rc)
  		audit_log_format(ab, " tsid=%d", tsid);
  	else {
  		audit_log_format(ab, " tcontext=%s", scontext);
  		kfree(scontext);
  	}
a764ae4b0   Stephen Smalley   selinux: remove u...
158

c6d3aaa4e   Stephen Smalley   selinux: dynamic ...
159
160
  	BUG_ON(tclass >= ARRAY_SIZE(secclass_map));
  	audit_log_format(ab, " tclass=%s", secclass_map[tclass-1].name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
164
165
166
167
168
169
170
171
172
  }
  
  /**
   * avc_init - Initialize the AVC.
   *
   * Initialize the access vector cache.
   */
  void __init avc_init(void)
  {
  	int i;
  
  	for (i = 0; i < AVC_CACHE_SLOTS; i++) {
26036651c   Eric Paris   SELinux: convert ...
173
  		INIT_HLIST_HEAD(&avc_cache.slots[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
176
177
178
179
  		spin_lock_init(&avc_cache.slots_lock[i]);
  	}
  	atomic_set(&avc_cache.active_nodes, 0);
  	atomic_set(&avc_cache.lru_hint, 0);
  
  	avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node),
20c2df83d   Paul Mundt   mm: Remove slab d...
180
  					     0, SLAB_PANIC, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181

9ad9ad385   David Woodhouse   AUDIT: Wait for b...
182
183
  	audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
186
187
188
189
  }
  
  int avc_get_hash_stats(char *page)
  {
  	int i, chain_len, max_chain_len, slots_used;
  	struct avc_node *node;
26036651c   Eric Paris   SELinux: convert ...
190
  	struct hlist_head *head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
193
194
195
196
  
  	rcu_read_lock();
  
  	slots_used = 0;
  	max_chain_len = 0;
  	for (i = 0; i < AVC_CACHE_SLOTS; i++) {
edf3d1aec   Eric Paris   SELinux: code rea...
197
  		head = &avc_cache.slots[i];
26036651c   Eric Paris   SELinux: convert ...
198
199
  		if (!hlist_empty(head)) {
  			struct hlist_node *next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
201
  			slots_used++;
  			chain_len = 0;
26036651c   Eric Paris   SELinux: convert ...
202
  			hlist_for_each_entry_rcu(node, next, head, list)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
  				chain_len++;
  			if (chain_len > max_chain_len)
  				max_chain_len = chain_len;
  		}
  	}
  
  	rcu_read_unlock();
  
  	return scnprintf(page, PAGE_SIZE, "entries: %d
  buckets used: %d/%d
  "
  			 "longest chain: %d
  ",
  			 atomic_read(&avc_cache.active_nodes),
  			 slots_used, AVC_CACHE_SLOTS, max_chain_len);
  }
  
  static void avc_node_free(struct rcu_head *rhead)
  {
  	struct avc_node *node = container_of(rhead, struct avc_node, rhead);
  	kmem_cache_free(avc_node_cachep, node);
  	avc_cache_stats_incr(frees);
  }
  
  static void avc_node_delete(struct avc_node *node)
  {
26036651c   Eric Paris   SELinux: convert ...
229
  	hlist_del_rcu(&node->list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
231
232
233
234
235
236
237
238
239
240
241
242
  	call_rcu(&node->rhead, avc_node_free);
  	atomic_dec(&avc_cache.active_nodes);
  }
  
  static void avc_node_kill(struct avc_node *node)
  {
  	kmem_cache_free(avc_node_cachep, node);
  	avc_cache_stats_incr(frees);
  	atomic_dec(&avc_cache.active_nodes);
  }
  
  static void avc_node_replace(struct avc_node *new, struct avc_node *old)
  {
26036651c   Eric Paris   SELinux: convert ...
243
  	hlist_replace_rcu(&old->list, &new->list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
246
247
248
249
250
251
252
  	call_rcu(&old->rhead, avc_node_free);
  	atomic_dec(&avc_cache.active_nodes);
  }
  
  static inline int avc_reclaim_node(void)
  {
  	struct avc_node *node;
  	int hvalue, try, ecx;
  	unsigned long flags;
26036651c   Eric Paris   SELinux: convert ...
253
254
  	struct hlist_head *head;
  	struct hlist_node *next;
edf3d1aec   Eric Paris   SELinux: code rea...
255
  	spinlock_t *lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256

95fff33b8   Eric Paris   SELinux: one litt...
257
  	for (try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
  		hvalue = atomic_inc_return(&avc_cache.lru_hint) & (AVC_CACHE_SLOTS - 1);
edf3d1aec   Eric Paris   SELinux: code rea...
259
260
  		head = &avc_cache.slots[hvalue];
  		lock = &avc_cache.slots_lock[hvalue];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261

edf3d1aec   Eric Paris   SELinux: code rea...
262
  		if (!spin_trylock_irqsave(lock, flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
  			continue;
618442509   Paul E. McKenney   SELinux fixups ne...
264
  		rcu_read_lock();
26036651c   Eric Paris   SELinux: convert ...
265
  		hlist_for_each_entry(node, next, head, list) {
906d27d9d   Eric Paris   SELinux: remove t...
266
267
268
269
270
  			avc_node_delete(node);
  			avc_cache_stats_incr(reclaims);
  			ecx++;
  			if (ecx >= AVC_CACHE_RECLAIM) {
  				rcu_read_unlock();
edf3d1aec   Eric Paris   SELinux: code rea...
271
  				spin_unlock_irqrestore(lock, flags);
906d27d9d   Eric Paris   SELinux: remove t...
272
  				goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
274
  			}
  		}
618442509   Paul E. McKenney   SELinux fixups ne...
275
  		rcu_read_unlock();
edf3d1aec   Eric Paris   SELinux: code rea...
276
  		spin_unlock_irqrestore(lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
278
279
280
281
282
283
284
  	}
  out:
  	return ecx;
  }
  
  static struct avc_node *avc_alloc_node(void)
  {
  	struct avc_node *node;
c37622296   Robert P. J. Day   [PATCH] Transform...
285
  	node = kmem_cache_zalloc(avc_node_cachep, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
  	if (!node)
  		goto out;
26036651c   Eric Paris   SELinux: convert ...
288
  	INIT_HLIST_NODE(&node->list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
291
292
293
294
295
296
  	avc_cache_stats_incr(allocations);
  
  	if (atomic_inc_return(&avc_cache.active_nodes) > avc_cache_threshold)
  		avc_reclaim_node();
  
  out:
  	return node;
  }
21193dcd1   Eric Paris   SELinux: more car...
297
  static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
299
300
301
  {
  	node->ae.ssid = ssid;
  	node->ae.tsid = tsid;
  	node->ae.tclass = tclass;
21193dcd1   Eric Paris   SELinux: more car...
302
  	memcpy(&node->ae.avd, avd, sizeof(node->ae.avd));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
304
305
306
307
308
  }
  
  static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass)
  {
  	struct avc_node *node, *ret = NULL;
  	int hvalue;
26036651c   Eric Paris   SELinux: convert ...
309
310
  	struct hlist_head *head;
  	struct hlist_node *next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
  
  	hvalue = avc_hash(ssid, tsid, tclass);
edf3d1aec   Eric Paris   SELinux: code rea...
313
  	head = &avc_cache.slots[hvalue];
26036651c   Eric Paris   SELinux: convert ...
314
  	hlist_for_each_entry_rcu(node, next, head, list) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
316
317
318
319
320
321
  		if (ssid == node->ae.ssid &&
  		    tclass == node->ae.tclass &&
  		    tsid == node->ae.tsid) {
  			ret = node;
  			break;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
323
324
325
326
327
328
329
  	return ret;
  }
  
  /**
   * avc_lookup - Look up an AVC entry.
   * @ssid: source security identifier
   * @tsid: target security identifier
   * @tclass: target security class
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
331
   *
   * Look up an AVC entry that is valid for the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
   * (@ssid, @tsid), interpreting the permissions
   * based on @tclass.  If a valid AVC entry exists,
6382dc334   Justin P. Mattock   fix comment typos...
334
   * then this function returns the avc_node.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
336
   * Otherwise, this function returns NULL.
   */
f1c6381a6   Eric Paris   SELinux: remove u...
337
  static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
339
340
341
342
  {
  	struct avc_node *node;
  
  	avc_cache_stats_incr(lookups);
  	node = avc_search_node(ssid, tsid, tclass);
f1c6381a6   Eric Paris   SELinux: remove u...
343
  	if (node)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
  		avc_cache_stats_incr(hits);
f1c6381a6   Eric Paris   SELinux: remove u...
345
346
  	else
  		avc_cache_stats_incr(misses);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
350
351
352
353
354
355
356
357
358
359
  	return node;
  }
  
  static int avc_latest_notif_update(int seqno, int is_insert)
  {
  	int ret = 0;
  	static DEFINE_SPINLOCK(notif_lock);
  	unsigned long flag;
  
  	spin_lock_irqsave(&notif_lock, flag);
  	if (is_insert) {
  		if (seqno < avc_cache.latest_notif) {
744ba35e4   Eric Paris   SELinux: clean up...
360
361
  			printk(KERN_WARNING "SELinux: avc:  seqno %d < latest_notif %d
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  			       seqno, avc_cache.latest_notif);
  			ret = -EAGAIN;
  		}
  	} else {
  		if (seqno > avc_cache.latest_notif)
  			avc_cache.latest_notif = seqno;
  	}
  	spin_unlock_irqrestore(&notif_lock, flag);
  
  	return ret;
  }
  
  /**
   * avc_insert - Insert an AVC entry.
   * @ssid: source security identifier
   * @tsid: target security identifier
   * @tclass: target security class
21193dcd1   Eric Paris   SELinux: more car...
379
   * @avd: resulting av decision
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
382
383
384
385
   *
   * Insert an AVC entry for the SID pair
   * (@ssid, @tsid) and class @tclass.
   * The access vectors and the sequence number are
   * normally provided by the security server in
   * response to a security_compute_av() call.  If the
21193dcd1   Eric Paris   SELinux: more car...
386
   * sequence number @avd->seqno is not less than the latest
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
389
390
   * revocation notification, then the function copies
   * the access vectors into a cache entry, returns
   * avc_node inserted. Otherwise, this function returns NULL.
   */
21193dcd1   Eric Paris   SELinux: more car...
391
  static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
393
394
395
  {
  	struct avc_node *pos, *node = NULL;
  	int hvalue;
  	unsigned long flag;
21193dcd1   Eric Paris   SELinux: more car...
396
  	if (avc_latest_notif_update(avd->seqno, 1))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
399
400
  		goto out;
  
  	node = avc_alloc_node();
  	if (node) {
26036651c   Eric Paris   SELinux: convert ...
401
402
  		struct hlist_head *head;
  		struct hlist_node *next;
edf3d1aec   Eric Paris   SELinux: code rea...
403
  		spinlock_t *lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
  		hvalue = avc_hash(ssid, tsid, tclass);
21193dcd1   Eric Paris   SELinux: more car...
405
  		avc_node_populate(node, ssid, tsid, tclass, avd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406

edf3d1aec   Eric Paris   SELinux: code rea...
407
408
409
410
  		head = &avc_cache.slots[hvalue];
  		lock = &avc_cache.slots_lock[hvalue];
  
  		spin_lock_irqsave(lock, flag);
26036651c   Eric Paris   SELinux: convert ...
411
  		hlist_for_each_entry(pos, next, head, list) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
413
414
  			if (pos->ae.ssid == ssid &&
  			    pos->ae.tsid == tsid &&
  			    pos->ae.tclass == tclass) {
95fff33b8   Eric Paris   SELinux: one litt...
415
  				avc_node_replace(node, pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
417
418
  				goto found;
  			}
  		}
26036651c   Eric Paris   SELinux: convert ...
419
  		hlist_add_head_rcu(&node->list, head);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
  found:
edf3d1aec   Eric Paris   SELinux: code rea...
421
  		spin_unlock_irqrestore(lock, flag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
424
425
  	}
  out:
  	return node;
  }
2bf496903   Thomas Liu   SELinux: Convert ...
426
427
428
429
430
431
432
  /**
   * avc_audit_pre_callback - SELinux specific information
   * will be called by generic audit code
   * @ab: the audit buffer
   * @a: audit_data
   */
  static void avc_audit_pre_callback(struct audit_buffer *ab, void *a)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
  {
2bf496903   Thomas Liu   SELinux: Convert ...
434
435
436
437
438
439
  	struct common_audit_data *ad = a;
  	audit_log_format(ab, "avc:  %s ",
  			 ad->selinux_audit_data.denied ? "denied" : "granted");
  	avc_dump_av(ab, ad->selinux_audit_data.tclass,
  			ad->selinux_audit_data.audited);
  	audit_log_format(ab, " for ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
  }
2bf496903   Thomas Liu   SELinux: Convert ...
441
442
443
444
445
446
447
  /**
   * avc_audit_post_callback - SELinux specific information
   * will be called by generic audit code
   * @ab: the audit buffer
   * @a: audit_data
   */
  static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
  {
2bf496903   Thomas Liu   SELinux: Convert ...
449
450
451
452
453
  	struct common_audit_data *ad = a;
  	audit_log_format(ab, " ");
  	avc_dump_query(ab, ad->selinux_audit_data.ssid,
  			   ad->selinux_audit_data.tsid,
  			   ad->selinux_audit_data.tclass);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
455
456
457
458
459
460
461
462
463
464
  }
  
  /**
   * avc_audit - Audit the granting or denial of permissions.
   * @ssid: source security identifier
   * @tsid: target security identifier
   * @tclass: target security class
   * @requested: requested permissions
   * @avd: access vector decisions
   * @result: result from avc_has_perm_noaudit
   * @a:  auxiliary audit data
0dc1ba24f   Eric Paris   SELINUX: Make sel...
465
   * @flags: VFS walk flags
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
467
468
469
470
471
472
473
474
475
   *
   * Audit the granting or denial of permissions in accordance
   * with the policy.  This function is typically called by
   * avc_has_perm() after a permission check, but can also be
   * called directly by callers who use avc_has_perm_noaudit()
   * in order to separate the permission check from the auditing.
   * For example, this separation is useful when the permission check must
   * be performed under a lock, to allow the lock to be released
   * before calling the auditing code.
   */
0dc1ba24f   Eric Paris   SELINUX: Make sel...
476
  int avc_audit(u32 ssid, u32 tsid,
95fff33b8   Eric Paris   SELinux: one litt...
477
  	       u16 tclass, u32 requested,
0dc1ba24f   Eric Paris   SELINUX: Make sel...
478
479
  	       struct av_decision *avd, int result, struct common_audit_data *a,
  	       unsigned flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
  {
2bf496903   Thomas Liu   SELinux: Convert ...
481
  	struct common_audit_data stack_data;
be940d627   James Morris   Revert "SELinux: ...
482
  	u32 denied, audited;
be940d627   James Morris   Revert "SELinux: ...
483
  	denied = requested & ~avd->allowed;
b782e0a68   Eric Paris   SELinux: special ...
484
  	if (denied) {
b6cac5a30   Stephen Smalley   selinux: Only aud...
485
  		audited = denied & avd->auditdeny;
b782e0a68   Eric Paris   SELinux: special ...
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
  		/*
  		 * a->selinux_audit_data.auditdeny is TRICKY!  Setting a bit in
  		 * this field means that ANY denials should NOT be audited if
  		 * the policy contains an explicit dontaudit rule for that
  		 * permission.  Take notice that this is unrelated to the
  		 * actual permissions that were denied.  As an example lets
  		 * assume:
  		 *
  		 * denied == READ
  		 * avd.auditdeny & ACCESS == 0 (not set means explicit rule)
  		 * selinux_audit_data.auditdeny & ACCESS == 1
  		 *
  		 * We will NOT audit the denial even though the denied
  		 * permission was READ and the auditdeny checks were for
  		 * ACCESS
  		 */
  		if (a &&
  		    a->selinux_audit_data.auditdeny &&
  		    !(a->selinux_audit_data.auditdeny & avd->auditdeny))
  			audited = 0;
  	} else if (result)
be940d627   James Morris   Revert "SELinux: ...
507
  		audited = denied = requested;
b6cac5a30   Stephen Smalley   selinux: Only aud...
508
509
510
  	else
  		audited = requested & avd->auditallow;
  	if (!audited)
0dc1ba24f   Eric Paris   SELINUX: Make sel...
511
  		return 0;
2bf496903   Thomas Liu   SELinux: Convert ...
512
513
  	if (!a) {
  		a = &stack_data;
cb84aa9b4   Eric Paris   LSM Audit: rename...
514
  		COMMON_AUDIT_DATA_INIT(a, NONE);
be940d627   James Morris   Revert "SELinux: ...
515
  	}
0dc1ba24f   Eric Paris   SELINUX: Make sel...
516
517
518
519
520
521
522
523
524
525
526
  
  	/*
  	 * When in a RCU walk do the audit on the RCU retry.  This is because
  	 * the collection of the dname in an inode audit message is not RCU
  	 * safe.  Note this may drop some audits when the situation changes
  	 * during retry. However this is logically just as if the operation
  	 * happened a little later.
  	 */
  	if ((a->type == LSM_AUDIT_DATA_FS) &&
  	    (flags & IPERM_FLAG_RCU))
  		return -ECHILD;
2bf496903   Thomas Liu   SELinux: Convert ...
527
528
529
530
531
532
533
534
535
  	a->selinux_audit_data.tclass = tclass;
  	a->selinux_audit_data.requested = requested;
  	a->selinux_audit_data.ssid = ssid;
  	a->selinux_audit_data.tsid = tsid;
  	a->selinux_audit_data.audited = audited;
  	a->selinux_audit_data.denied = denied;
  	a->lsm_pre_audit = avc_audit_pre_callback;
  	a->lsm_post_audit = avc_audit_post_callback;
  	common_lsm_audit(a);
0dc1ba24f   Eric Paris   SELINUX: Make sel...
536
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
539
540
541
542
543
544
545
546
547
548
  }
  
  /**
   * avc_add_callback - Register a callback for security events.
   * @callback: callback function
   * @events: security events
   * @ssid: source security identifier or %SECSID_WILD
   * @tsid: target security identifier or %SECSID_WILD
   * @tclass: target security class
   * @perms: permissions
   *
   * Register a callback function for events in the set @events
6382dc334   Justin P. Mattock   fix comment typos...
549
   * related to the SID pair (@ssid, @tsid) 
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
551
552
553
554
   * and the permissions @perms, interpreting
   * @perms based on @tclass.  Returns %0 on success or
   * -%ENOMEM if insufficient memory exists to add the callback.
   */
  int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
95fff33b8   Eric Paris   SELinux: one litt...
555
556
557
558
  				     u16 tclass, u32 perms,
  				     u32 *out_retained),
  		     u32 events, u32 ssid, u32 tsid,
  		     u16 tclass, u32 perms)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
  {
  	struct avc_callback_node *c;
  	int rc = 0;
  
  	c = kmalloc(sizeof(*c), GFP_ATOMIC);
  	if (!c) {
  		rc = -ENOMEM;
  		goto out;
  	}
  
  	c->callback = callback;
  	c->events = events;
  	c->ssid = ssid;
  	c->tsid = tsid;
  	c->perms = perms;
  	c->next = avc_callbacks;
  	avc_callbacks = c;
  out:
  	return rc;
  }
  
  static inline int avc_sidcmp(u32 x, u32 y)
  {
  	return (x == y || x == SECSID_WILD || y == SECSID_WILD);
  }
  
  /**
   * avc_update_node Update an AVC entry
   * @event : Updating event
   * @perms : Permission mask bits
   * @ssid,@tsid,@tclass : identifier of an AVC entry
a5dda6833   Eric Paris   SELinux: check se...
590
   * @seqno : sequence number when decision was made
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
592
593
   *
   * if a valid AVC entry doesn't exist,this function returns -ENOENT.
   * if kmalloc() called internal returns NULL, this function returns -ENOMEM.
6382dc334   Justin P. Mattock   fix comment typos...
594
   * otherwise, this function updates the AVC entry. The original AVC-entry object
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
596
   * will release later by RCU.
   */
a5dda6833   Eric Paris   SELinux: check se...
597
598
  static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass,
  			   u32 seqno)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
600
601
602
  {
  	int hvalue, rc = 0;
  	unsigned long flag;
  	struct avc_node *pos, *node, *orig = NULL;
26036651c   Eric Paris   SELinux: convert ...
603
604
  	struct hlist_head *head;
  	struct hlist_node *next;
edf3d1aec   Eric Paris   SELinux: code rea...
605
  	spinlock_t *lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
608
609
610
611
612
613
614
  
  	node = avc_alloc_node();
  	if (!node) {
  		rc = -ENOMEM;
  		goto out;
  	}
  
  	/* Lock the target slot */
  	hvalue = avc_hash(ssid, tsid, tclass);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615

edf3d1aec   Eric Paris   SELinux: code rea...
616
617
618
619
  	head = &avc_cache.slots[hvalue];
  	lock = &avc_cache.slots_lock[hvalue];
  
  	spin_lock_irqsave(lock, flag);
26036651c   Eric Paris   SELinux: convert ...
620
  	hlist_for_each_entry(pos, next, head, list) {
95fff33b8   Eric Paris   SELinux: one litt...
621
622
  		if (ssid == pos->ae.ssid &&
  		    tsid == pos->ae.tsid &&
a5dda6833   Eric Paris   SELinux: check se...
623
624
  		    tclass == pos->ae.tclass &&
  		    seqno == pos->ae.avd.seqno){
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
627
628
629
630
631
632
633
634
635
636
637
638
  			orig = pos;
  			break;
  		}
  	}
  
  	if (!orig) {
  		rc = -ENOENT;
  		avc_node_kill(node);
  		goto out_unlock;
  	}
  
  	/*
  	 * Copy and replace original node.
  	 */
21193dcd1   Eric Paris   SELinux: more car...
639
  	avc_node_populate(node, ssid, tsid, tclass, &orig->ae.avd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
  
  	switch (event) {
  	case AVC_CALLBACK_GRANT:
  		node->ae.avd.allowed |= perms;
  		break;
  	case AVC_CALLBACK_TRY_REVOKE:
  	case AVC_CALLBACK_REVOKE:
  		node->ae.avd.allowed &= ~perms;
  		break;
  	case AVC_CALLBACK_AUDITALLOW_ENABLE:
  		node->ae.avd.auditallow |= perms;
  		break;
  	case AVC_CALLBACK_AUDITALLOW_DISABLE:
  		node->ae.avd.auditallow &= ~perms;
  		break;
  	case AVC_CALLBACK_AUDITDENY_ENABLE:
  		node->ae.avd.auditdeny |= perms;
  		break;
  	case AVC_CALLBACK_AUDITDENY_DISABLE:
  		node->ae.avd.auditdeny &= ~perms;
  		break;
  	}
  	avc_node_replace(node, orig);
  out_unlock:
edf3d1aec   Eric Paris   SELinux: code rea...
664
  	spin_unlock_irqrestore(lock, flag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
666
667
668
669
  out:
  	return rc;
  }
  
  /**
008574b11   Eric Paris   SELinux: seperate...
670
   * avc_flush - Flush the cache
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
   */
008574b11   Eric Paris   SELinux: seperate...
672
  static void avc_flush(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
  {
26036651c   Eric Paris   SELinux: convert ...
674
675
  	struct hlist_head *head;
  	struct hlist_node *next;
008574b11   Eric Paris   SELinux: seperate...
676
  	struct avc_node *node;
edf3d1aec   Eric Paris   SELinux: code rea...
677
  	spinlock_t *lock;
008574b11   Eric Paris   SELinux: seperate...
678
679
  	unsigned long flag;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
681
  
  	for (i = 0; i < AVC_CACHE_SLOTS; i++) {
edf3d1aec   Eric Paris   SELinux: code rea...
682
683
684
685
  		head = &avc_cache.slots[i];
  		lock = &avc_cache.slots_lock[i];
  
  		spin_lock_irqsave(lock, flag);
618442509   Paul E. McKenney   SELinux fixups ne...
686
687
688
689
690
  		/*
  		 * With preemptable RCU, the outer spinlock does not
  		 * prevent RCU grace periods from ending.
  		 */
  		rcu_read_lock();
26036651c   Eric Paris   SELinux: convert ...
691
  		hlist_for_each_entry(node, next, head, list)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
  			avc_node_delete(node);
618442509   Paul E. McKenney   SELinux fixups ne...
693
  		rcu_read_unlock();
edf3d1aec   Eric Paris   SELinux: code rea...
694
  		spin_unlock_irqrestore(lock, flag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
  	}
008574b11   Eric Paris   SELinux: seperate...
696
697
698
699
700
701
702
703
704
705
706
707
  }
  
  /**
   * avc_ss_reset - Flush the cache and revalidate migrated permissions.
   * @seqno: policy sequence number
   */
  int avc_ss_reset(u32 seqno)
  {
  	struct avc_callback_node *c;
  	int rc = 0, tmprc;
  
  	avc_flush();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
709
710
  
  	for (c = avc_callbacks; c; c = c->next) {
  		if (c->events & AVC_CALLBACK_RESET) {
376bd9cb3   Darrel Goeddel   [PATCH] support f...
711
  			tmprc = c->callback(AVC_CALLBACK_RESET,
95fff33b8   Eric Paris   SELinux: one litt...
712
  					    0, 0, 0, 0, NULL);
376bd9cb3   Darrel Goeddel   [PATCH] support f...
713
714
715
716
  			/* save the first error encountered for the return
  			   value and continue processing the callbacks */
  			if (!rc)
  				rc = tmprc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
718
719
720
  		}
  	}
  
  	avc_latest_notif_update(seqno, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
722
723
724
725
726
727
728
729
  	return rc;
  }
  
  /**
   * avc_has_perm_noaudit - Check permissions but perform no auditing.
   * @ssid: source security identifier
   * @tsid: target security identifier
   * @tclass: target security class
   * @requested: requested permissions, interpreted based on @tclass
2c3c05dbc   Stephen Smalley   SELinux: allow pr...
730
   * @flags:  AVC_STRICT or 0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
732
733
734
735
736
737
738
739
740
741
742
743
744
   * @avd: access vector decisions
   *
   * Check the AVC to determine whether the @requested permissions are granted
   * for the SID pair (@ssid, @tsid), interpreting the permissions
   * based on @tclass, and call the security server on a cache miss to obtain
   * a new decision and add it to the cache.  Return a copy of the decisions
   * in @avd.  Return %0 if all @requested permissions are granted,
   * -%EACCES if any permissions are denied, or another -errno upon
   * other errors.  This function is typically called by avc_has_perm(),
   * but may also be called directly to separate permission checking from
   * auditing, e.g. in cases where a lock must be held for the check but
   * should be released for the auditing.
   */
  int avc_has_perm_noaudit(u32 ssid, u32 tsid,
2c3c05dbc   Stephen Smalley   SELinux: allow pr...
745
746
  			 u16 tclass, u32 requested,
  			 unsigned flags,
21193dcd1   Eric Paris   SELinux: more car...
747
  			 struct av_decision *in_avd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
749
  {
  	struct avc_node *node;
21193dcd1   Eric Paris   SELinux: more car...
750
  	struct av_decision avd_entry, *avd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
752
  	int rc = 0;
  	u32 denied;
eda4f69ca   Eric Paris   SELinux: requesti...
753
  	BUG_ON(!requested);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754
  	rcu_read_lock();
f1c6381a6   Eric Paris   SELinux: remove u...
755
  	node = avc_lookup(ssid, tsid, tclass);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
756
757
  	if (!node) {
  		rcu_read_unlock();
21193dcd1   Eric Paris   SELinux: more car...
758
759
760
761
762
  
  		if (in_avd)
  			avd = in_avd;
  		else
  			avd = &avd_entry;
19439d05b   Stephen Smalley   selinux: change t...
763
  		security_compute_av(ssid, tsid, tclass, avd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
  		rcu_read_lock();
21193dcd1   Eric Paris   SELinux: more car...
765
766
767
768
769
  		node = avc_insert(ssid, tsid, tclass, avd);
  	} else {
  		if (in_avd)
  			memcpy(in_avd, &node->ae.avd, sizeof(*in_avd));
  		avd = &node->ae.avd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
  	}
21193dcd1   Eric Paris   SELinux: more car...
771
  	denied = requested & ~(avd->allowed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772

eda4f69ca   Eric Paris   SELinux: requesti...
773
  	if (denied) {
64dbf0747   Eric Paris   selinux: introduc...
774
  		if (flags & AVC_STRICT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
  			rc = -EACCES;
8a6f83afd   KaiGai Kohei   Permissive domain...
776
  		else if (!selinux_enforcing || (avd->flags & AVD_FLAGS_PERMISSIVE))
64dbf0747   Eric Paris   selinux: introduc...
777
  			avc_update_node(AVC_CALLBACK_GRANT, requested, ssid,
21193dcd1   Eric Paris   SELinux: more car...
778
  					tsid, tclass, avd->seqno);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
  		else
64dbf0747   Eric Paris   selinux: introduc...
780
  			rc = -EACCES;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
782
783
  	}
  
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
785
786
787
788
789
790
791
792
793
  	return rc;
  }
  
  /**
   * avc_has_perm - Check permissions and perform any appropriate auditing.
   * @ssid: source security identifier
   * @tsid: target security identifier
   * @tclass: target security class
   * @requested: requested permissions, interpreted based on @tclass
   * @auditdata: auxiliary audit data
0dc1ba24f   Eric Paris   SELINUX: Make sel...
794
   * @flags: VFS walk flags
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
796
797
798
799
800
801
802
803
   *
   * Check the AVC to determine whether the @requested permissions are granted
   * for the SID pair (@ssid, @tsid), interpreting the permissions
   * based on @tclass, and call the security server on a cache miss to obtain
   * a new decision and add it to the cache.  Audit the granting or denial of
   * permissions in accordance with the policy.  Return %0 if all @requested
   * permissions are granted, -%EACCES if any permissions are denied, or
   * another -errno upon other errors.
   */
0dc1ba24f   Eric Paris   SELINUX: Make sel...
804
805
806
  int avc_has_perm_flags(u32 ssid, u32 tsid, u16 tclass,
  		       u32 requested, struct common_audit_data *auditdata,
  		       unsigned flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
808
  {
  	struct av_decision avd;
0dc1ba24f   Eric Paris   SELINUX: Make sel...
809
  	int rc, rc2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810

2c3c05dbc   Stephen Smalley   SELinux: allow pr...
811
  	rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd);
0dc1ba24f   Eric Paris   SELINUX: Make sel...
812
813
814
815
816
  
  	rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata,
  			flags);
  	if (rc2)
  		return rc2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
818
  	return rc;
  }
788e7dd4c   Yuichi Nakamura   SELinux: Improve ...
819
820
821
822
823
  
  u32 avc_policy_seqno(void)
  {
  	return avc_cache.latest_notif;
  }
89c86576e   Thomas Liu   selinux: clean up...
824
825
826
  
  void avc_disable(void)
  {
5224ee086   Eric Paris   SELinux: do not d...
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
  	/*
  	 * If you are looking at this because you have realized that we are
  	 * not destroying the avc_node_cachep it might be easy to fix, but
  	 * I don't know the memory barrier semantics well enough to know.  It's
  	 * possible that some other task dereferenced security_ops when
  	 * it still pointed to selinux operations.  If that is the case it's
  	 * possible that it is about to use the avc and is about to need the
  	 * avc_node_cachep.  I know I could wrap the security.c security_ops call
  	 * in an rcu_lock, but seriously, it's not worth it.  Instead I just flush
  	 * the cache and get that memory back.
  	 */
  	if (avc_node_cachep) {
  		avc_flush();
  		/* kmem_cache_destroy(avc_node_cachep); */
  	}
89c86576e   Thomas Liu   selinux: clean up...
842
  }