1/*
2 * Implementation of the userspace access vector cache (AVC).
3 *
4 * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil>
5 *
6 * Derived from the kernel AVC implementation by
7 * Stephen Smalley <sds@epoch.ncsc.mil> and
8 * James Morris <jmorris@redhat.com>.
9 */
10#include <selinux/avc.h>
11#include "selinux_internal.h"
12#include "avc_sidtab.h"
13#include "avc_internal.h"
14
15#define AVC_CACHE_SLOTS		512
16#define AVC_CACHE_MAXNODES	410
17
18struct avc_entry {
19	security_id_t ssid;
20	security_id_t tsid;
21	security_class_t tclass;
22	struct av_decision avd;
23	security_id_t	create_sid;
24	int used;		/* used recently */
25};
26
27struct avc_node {
28	struct avc_entry ae;
29	struct avc_node *next;
30};
31
32struct avc_cache {
33	struct avc_node *slots[AVC_CACHE_SLOTS];
34	uint32_t lru_hint;	/* LRU hint for reclaim scan */
35	uint32_t active_nodes;
36	uint32_t latest_notif;	/* latest revocation notification */
37};
38
39struct avc_callback_node {
40	int (*callback) (uint32_t event, security_id_t ssid,
41			 security_id_t tsid,
42			 security_class_t tclass, access_vector_t perms,
43			 access_vector_t * out_retained);
44	uint32_t events;
45	security_id_t ssid;
46	security_id_t tsid;
47	security_class_t tclass;
48	access_vector_t perms;
49	struct avc_callback_node *next;
50};
51
52static void *avc_netlink_thread = NULL;
53static void *avc_lock = NULL;
54static void *avc_log_lock = NULL;
55static struct avc_node *avc_node_freelist = NULL;
56static struct avc_cache avc_cache;
57static char *avc_audit_buf = NULL;
58static struct avc_cache_stats cache_stats;
59static struct avc_callback_node *avc_callbacks = NULL;
60static struct sidtab avc_sidtab;
61
62static inline int avc_hash(security_id_t ssid,
63			   security_id_t tsid, security_class_t tclass)
64{
65	return ((uintptr_t) ssid ^ ((uintptr_t) tsid << 2) ^ tclass)
66	    & (AVC_CACHE_SLOTS - 1);
67}
68
69int avc_context_to_sid(const char * ctx, security_id_t * sid)
70{
71	int rc;
72	avc_get_lock(avc_lock);
73	rc = sidtab_context_to_sid(&avc_sidtab, ctx, sid);
74	avc_release_lock(avc_lock);
75	return rc;
76}
77
78int avc_sid_to_context(security_id_t sid, char ** ctx)
79{
80	int rc;
81	*ctx = NULL;
82	avc_get_lock(avc_lock);
83	*ctx = strdup(sid->ctx);	/* caller must free via freecon */
84	rc = *ctx ? 0 : -1;
85	avc_release_lock(avc_lock);
86	return rc;
87}
88
89int avc_get_initial_sid(const char * name, security_id_t * sid)
90{
91	int rc;
92	char * con;
93
94	rc = security_get_initial_context(name, &con);
95	if (rc < 0)
96		return rc;
97	rc = avc_context_to_sid(con, sid);
98
99	freecon(con);
100
101	return rc;
102}
103
104int avc_open(struct selinux_opt *opts, unsigned nopts)
105{
106	avc_setenforce = 0;
107
108	while (nopts--)
109		switch(opts[nopts].type) {
110		case AVC_OPT_SETENFORCE:
111			avc_setenforce = 1;
112			avc_enforcing = !!opts[nopts].value;
113			break;
114		}
115
116	return avc_init("avc", NULL, NULL, NULL, NULL);
117}
118
119int avc_init(const char *prefix,
120	     const struct avc_memory_callback *mem_cb,
121	     const struct avc_log_callback *log_cb,
122	     const struct avc_thread_callback *thread_cb,
123	     const struct avc_lock_callback *lock_cb)
124{
125	struct avc_node *new;
126	int i, rc = 0;
127
128	if (prefix)
129		strncpy(avc_prefix, prefix, AVC_PREFIX_SIZE - 1);
130
131	set_callbacks(mem_cb, log_cb, thread_cb, lock_cb);
132
133	avc_lock = avc_alloc_lock();
134	avc_log_lock = avc_alloc_lock();
135
136	memset(&cache_stats, 0, sizeof(cache_stats));
137
138	for (i = 0; i < AVC_CACHE_SLOTS; i++)
139		avc_cache.slots[i] = 0;
140	avc_cache.lru_hint = 0;
141	avc_cache.active_nodes = 0;
142	avc_cache.latest_notif = 0;
143
144	rc = sidtab_init(&avc_sidtab);
145	if (rc) {
146		avc_log(SELINUX_ERROR,
147			"%s:  unable to initialize SID table\n",
148			avc_prefix);
149		goto out;
150	}
151
152	avc_audit_buf = (char *)avc_malloc(AVC_AUDIT_BUFSIZE);
153	if (!avc_audit_buf) {
154		avc_log(SELINUX_ERROR,
155			"%s:  unable to allocate audit buffer\n",
156			avc_prefix);
157		rc = -1;
158		goto out;
159	}
160
161	for (i = 0; i < AVC_CACHE_MAXNODES; i++) {
162		new = avc_malloc(sizeof(*new));
163		if (!new) {
164			avc_log(SELINUX_WARNING,
165				"%s:  warning: only got %d av entries\n",
166				avc_prefix, i);
167			break;
168		}
169		memset(new, 0, sizeof(*new));
170		new->next = avc_node_freelist;
171		avc_node_freelist = new;
172	}
173
174	if (!avc_setenforce) {
175		rc = security_getenforce();
176		if (rc < 0) {
177			avc_log(SELINUX_ERROR,
178				"%s:  could not determine enforcing mode: %s\n",
179				avc_prefix,
180				strerror(errno));
181			goto out;
182		}
183		avc_enforcing = rc;
184	}
185
186	rc = avc_netlink_open(0);
187	if (rc < 0) {
188		avc_log(SELINUX_ERROR,
189			"%s:  can't open netlink socket: %d (%s)\n",
190			avc_prefix, errno, strerror(errno));
191		goto out;
192	}
193	if (avc_using_threads) {
194		avc_netlink_thread = avc_create_thread(&avc_netlink_loop);
195		avc_netlink_trouble = 0;
196	}
197	avc_running = 1;
198      out:
199	return rc;
200}
201
202void avc_cache_stats(struct avc_cache_stats *p)
203{
204	memcpy(p, &cache_stats, sizeof(cache_stats));
205}
206
207void avc_sid_stats(void)
208{
209	avc_get_lock(avc_log_lock);
210	avc_get_lock(avc_lock);
211	sidtab_sid_stats(&avc_sidtab, avc_audit_buf, AVC_AUDIT_BUFSIZE);
212	avc_release_lock(avc_lock);
213	avc_log(SELINUX_INFO, "%s", avc_audit_buf);
214	avc_release_lock(avc_log_lock);
215}
216
217void avc_av_stats(void)
218{
219	int i, chain_len, max_chain_len, slots_used;
220	struct avc_node *node;
221
222	avc_get_lock(avc_lock);
223
224	slots_used = 0;
225	max_chain_len = 0;
226	for (i = 0; i < AVC_CACHE_SLOTS; i++) {
227		node = avc_cache.slots[i];
228		if (node) {
229			slots_used++;
230			chain_len = 0;
231			while (node) {
232				chain_len++;
233				node = node->next;
234			}
235			if (chain_len > max_chain_len)
236				max_chain_len = chain_len;
237		}
238	}
239
240	avc_release_lock(avc_lock);
241
242	avc_log(SELINUX_INFO, "%s:  %d AV entries and %d/%d buckets used, "
243		"longest chain length %d\n", avc_prefix,
244		avc_cache.active_nodes,
245		slots_used, AVC_CACHE_SLOTS, max_chain_len);
246}
247
248hidden_def(avc_av_stats)
249
250static inline struct avc_node *avc_reclaim_node(void)
251{
252	struct avc_node *prev, *cur;
253	int try;
254	uint32_t hvalue;
255
256	hvalue = avc_cache.lru_hint;
257	for (try = 0; try < 2; try++) {
258		do {
259			prev = NULL;
260			cur = avc_cache.slots[hvalue];
261			while (cur) {
262				if (!cur->ae.used)
263					goto found;
264
265				cur->ae.used = 0;
266
267				prev = cur;
268				cur = cur->next;
269			}
270			hvalue = (hvalue + 1) & (AVC_CACHE_SLOTS - 1);
271		} while (hvalue != avc_cache.lru_hint);
272	}
273
274	errno = ENOMEM;		/* this was a panic in the kernel... */
275	return NULL;
276
277      found:
278	avc_cache.lru_hint = hvalue;
279
280	if (prev == NULL)
281		avc_cache.slots[hvalue] = cur->next;
282	else
283		prev->next = cur->next;
284
285	return cur;
286}
287
288static inline void avc_clear_avc_entry(struct avc_entry *ae)
289{
290	memset(ae, 0, sizeof *ae);
291}
292
293static inline struct avc_node *avc_claim_node(security_id_t ssid,
294					      security_id_t tsid,
295					      security_class_t tclass)
296{
297	struct avc_node *new;
298	int hvalue;
299
300	if (!avc_node_freelist)
301		avc_cleanup();
302
303	if (avc_node_freelist) {
304		new = avc_node_freelist;
305		avc_node_freelist = avc_node_freelist->next;
306		avc_cache.active_nodes++;
307	} else {
308		new = avc_reclaim_node();
309		if (!new)
310			goto out;
311	}
312
313	hvalue = avc_hash(ssid, tsid, tclass);
314	avc_clear_avc_entry(&new->ae);
315	new->ae.used = 1;
316	new->ae.ssid = ssid;
317	new->ae.tsid = tsid;
318	new->ae.tclass = tclass;
319	new->next = avc_cache.slots[hvalue];
320	avc_cache.slots[hvalue] = new;
321
322      out:
323	return new;
324}
325
326static inline struct avc_node *avc_search_node(security_id_t ssid,
327					       security_id_t tsid,
328					       security_class_t tclass,
329					       int *probes)
330{
331	struct avc_node *cur;
332	int hvalue;
333	int tprobes = 1;
334
335	hvalue = avc_hash(ssid, tsid, tclass);
336	cur = avc_cache.slots[hvalue];
337	while (cur != NULL &&
338	       (ssid != cur->ae.ssid ||
339		tclass != cur->ae.tclass || tsid != cur->ae.tsid)) {
340		tprobes++;
341		cur = cur->next;
342	}
343
344	if (cur == NULL) {
345		/* cache miss */
346		goto out;
347	}
348
349	/* cache hit */
350	if (probes)
351		*probes = tprobes;
352
353	cur->ae.used = 1;
354
355      out:
356	return cur;
357}
358
359/**
360 * avc_lookup - Look up an AVC entry.
361 * @ssid: source security identifier
362 * @tsid: target security identifier
363 * @tclass: target security class
364 * @requested: requested permissions, interpreted based on @tclass
365 * @aeref:  AVC entry reference
366 *
367 * Look up an AVC entry that is valid for the
368 * @requested permissions between the SID pair
369 * (@ssid, @tsid), interpreting the permissions
370 * based on @tclass.  If a valid AVC entry exists,
371 * then this function updates @aeref to refer to the
372 * entry and returns %0.  Otherwise, -1 is returned.
373 */
374static int avc_lookup(security_id_t ssid, security_id_t tsid,
375		      security_class_t tclass,
376		      access_vector_t requested, struct avc_entry_ref *aeref)
377{
378	struct avc_node *node;
379	int probes, rc = 0;
380
381	avc_cache_stats_incr(cav_lookups);
382	node = avc_search_node(ssid, tsid, tclass, &probes);
383
384	if (node && ((node->ae.avd.decided & requested) == requested)) {
385		avc_cache_stats_incr(cav_hits);
386		avc_cache_stats_add(cav_probes, probes);
387		aeref->ae = &node->ae;
388		goto out;
389	}
390
391	avc_cache_stats_incr(cav_misses);
392	rc = -1;
393      out:
394	return rc;
395}
396
397/**
398 * avc_insert - Insert an AVC entry.
399 * @ssid: source security identifier
400 * @tsid: target security identifier
401 * @tclass: target security class
402 * @ae: AVC entry
403 * @aeref:  AVC entry reference
404 *
405 * Insert an AVC entry for the SID pair
406 * (@ssid, @tsid) and class @tclass.
407 * The access vectors and the sequence number are
408 * normally provided by the security server in
409 * response to a security_compute_av() call.  If the
410 * sequence number @ae->avd.seqno is not less than the latest
411 * revocation notification, then the function copies
412 * the access vectors into a cache entry, updates
413 * @aeref to refer to the entry, and returns %0.
414 * Otherwise, this function returns -%1 with @errno set to %EAGAIN.
415 */
416static int avc_insert(security_id_t ssid, security_id_t tsid,
417		      security_class_t tclass,
418		      struct avc_entry *ae, struct avc_entry_ref *aeref)
419{
420	struct avc_node *node;
421	int rc = 0;
422
423	if (ae->avd.seqno < avc_cache.latest_notif) {
424		avc_log(SELINUX_WARNING,
425			"%s:  seqno %d < latest_notif %d\n", avc_prefix,
426			ae->avd.seqno, avc_cache.latest_notif);
427		errno = EAGAIN;
428		rc = -1;
429		goto out;
430	}
431
432	node = avc_claim_node(ssid, tsid, tclass);
433	if (!node) {
434		rc = -1;
435		goto out;
436	}
437
438	memcpy(&node->ae.avd, &ae->avd, sizeof ae->avd);
439	aeref->ae = &node->ae;
440      out:
441	return rc;
442}
443
444void avc_cleanup(void)
445{
446}
447
448hidden_def(avc_cleanup)
449
450int avc_reset(void)
451{
452	struct avc_callback_node *c;
453	int i, ret, rc = 0, errsave = 0;
454	struct avc_node *node, *tmp;
455	errno = 0;
456
457	if (!avc_running)
458		return 0;
459
460	avc_get_lock(avc_lock);
461
462	for (i = 0; i < AVC_CACHE_SLOTS; i++) {
463		node = avc_cache.slots[i];
464		while (node) {
465			tmp = node;
466			node = node->next;
467			avc_clear_avc_entry(&tmp->ae);
468			tmp->next = avc_node_freelist;
469			avc_node_freelist = tmp;
470			avc_cache.active_nodes--;
471		}
472		avc_cache.slots[i] = 0;
473	}
474	avc_cache.lru_hint = 0;
475
476	avc_release_lock(avc_lock);
477
478	memset(&cache_stats, 0, sizeof(cache_stats));
479
480	for (c = avc_callbacks; c; c = c->next) {
481		if (c->events & AVC_CALLBACK_RESET) {
482			ret = c->callback(AVC_CALLBACK_RESET, 0, 0, 0, 0, 0);
483			if (ret && !rc) {
484				rc = ret;
485				errsave = errno;
486			}
487		}
488	}
489	errno = errsave;
490	return rc;
491}
492
493hidden_def(avc_reset)
494
495void avc_destroy(void)
496{
497	struct avc_callback_node *c;
498	struct avc_node *node, *tmp;
499	int i;
500
501	avc_get_lock(avc_lock);
502
503	if (avc_using_threads)
504		avc_stop_thread(avc_netlink_thread);
505	avc_netlink_close();
506
507	for (i = 0; i < AVC_CACHE_SLOTS; i++) {
508		node = avc_cache.slots[i];
509		while (node) {
510			tmp = node;
511			node = node->next;
512			avc_free(tmp);
513		}
514	}
515	while (avc_node_freelist) {
516		tmp = avc_node_freelist;
517		avc_node_freelist = tmp->next;
518		avc_free(tmp);
519	}
520	avc_release_lock(avc_lock);
521
522	while (avc_callbacks) {
523		c = avc_callbacks;
524		avc_callbacks = c->next;
525		avc_free(c);
526	}
527	sidtab_destroy(&avc_sidtab);
528	avc_free_lock(avc_lock);
529	avc_free_lock(avc_log_lock);
530	avc_free(avc_audit_buf);
531	avc_running = 0;
532}
533
534/* ratelimit stuff put aside for now --EFW */
535#if 0
536/*
537 * Copied from net/core/utils.c:net_ratelimit and modified for
538 * use by the AVC audit facility.
539 */
540#define AVC_MSG_COST	5*HZ
541#define AVC_MSG_BURST	10*5*HZ
542
543/*
544 * This enforces a rate limit: not more than one kernel message
545 * every 5secs to make a denial-of-service attack impossible.
546 */
547static int avc_ratelimit(void)
548{
549	static unsigned long toks = 10 * 5 * HZ;
550	static unsigned long last_msg;
551	static int missed, rc = 0;
552	unsigned long now = jiffies;
553	void *ratelimit_lock = avc_alloc_lock();
554
555	avc_get_lock(ratelimit_lock);
556	toks += now - last_msg;
557	last_msg = now;
558	if (toks > AVC_MSG_BURST)
559		toks = AVC_MSG_BURST;
560	if (toks >= AVC_MSG_COST) {
561		int lost = missed;
562		missed = 0;
563		toks -= AVC_MSG_COST;
564		avc_release_lock(ratelimit_lock);
565		if (lost) {
566			avc_log(SELINUX_WARNING,
567				"%s:  %d messages suppressed.\n", avc_prefix,
568				lost);
569		}
570		rc = 1;
571		goto out;
572	}
573	missed++;
574	avc_release_lock(ratelimit_lock);
575      out:
576	avc_free_lock(ratelimit_lock);
577	return rc;
578}
579
580static inline int check_avc_ratelimit(void)
581{
582	if (avc_enforcing)
583		return avc_ratelimit();
584	else {
585		/* If permissive, then never suppress messages. */
586		return 1;
587	}
588}
589#endif				/* ratelimit stuff */
590
591/**
592 * avc_dump_av - Display an access vector in human-readable form.
593 * @tclass: target security class
594 * @av: access vector
595 */
596static void avc_dump_av(security_class_t tclass, access_vector_t av)
597{
598	const char *permstr;
599	access_vector_t bit = 1;
600
601	if (av == 0) {
602		log_append(avc_audit_buf, " null");
603		return;
604	}
605
606	log_append(avc_audit_buf, " {");
607
608	while (av) {
609		if (av & bit) {
610			permstr = security_av_perm_to_string(tclass, bit);
611			if (!permstr)
612				break;
613			log_append(avc_audit_buf, " %s", permstr);
614			av &= ~bit;
615		}
616		bit <<= 1;
617	}
618
619	if (av)
620		log_append(avc_audit_buf, " 0x%x", av);
621	log_append(avc_audit_buf, " }");
622}
623
624/**
625 * avc_dump_query - Display a SID pair and a class in human-readable form.
626 * @ssid: source security identifier
627 * @tsid: target security identifier
628 * @tclass: target security class
629 */
630static void avc_dump_query(security_id_t ssid, security_id_t tsid,
631			   security_class_t tclass)
632{
633	avc_get_lock(avc_lock);
634
635	log_append(avc_audit_buf, "scontext=%s tcontext=%s",
636		   ssid->ctx, tsid->ctx);
637
638	avc_release_lock(avc_lock);
639	log_append(avc_audit_buf, " tclass=%s",
640		   security_class_to_string(tclass));
641}
642
643void avc_audit(security_id_t ssid, security_id_t tsid,
644	       security_class_t tclass, access_vector_t requested,
645	       struct av_decision *avd, int result, void *a)
646{
647	access_vector_t denied, audited;
648
649	denied = requested & ~avd->allowed;
650	if (denied)
651		audited = denied & avd->auditdeny;
652	else if (!requested || result)
653		audited = denied = requested;
654	else
655		audited = requested & avd->auditallow;
656	if (!audited)
657		return;
658#if 0
659	if (!check_avc_ratelimit())
660		return;
661#endif
662	/* prevent overlapping buffer writes */
663	avc_get_lock(avc_log_lock);
664	snprintf(avc_audit_buf, AVC_AUDIT_BUFSIZE,
665		 "%s:  %s ", avc_prefix, (denied || !requested) ? "denied" : "granted");
666	avc_dump_av(tclass, audited);
667	log_append(avc_audit_buf, " for ");
668
669	/* get any extra information printed by the callback */
670	avc_suppl_audit(a, tclass, avc_audit_buf + strlen(avc_audit_buf),
671			AVC_AUDIT_BUFSIZE - strlen(avc_audit_buf));
672
673	log_append(avc_audit_buf, " ");
674	avc_dump_query(ssid, tsid, tclass);
675	log_append(avc_audit_buf, "\n");
676	avc_log(SELINUX_AVC, "%s", avc_audit_buf);
677
678	avc_release_lock(avc_log_lock);
679}
680
681hidden_def(avc_audit)
682
683int avc_has_perm_noaudit(security_id_t ssid,
684			 security_id_t tsid,
685			 security_class_t tclass,
686			 access_vector_t requested,
687			 struct avc_entry_ref *aeref, struct av_decision *avd)
688{
689	struct avc_entry *ae;
690	int rc = 0;
691	struct avc_entry entry;
692	access_vector_t denied;
693	struct avc_entry_ref ref;
694
695	if (!avc_using_threads && !avc_app_main_loop) {
696		(void)avc_netlink_check_nb();
697	}
698
699	if (!aeref) {
700		avc_entry_ref_init(&ref);
701		aeref = &ref;
702	}
703
704	avc_get_lock(avc_lock);
705	avc_cache_stats_incr(entry_lookups);
706	ae = aeref->ae;
707	if (ae) {
708		if (ae->ssid == ssid &&
709		    ae->tsid == tsid &&
710		    ae->tclass == tclass &&
711		    ((ae->avd.decided & requested) == requested)) {
712			avc_cache_stats_incr(entry_hits);
713			ae->used = 1;
714		} else {
715			avc_cache_stats_incr(entry_discards);
716			ae = 0;
717		}
718	}
719
720	if (!ae) {
721		avc_cache_stats_incr(entry_misses);
722		rc = avc_lookup(ssid, tsid, tclass, requested, aeref);
723		if (rc) {
724			rc = security_compute_av(ssid->ctx, tsid->ctx,
725						 tclass, requested,
726						 &entry.avd);
727			if (rc)
728				goto out;
729			rc = avc_insert(ssid, tsid, tclass, &entry, aeref);
730			if (rc)
731				goto out;
732		}
733		ae = aeref->ae;
734	}
735
736	if (avd)
737		memcpy(avd, &ae->avd, sizeof(*avd));
738
739	denied = requested & ~(ae->avd.allowed);
740
741	if (!requested || denied) {
742		if (!avc_enforcing ||
743		    (ae->avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE))
744			ae->avd.allowed |= requested;
745		else {
746			errno = EACCES;
747			rc = -1;
748		}
749	}
750
751      out:
752	avc_release_lock(avc_lock);
753	return rc;
754}
755
756hidden_def(avc_has_perm_noaudit)
757
758int avc_has_perm(security_id_t ssid, security_id_t tsid,
759		 security_class_t tclass, access_vector_t requested,
760		 struct avc_entry_ref *aeref, void *auditdata)
761{
762	struct av_decision avd;
763	int errsave, rc;
764
765	memset(&avd, 0, sizeof(avd));
766
767	rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, aeref, &avd);
768	errsave = errno;
769	avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
770	errno = errsave;
771	return rc;
772}
773
774int avc_compute_create(security_id_t ssid,  security_id_t tsid,
775		       security_class_t tclass, security_id_t *newsid)
776{
777	int rc;
778	struct avc_entry_ref aeref;
779	struct avc_entry entry;
780	char * ctx;
781
782	*newsid = NULL;
783	avc_entry_ref_init(&aeref);
784
785	avc_get_lock(avc_lock);
786
787	/* check for a cached entry */
788	rc = avc_lookup(ssid, tsid, tclass, 0, &aeref);
789	if (rc) {
790		/* need to make a cache entry for this tuple */
791		rc = security_compute_av(ssid->ctx, tsid->ctx,
792					 tclass, 0, &entry.avd);
793		if (rc)
794			goto out;
795		rc = avc_insert(ssid, tsid, tclass, &entry, &aeref);
796		if (rc)
797			goto out;
798	}
799
800	/* check for a saved compute_create value */
801	if (!aeref.ae->create_sid) {
802		/* need to query the kernel policy */
803		rc = security_compute_create(ssid->ctx, tsid->ctx, tclass,
804						 &ctx);
805		if (rc)
806			goto out;
807		rc = sidtab_context_to_sid(&avc_sidtab, ctx, newsid);
808		freecon(ctx);
809		if (rc)
810			goto out;
811
812		aeref.ae->create_sid = *newsid;
813	} else {
814		/* found saved value */
815		*newsid = aeref.ae->create_sid;
816	}
817
818	rc = 0;
819out:
820	avc_release_lock(avc_lock);
821	return rc;
822}
823
824int avc_add_callback(int (*callback) (uint32_t event, security_id_t ssid,
825				      security_id_t tsid,
826				      security_class_t tclass,
827				      access_vector_t perms,
828				      access_vector_t * out_retained),
829		     uint32_t events, security_id_t ssid,
830		     security_id_t tsid,
831		     security_class_t tclass, access_vector_t perms)
832{
833	struct avc_callback_node *c;
834	int rc = 0;
835
836	c = avc_malloc(sizeof(*c));
837	if (!c) {
838		rc = -1;
839		goto out;
840	}
841
842	c->callback = callback;
843	c->events = events;
844	c->ssid = ssid;
845	c->tsid = tsid;
846	c->tclass = tclass;
847	c->perms = perms;
848	c->next = avc_callbacks;
849	avc_callbacks = c;
850      out:
851	return rc;
852}
853
854static inline int avc_sidcmp(security_id_t x, security_id_t y)
855{
856	return (x == y || x == SECSID_WILD || y == SECSID_WILD);
857}
858
859static inline void avc_update_node(uint32_t event, struct avc_node *node,
860				   access_vector_t perms)
861{
862	switch (event) {
863	case AVC_CALLBACK_GRANT:
864		node->ae.avd.allowed |= perms;
865		break;
866	case AVC_CALLBACK_TRY_REVOKE:
867	case AVC_CALLBACK_REVOKE:
868		node->ae.avd.allowed &= ~perms;
869		break;
870	case AVC_CALLBACK_AUDITALLOW_ENABLE:
871		node->ae.avd.auditallow |= perms;
872		break;
873	case AVC_CALLBACK_AUDITALLOW_DISABLE:
874		node->ae.avd.auditallow &= ~perms;
875		break;
876	case AVC_CALLBACK_AUDITDENY_ENABLE:
877		node->ae.avd.auditdeny |= perms;
878		break;
879	case AVC_CALLBACK_AUDITDENY_DISABLE:
880		node->ae.avd.auditdeny &= ~perms;
881		break;
882	}
883}
884
885static int avc_update_cache(uint32_t event, security_id_t ssid,
886			    security_id_t tsid, security_class_t tclass,
887			    access_vector_t perms)
888{
889	struct avc_node *node;
890	int i;
891
892	avc_get_lock(avc_lock);
893
894	if (ssid == SECSID_WILD || tsid == SECSID_WILD) {
895		/* apply to all matching nodes */
896		for (i = 0; i < AVC_CACHE_SLOTS; i++) {
897			for (node = avc_cache.slots[i]; node; node = node->next) {
898				if (avc_sidcmp(ssid, node->ae.ssid) &&
899				    avc_sidcmp(tsid, node->ae.tsid) &&
900				    tclass == node->ae.tclass) {
901					avc_update_node(event, node, perms);
902				}
903			}
904		}
905	} else {
906		/* apply to one node */
907		node = avc_search_node(ssid, tsid, tclass, 0);
908		if (node) {
909			avc_update_node(event, node, perms);
910		}
911	}
912
913	avc_release_lock(avc_lock);
914
915	return 0;
916}
917
918/* avc_control - update cache and call callbacks
919 *
920 * This should not be called directly; use the individual event
921 * functions instead.
922 */
923static int avc_control(uint32_t event, security_id_t ssid,
924		       security_id_t tsid, security_class_t tclass,
925		       access_vector_t perms,
926		       uint32_t seqno, access_vector_t * out_retained)
927{
928	struct avc_callback_node *c;
929	access_vector_t tretained = 0, cretained = 0;
930	int ret, rc = 0, errsave = 0;
931	errno = 0;
932
933	/*
934	 * try_revoke only removes permissions from the cache
935	 * state if they are not retained by the object manager.
936	 * Hence, try_revoke must wait until after the callbacks have
937	 * been invoked to update the cache state.
938	 */
939	if (event != AVC_CALLBACK_TRY_REVOKE)
940		avc_update_cache(event, ssid, tsid, tclass, perms);
941
942	for (c = avc_callbacks; c; c = c->next) {
943		if ((c->events & event) &&
944		    avc_sidcmp(c->ssid, ssid) &&
945		    avc_sidcmp(c->tsid, tsid) &&
946		    c->tclass == tclass && (c->perms & perms)) {
947			cretained = 0;
948			ret = c->callback(event, ssid, tsid, tclass,
949					  (c->perms & perms), &cretained);
950			if (ret && !rc) {
951				rc = ret;
952				errsave = errno;
953			}
954			if (!ret)
955				tretained |= cretained;
956		}
957	}
958
959	if (event == AVC_CALLBACK_TRY_REVOKE) {
960		/* revoke any unretained permissions */
961		perms &= ~tretained;
962		avc_update_cache(event, ssid, tsid, tclass, perms);
963		*out_retained = tretained;
964	}
965
966	avc_get_lock(avc_lock);
967	if (seqno > avc_cache.latest_notif)
968		avc_cache.latest_notif = seqno;
969	avc_release_lock(avc_lock);
970
971	errno = errsave;
972	return rc;
973}
974
975/**
976 * avc_ss_grant - Grant previously denied permissions.
977 * @ssid: source security identifier or %SECSID_WILD
978 * @tsid: target security identifier or %SECSID_WILD
979 * @tclass: target security class
980 * @perms: permissions to grant
981 * @seqno: policy sequence number
982 */
983int avc_ss_grant(security_id_t ssid, security_id_t tsid,
984		 security_class_t tclass, access_vector_t perms,
985		 uint32_t seqno)
986{
987	return avc_control(AVC_CALLBACK_GRANT,
988			   ssid, tsid, tclass, perms, seqno, 0);
989}
990
991/**
992 * avc_ss_try_revoke - Try to revoke previously granted permissions.
993 * @ssid: source security identifier or %SECSID_WILD
994 * @tsid: target security identifier or %SECSID_WILD
995 * @tclass: target security class
996 * @perms: permissions to grant
997 * @seqno: policy sequence number
998 * @out_retained: subset of @perms that are retained
999 *
1000 * Try to revoke previously granted permissions, but
1001 * only if they are not retained as migrated permissions.
1002 * Return the subset of permissions that are retained via @out_retained.
1003 */
1004int avc_ss_try_revoke(security_id_t ssid, security_id_t tsid,
1005		      security_class_t tclass,
1006		      access_vector_t perms, uint32_t seqno,
1007		      access_vector_t * out_retained)
1008{
1009	return avc_control(AVC_CALLBACK_TRY_REVOKE,
1010			   ssid, tsid, tclass, perms, seqno, out_retained);
1011}
1012
1013/**
1014 * avc_ss_revoke - Revoke previously granted permissions.
1015 * @ssid: source security identifier or %SECSID_WILD
1016 * @tsid: target security identifier or %SECSID_WILD
1017 * @tclass: target security class
1018 * @perms: permissions to grant
1019 * @seqno: policy sequence number
1020 *
1021 * Revoke previously granted permissions, even if
1022 * they are retained as migrated permissions.
1023 */
1024int avc_ss_revoke(security_id_t ssid, security_id_t tsid,
1025		  security_class_t tclass, access_vector_t perms,
1026		  uint32_t seqno)
1027{
1028	return avc_control(AVC_CALLBACK_REVOKE,
1029			   ssid, tsid, tclass, perms, seqno, 0);
1030}
1031
1032/**
1033 * avc_ss_reset - Flush the cache and revalidate migrated permissions.
1034 * @seqno: policy sequence number
1035 */
1036int avc_ss_reset(uint32_t seqno)
1037{
1038	int rc;
1039
1040	rc = avc_reset();
1041
1042	avc_get_lock(avc_lock);
1043	if (seqno > avc_cache.latest_notif)
1044		avc_cache.latest_notif = seqno;
1045	avc_release_lock(avc_lock);
1046
1047	return rc;
1048}
1049
1050/**
1051 * avc_ss_set_auditallow - Enable or disable auditing of granted permissions.
1052 * @ssid: source security identifier or %SECSID_WILD
1053 * @tsid: target security identifier or %SECSID_WILD
1054 * @tclass: target security class
1055 * @perms: permissions to grant
1056 * @seqno: policy sequence number
1057 * @enable: enable flag.
1058 */
1059int avc_ss_set_auditallow(security_id_t ssid, security_id_t tsid,
1060			  security_class_t tclass, access_vector_t perms,
1061			  uint32_t seqno, uint32_t enable)
1062{
1063	if (enable)
1064		return avc_control(AVC_CALLBACK_AUDITALLOW_ENABLE,
1065				   ssid, tsid, tclass, perms, seqno, 0);
1066	else
1067		return avc_control(AVC_CALLBACK_AUDITALLOW_DISABLE,
1068				   ssid, tsid, tclass, perms, seqno, 0);
1069}
1070
1071/**
1072 * avc_ss_set_auditdeny - Enable or disable auditing of denied permissions.
1073 * @ssid: source security identifier or %SECSID_WILD
1074 * @tsid: target security identifier or %SECSID_WILD
1075 * @tclass: target security class
1076 * @perms: permissions to grant
1077 * @seqno: policy sequence number
1078 * @enable: enable flag.
1079 */
1080int avc_ss_set_auditdeny(security_id_t ssid, security_id_t tsid,
1081			 security_class_t tclass, access_vector_t perms,
1082			 uint32_t seqno, uint32_t enable)
1083{
1084	if (enable)
1085		return avc_control(AVC_CALLBACK_AUDITDENY_ENABLE,
1086				   ssid, tsid, tclass, perms, seqno, 0);
1087	else
1088		return avc_control(AVC_CALLBACK_AUDITDENY_DISABLE,
1089				   ssid, tsid, tclass, perms, seqno, 0);
1090}
1091