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