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