Blame view

security/selinux/avc.c 21.6 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
044aea9b8   Linus Torvalds   selinux: de-crapi...
41
  #define avc_cache_stats_incr(field)	this_cpu_inc(avc_cache_stats.field)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
46
47
48
49
50
  #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
51
52
53
54
  };
  
  struct avc_node {
  	struct avc_entry	ae;
26036651c   Eric Paris   SELinux: convert ...
55
  	struct hlist_node	list; /* anchored in avc_cache->slots[i] */
95fff33b8   Eric Paris   SELinux: one litt...
56
  	struct rcu_head		rhead;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
  };
  
  struct avc_cache {
26036651c   Eric Paris   SELinux: convert ...
60
  	struct hlist_head	slots[AVC_CACHE_SLOTS]; /* head for avc_node->list */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
63
64
65
66
67
68
  	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...
69
70
  			 u16 tclass, u32 perms,
  			 u32 *out_retained);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
  	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...
88
  static struct kmem_cache *avc_node_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
91
92
93
94
95
96
97
98
99
  
  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...
100
  static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
  {
c6d3aaa4e   Stephen Smalley   selinux: dynamic ...
102
103
  	const char **perms;
  	int i, perm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
106
107
108
  
  	if (av == 0) {
  		audit_log_format(ab, " null");
  		return;
  	}
c6d3aaa4e   Stephen Smalley   selinux: dynamic ...
109
  	perms = secclass_map[tclass-1].perms;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
  
  	audit_log_format(ab, " {");
  	i = 0;
  	perm = 1;
c6d3aaa4e   Stephen Smalley   selinux: dynamic ...
114
  	while (i < (sizeof(av) * 8)) {
0bce95279   Eric Paris   SELinux: print de...
115
  		if ((perm & av) && perms[i]) {
c6d3aaa4e   Stephen Smalley   selinux: dynamic ...
116
  			audit_log_format(ab, " %s", perms[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
118
119
120
121
  			av &= ~perm;
  		}
  		i++;
  		perm <<= 1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
  	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...
139
  	rc = security_sid_to_context(ssid, &scontext, &scontext_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
143
144
145
146
147
148
149
150
151
152
153
  	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...
154

c6d3aaa4e   Stephen Smalley   selinux: dynamic ...
155
156
  	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
157
158
159
160
161
162
163
164
165
166
167
168
  }
  
  /**
   * 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 ...
169
  		INIT_HLIST_HEAD(&avc_cache.slots[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
172
173
174
175
  		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...
176
  					     0, SLAB_PANIC, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177

9ad9ad385   David Woodhouse   AUDIT: Wait for b...
178
179
  	audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
183
184
185
  }
  
  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 ...
186
  	struct hlist_head *head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
188
189
190
191
192
  
  	rcu_read_lock();
  
  	slots_used = 0;
  	max_chain_len = 0;
  	for (i = 0; i < AVC_CACHE_SLOTS; i++) {
edf3d1aec   Eric Paris   SELinux: code rea...
193
  		head = &avc_cache.slots[i];
26036651c   Eric Paris   SELinux: convert ...
194
195
  		if (!hlist_empty(head)) {
  			struct hlist_node *next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
197
  			slots_used++;
  			chain_len = 0;
26036651c   Eric Paris   SELinux: convert ...
198
  			hlist_for_each_entry_rcu(node, next, head, list)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
  				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 ...
225
  	hlist_del_rcu(&node->list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
230
231
232
233
234
235
236
237
238
  	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 ...
239
  	hlist_replace_rcu(&old->list, &new->list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
242
243
244
245
246
247
248
  	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 ...
249
250
  	struct hlist_head *head;
  	struct hlist_node *next;
edf3d1aec   Eric Paris   SELinux: code rea...
251
  	spinlock_t *lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252

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

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

257313b2a   Linus Torvalds   selinux: avoid un...
342
343
  	avc_cache_stats_incr(misses);
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
348
349
350
351
352
353
354
  }
  
  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...
355
356
  			printk(KERN_WARNING "SELinux: avc:  seqno %d < latest_notif %d
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
  			       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...
374
   * @avd: resulting av decision
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
376
377
378
379
380
   *
   * 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...
381
   * sequence number @avd->seqno is not less than the latest
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
383
384
385
   * 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...
386
  static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
389
390
  {
  	struct avc_node *pos, *node = NULL;
  	int hvalue;
  	unsigned long flag;
21193dcd1   Eric Paris   SELinux: more car...
391
  	if (avc_latest_notif_update(avd->seqno, 1))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
393
394
395
  		goto out;
  
  	node = avc_alloc_node();
  	if (node) {
26036651c   Eric Paris   SELinux: convert ...
396
397
  		struct hlist_head *head;
  		struct hlist_node *next;
edf3d1aec   Eric Paris   SELinux: code rea...
398
  		spinlock_t *lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
  		hvalue = avc_hash(ssid, tsid, tclass);
21193dcd1   Eric Paris   SELinux: more car...
400
  		avc_node_populate(node, ssid, tsid, tclass, avd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401

edf3d1aec   Eric Paris   SELinux: code rea...
402
403
404
405
  		head = &avc_cache.slots[hvalue];
  		lock = &avc_cache.slots_lock[hvalue];
  
  		spin_lock_irqsave(lock, flag);
26036651c   Eric Paris   SELinux: convert ...
406
  		hlist_for_each_entry(pos, next, head, list) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
  			if (pos->ae.ssid == ssid &&
  			    pos->ae.tsid == tsid &&
  			    pos->ae.tclass == tclass) {
95fff33b8   Eric Paris   SELinux: one litt...
410
  				avc_node_replace(node, pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
  				goto found;
  			}
  		}
26036651c   Eric Paris   SELinux: convert ...
414
  		hlist_add_head_rcu(&node->list, head);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
  found:
edf3d1aec   Eric Paris   SELinux: code rea...
416
  		spin_unlock_irqrestore(lock, flag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
418
419
420
  	}
  out:
  	return node;
  }
2bf496903   Thomas Liu   SELinux: Convert ...
421
422
423
424
425
426
427
  /**
   * 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
428
  {
2bf496903   Thomas Liu   SELinux: Convert ...
429
430
431
432
433
434
  	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
435
  }
2bf496903   Thomas Liu   SELinux: Convert ...
436
437
438
439
440
441
442
  /**
   * 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
443
  {
2bf496903   Thomas Liu   SELinux: Convert ...
444
445
446
447
448
  	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
449
450
451
452
453
454
455
456
457
458
459
  }
  
  /**
   * 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
9ade0cf44   Eric Paris   SELINUX: Make sel...
460
   * @flags: VFS walk flags
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
463
464
465
466
467
468
469
470
   *
   * 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.
   */
9ade0cf44   Eric Paris   SELINUX: Make sel...
471
  int avc_audit(u32 ssid, u32 tsid,
95fff33b8   Eric Paris   SELinux: one litt...
472
  	       u16 tclass, u32 requested,
9ade0cf44   Eric Paris   SELINUX: Make sel...
473
474
  	       struct av_decision *avd, int result, struct common_audit_data *a,
  	       unsigned flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
  {
2bf496903   Thomas Liu   SELinux: Convert ...
476
  	struct common_audit_data stack_data;
be940d627   James Morris   Revert "SELinux: ...
477
  	u32 denied, audited;
be940d627   James Morris   Revert "SELinux: ...
478
  	denied = requested & ~avd->allowed;
b782e0a68   Eric Paris   SELinux: special ...
479
  	if (denied) {
b6cac5a30   Stephen Smalley   selinux: Only aud...
480
  		audited = denied & avd->auditdeny;
b782e0a68   Eric Paris   SELinux: special ...
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
  		/*
  		 * 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: ...
502
  		audited = denied = requested;
b6cac5a30   Stephen Smalley   selinux: Only aud...
503
504
505
  	else
  		audited = requested & avd->auditallow;
  	if (!audited)
9ade0cf44   Eric Paris   SELINUX: Make sel...
506
  		return 0;
2bf496903   Thomas Liu   SELinux: Convert ...
507
508
  	if (!a) {
  		a = &stack_data;
cb84aa9b4   Eric Paris   LSM Audit: rename...
509
  		COMMON_AUDIT_DATA_INIT(a, NONE);
be940d627   James Morris   Revert "SELinux: ...
510
  	}
9ade0cf44   Eric Paris   SELINUX: Make sel...
511
512
513
514
515
516
517
518
  
  	/*
  	 * 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.
  	 */
f48b73998   Eric Paris   LSM: split LSM_AU...
519
  	if ((a->type == LSM_AUDIT_DATA_INODE) &&
cf1dd1dae   Al Viro   selinux: don't tr...
520
  	    (flags & MAY_NOT_BLOCK))
9ade0cf44   Eric Paris   SELINUX: Make sel...
521
  		return -ECHILD;
2bf496903   Thomas Liu   SELinux: Convert ...
522
523
524
525
526
527
528
529
530
  	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);
9ade0cf44   Eric Paris   SELINUX: Make sel...
531
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
533
534
535
536
537
538
539
540
541
542
543
  }
  
  /**
   * 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...
544
   * related to the SID pair (@ssid, @tsid) 
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
546
547
548
549
   * 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...
550
551
552
553
  				     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
554
555
556
557
558
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
  {
  	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...
585
   * @seqno : sequence number when decision was made
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
587
588
   *
   * 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...
589
   * otherwise, this function updates the AVC entry. The original AVC-entry object
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
591
   * will release later by RCU.
   */
a5dda6833   Eric Paris   SELinux: check se...
592
593
  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
594
595
596
597
  {
  	int hvalue, rc = 0;
  	unsigned long flag;
  	struct avc_node *pos, *node, *orig = NULL;
26036651c   Eric Paris   SELinux: convert ...
598
599
  	struct hlist_head *head;
  	struct hlist_node *next;
edf3d1aec   Eric Paris   SELinux: code rea...
600
  	spinlock_t *lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
602
603
604
605
606
607
608
609
  
  	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
610

edf3d1aec   Eric Paris   SELinux: code rea...
611
612
613
614
  	head = &avc_cache.slots[hvalue];
  	lock = &avc_cache.slots_lock[hvalue];
  
  	spin_lock_irqsave(lock, flag);
26036651c   Eric Paris   SELinux: convert ...
615
  	hlist_for_each_entry(pos, next, head, list) {
95fff33b8   Eric Paris   SELinux: one litt...
616
617
  		if (ssid == pos->ae.ssid &&
  		    tsid == pos->ae.tsid &&
a5dda6833   Eric Paris   SELinux: check se...
618
619
  		    tclass == pos->ae.tclass &&
  		    seqno == pos->ae.avd.seqno){
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
621
622
623
624
625
626
627
628
629
630
631
632
633
  			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...
634
  	avc_node_populate(node, ssid, tsid, tclass, &orig->ae.avd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
  
  	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...
659
  	spin_unlock_irqrestore(lock, flag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
661
662
663
664
  out:
  	return rc;
  }
  
  /**
008574b11   Eric Paris   SELinux: seperate...
665
   * avc_flush - Flush the cache
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666
   */
008574b11   Eric Paris   SELinux: seperate...
667
  static void avc_flush(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
  {
26036651c   Eric Paris   SELinux: convert ...
669
670
  	struct hlist_head *head;
  	struct hlist_node *next;
008574b11   Eric Paris   SELinux: seperate...
671
  	struct avc_node *node;
edf3d1aec   Eric Paris   SELinux: code rea...
672
  	spinlock_t *lock;
008574b11   Eric Paris   SELinux: seperate...
673
674
  	unsigned long flag;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
676
  
  	for (i = 0; i < AVC_CACHE_SLOTS; i++) {
edf3d1aec   Eric Paris   SELinux: code rea...
677
678
679
680
  		head = &avc_cache.slots[i];
  		lock = &avc_cache.slots_lock[i];
  
  		spin_lock_irqsave(lock, flag);
618442509   Paul E. McKenney   SELinux fixups ne...
681
682
683
684
685
  		/*
  		 * With preemptable RCU, the outer spinlock does not
  		 * prevent RCU grace periods from ending.
  		 */
  		rcu_read_lock();
26036651c   Eric Paris   SELinux: convert ...
686
  		hlist_for_each_entry(node, next, head, list)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
  			avc_node_delete(node);
618442509   Paul E. McKenney   SELinux fixups ne...
688
  		rcu_read_unlock();
edf3d1aec   Eric Paris   SELinux: code rea...
689
  		spin_unlock_irqrestore(lock, flag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690
  	}
008574b11   Eric Paris   SELinux: seperate...
691
692
693
694
695
696
697
698
699
700
701
702
  }
  
  /**
   * 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
703
704
705
  
  	for (c = avc_callbacks; c; c = c->next) {
  		if (c->events & AVC_CALLBACK_RESET) {
376bd9cb3   Darrel Goeddel   [PATCH] support f...
706
  			tmprc = c->callback(AVC_CALLBACK_RESET,
95fff33b8   Eric Paris   SELinux: one litt...
707
  					    0, 0, 0, 0, NULL);
376bd9cb3   Darrel Goeddel   [PATCH] support f...
708
709
710
711
  			/* 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
712
713
714
715
  		}
  	}
  
  	avc_latest_notif_update(seqno, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
716
717
718
719
720
721
722
723
724
  	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...
725
   * @flags:  AVC_STRICT or 0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726
727
728
729
730
731
732
733
734
735
736
737
738
739
   * @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...
740
741
  			 u16 tclass, u32 requested,
  			 unsigned flags,
f01e1af44   Linus Torvalds   selinux: don't pa...
742
  			 struct av_decision *avd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
744
  {
  	struct avc_node *node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745
746
  	int rc = 0;
  	u32 denied;
eda4f69ca   Eric Paris   SELinux: requesti...
747
  	BUG_ON(!requested);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
  	rcu_read_lock();
f1c6381a6   Eric Paris   SELinux: remove u...
749
  	node = avc_lookup(ssid, tsid, tclass);
257313b2a   Linus Torvalds   selinux: avoid un...
750
  	if (unlikely(!node)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
  		rcu_read_unlock();
19439d05b   Stephen Smalley   selinux: change t...
752
  		security_compute_av(ssid, tsid, tclass, avd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
  		rcu_read_lock();
21193dcd1   Eric Paris   SELinux: more car...
754
755
  		node = avc_insert(ssid, tsid, tclass, avd);
  	} else {
f01e1af44   Linus Torvalds   selinux: don't pa...
756
  		memcpy(avd, &node->ae.avd, sizeof(*avd));
21193dcd1   Eric Paris   SELinux: more car...
757
  		avd = &node->ae.avd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
  	}
21193dcd1   Eric Paris   SELinux: more car...
759
  	denied = requested & ~(avd->allowed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760

eda4f69ca   Eric Paris   SELinux: requesti...
761
  	if (denied) {
64dbf0747   Eric Paris   selinux: introduc...
762
  		if (flags & AVC_STRICT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
  			rc = -EACCES;
8a6f83afd   KaiGai Kohei   Permissive domain...
764
  		else if (!selinux_enforcing || (avd->flags & AVD_FLAGS_PERMISSIVE))
64dbf0747   Eric Paris   selinux: introduc...
765
  			avc_update_node(AVC_CALLBACK_GRANT, requested, ssid,
21193dcd1   Eric Paris   SELinux: more car...
766
  					tsid, tclass, avd->seqno);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
  		else
64dbf0747   Eric Paris   selinux: introduc...
768
  			rc = -EACCES;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
770
771
  	}
  
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
773
774
775
776
777
778
779
780
781
  	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
9ade0cf44   Eric Paris   SELINUX: Make sel...
782
   * @flags: VFS walk flags
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
784
785
786
787
788
789
790
791
   *
   * 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.
   */
9ade0cf44   Eric Paris   SELINUX: Make sel...
792
793
794
  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
795
796
  {
  	struct av_decision avd;
9ade0cf44   Eric Paris   SELINUX: Make sel...
797
  	int rc, rc2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798

2c3c05dbc   Stephen Smalley   SELinux: allow pr...
799
  	rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd);
9ade0cf44   Eric Paris   SELINUX: Make sel...
800
801
802
803
804
  
  	rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata,
  			flags);
  	if (rc2)
  		return rc2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
806
  	return rc;
  }
788e7dd4c   Yuichi Nakamura   SELinux: Improve ...
807
808
809
810
811
  
  u32 avc_policy_seqno(void)
  {
  	return avc_cache.latest_notif;
  }
89c86576e   Thomas Liu   selinux: clean up...
812
813
814
  
  void avc_disable(void)
  {
5224ee086   Eric Paris   SELinux: do not d...
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
  	/*
  	 * 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...
830
  }