debuggers.hg

view xen/xsm/flask/avc.c @ 0:7d21f7218375

Exact replica of unstable on 051908 + README-this
author Mukesh Rathor
date Mon May 19 15:34:57 2008 -0700 (2008-05-19)
parents
children 5c0bf00e371d
line source
1 /*
2 * Implementation of the kernel access vector cache (AVC).
3 *
4 * Authors: Stephen Smalley, <sds@epoch.ncsc.mil>
5 * James Morris <jmorris@redhat.com>
6 *
7 * Update: KaiGai, Kohei <kaigai@ak.jp.nec.com>
8 * Replaced the avc_lock spinlock by RCU.
9 *
10 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2,
14 * as published by the Free Software Foundation.
15 */
17 /* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
19 #include <xen/lib.h>
20 #include <xen/xmalloc.h>
21 #include <xen/types.h>
22 #include <xen/list.h>
23 #include <xen/spinlock.h>
24 #include <xen/prefetch.h>
25 #include <xen/kernel.h>
26 #include <xen/sched.h>
27 #include <xen/init.h>
28 #include <xen/rcupdate.h>
29 #include <asm/atomic.h>
30 #include <asm/current.h>
32 #include "avc.h"
33 #include "avc_ss.h"
35 static const struct av_perm_to_string
36 {
37 u16 tclass;
38 u32 value;
39 const char *name;
40 } av_perm_to_string[] = {
41 #define S_(c, v, s) { c, v, s },
42 #include "av_perm_to_string.h"
43 #undef S_
44 };
46 static const char *class_to_string[] = {
47 #define S_(s) s,
48 #include "class_to_string.h"
49 #undef S_
50 };
52 #define TB_(s) static const char * s [] = {
53 #define TE_(s) };
54 #define S_(s) s,
55 #include "common_perm_to_string.h"
56 #undef TB_
57 #undef TE_
58 #undef S_
60 static const struct av_inherit
61 {
62 u16 tclass;
63 const char **common_pts;
64 u32 common_base;
65 } av_inherit[] = {
66 #define S_(c, i, b) { c, common_##i##_perm_to_string, b },
67 #include "av_inherit.h"
68 #undef S_
69 };
71 #define AVC_CACHE_SLOTS 512
72 #define AVC_DEF_CACHE_THRESHOLD 512
73 #define AVC_CACHE_RECLAIM 16
75 #ifdef FLASK_AVC_STATS
76 #define avc_cache_stats_incr(field) \
77 do { \
78 __get_cpu_var(avc_cache_stats).field++; \
79 } while (0)
80 #else
81 #define avc_cache_stats_incr(field) do {} while (0)
82 #endif
84 struct avc_entry {
85 u32 ssid;
86 u32 tsid;
87 u16 tclass;
88 struct av_decision avd;
89 atomic_t used; /* used recently */
90 };
92 struct avc_node {
93 struct avc_entry ae;
94 struct list_head list;
95 struct rcu_head rhead;
96 };
98 struct avc_cache {
99 struct list_head slots[AVC_CACHE_SLOTS];
100 spinlock_t slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */
101 atomic_t lru_hint; /* LRU hint for reclaim scan */
102 atomic_t active_nodes;
103 u32 latest_notif; /* latest revocation notification */
104 };
106 struct avc_callback_node {
107 int (*callback) (u32 event, u32 ssid, u32 tsid,
108 u16 tclass, u32 perms,
109 u32 *out_retained);
110 u32 events;
111 u32 ssid;
112 u32 tsid;
113 u16 tclass;
114 u32 perms;
115 struct avc_callback_node *next;
116 };
118 /* Exported via Flask hypercall */
119 unsigned int avc_cache_threshold = AVC_DEF_CACHE_THRESHOLD;
121 #ifdef FLASK_AVC_STATS
122 DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 };
123 #endif
125 static struct avc_cache avc_cache;
126 static struct avc_callback_node *avc_callbacks;
128 static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
129 {
130 return (ssid ^ (tsid<<2) ^ (tclass<<4)) & (AVC_CACHE_SLOTS - 1);
131 }
133 /**
134 * avc_dump_av - Display an access vector in human-readable form.
135 * @tclass: target security class
136 * @av: access vector
137 */
138 static void avc_dump_av(u16 tclass, u32 av)
139 {
140 const char **common_pts = NULL;
141 u32 common_base = 0;
142 int i, i2, perm;
144 if ( av == 0 )
145 {
146 printk(" null");
147 return;
148 }
150 for ( i = 0; i < ARRAY_SIZE(av_inherit); i++ )
151 {
152 if (av_inherit[i].tclass == tclass)
153 {
154 common_pts = av_inherit[i].common_pts;
155 common_base = av_inherit[i].common_base;
156 break;
157 }
158 }
160 printk(" {");
161 i = 0;
162 perm = 1;
163 while ( perm < common_base )
164 {
165 if (perm & av)
166 {
167 printk(" %s", common_pts[i]);
168 av &= ~perm;
169 }
170 i++;
171 perm <<= 1;
172 }
174 while ( i < sizeof(av) * 8 )
175 {
176 if ( perm & av )
177 {
178 for ( i2 = 0; i2 < ARRAY_SIZE(av_perm_to_string); i2++ )
179 {
180 if ( (av_perm_to_string[i2].tclass == tclass) &&
181 (av_perm_to_string[i2].value == perm) )
182 break;
183 }
184 if ( i2 < ARRAY_SIZE(av_perm_to_string) )
185 {
186 printk(" %s", av_perm_to_string[i2].name);
187 av &= ~perm;
188 }
189 }
190 i++;
191 perm <<= 1;
192 }
194 if ( av )
195 printk(" 0x%x", av);
197 printk(" }");
198 }
200 /**
201 * avc_dump_query - Display a SID pair and a class in human-readable form.
202 * @ssid: source security identifier
203 * @tsid: target security identifier
204 * @tclass: target security class
205 */
206 static void avc_dump_query(u32 ssid, u32 tsid, u16 tclass)
207 {
208 int rc;
209 char *scontext;
210 u32 scontext_len;
212 rc = security_sid_to_context(ssid, &scontext, &scontext_len);
213 if ( rc )
214 printk("ssid=%d", ssid);
215 else
216 {
217 printk("scontext=%s", scontext);
218 xfree(scontext);
219 }
221 rc = security_sid_to_context(tsid, &scontext, &scontext_len);
222 if ( rc )
223 printk(" tsid=%d", tsid);
224 else
225 {
226 printk(" tcontext=%s", scontext);
227 xfree(scontext);
228 }
229 printk("\n");
230 printk("tclass=%s", class_to_string[tclass]);
231 }
233 /**
234 * avc_init - Initialize the AVC.
235 *
236 * Initialize the access vector cache.
237 */
238 void __init avc_init(void)
239 {
240 int i;
242 for ( i = 0; i < AVC_CACHE_SLOTS; i++ )
243 {
244 INIT_LIST_HEAD(&avc_cache.slots[i]);
245 spin_lock_init(&avc_cache.slots_lock[i]);
246 }
247 atomic_set(&avc_cache.active_nodes, 0);
248 atomic_set(&avc_cache.lru_hint, 0);
250 printk("AVC INITIALIZED\n");
251 }
253 int avc_get_hash_stats(char *page)
254 {
255 int i, chain_len, max_chain_len, slots_used;
256 struct avc_node *node;
258 rcu_read_lock();
260 slots_used = 0;
261 max_chain_len = 0;
262 for ( i = 0; i < AVC_CACHE_SLOTS; i++ )
263 {
264 if ( !list_empty(&avc_cache.slots[i]) )
265 {
266 slots_used++;
267 chain_len = 0;
268 list_for_each_entry_rcu(node, &avc_cache.slots[i], list)
269 chain_len++;
270 if ( chain_len > max_chain_len )
271 max_chain_len = chain_len;
272 }
273 }
275 rcu_read_unlock();
277 return snprintf(page, PAGE_SIZE, "entries: %d\nbuckets used: %d/%d\n"
278 "longest chain: %d\n",
279 atomic_read(&avc_cache.active_nodes),
280 slots_used, AVC_CACHE_SLOTS, max_chain_len);
281 }
283 static void avc_node_free(struct rcu_head *rhead)
284 {
285 struct avc_node *node = container_of(rhead, struct avc_node, rhead);
286 xfree(node);
287 avc_cache_stats_incr(frees);
288 }
290 static void avc_node_delete(struct avc_node *node)
291 {
292 list_del_rcu(&node->list);
293 call_rcu(&node->rhead, avc_node_free);
294 atomic_dec(&avc_cache.active_nodes);
295 }
297 static void avc_node_kill(struct avc_node *node)
298 {
299 xfree(node);
300 avc_cache_stats_incr(frees);
301 atomic_dec(&avc_cache.active_nodes);
302 }
304 static void avc_node_replace(struct avc_node *new, struct avc_node *old)
305 {
306 list_replace_rcu(&old->list, &new->list);
307 call_rcu(&old->rhead, avc_node_free);
308 atomic_dec(&avc_cache.active_nodes);
309 }
311 static inline int avc_reclaim_node(void)
312 {
313 struct avc_node *node;
314 int hvalue, try, ecx;
315 unsigned long flags;
317 for ( try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++ )
318 {
319 atomic_inc(&avc_cache.lru_hint);
320 hvalue = atomic_read(&avc_cache.lru_hint) & (AVC_CACHE_SLOTS - 1);
322 spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flags);
324 list_for_each_entry(node, &avc_cache.slots[hvalue], list)
325 {
326 if ( atomic_dec_and_test(&node->ae.used) )
327 {
328 /* Recently Unused */
329 avc_node_delete(node);
330 avc_cache_stats_incr(reclaims);
331 ecx++;
332 if ( ecx >= AVC_CACHE_RECLAIM )
333 {
334 spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags);
335 goto out;
336 }
337 }
338 }
339 spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags);
340 }
341 out:
342 return ecx;
343 }
345 static struct avc_node *avc_alloc_node(void)
346 {
347 struct avc_node *node;
349 node = xmalloc(struct avc_node);
350 if (!node)
351 goto out;
353 memset(node, 0, sizeof(*node));
354 INIT_RCU_HEAD(&node->rhead);
355 INIT_LIST_HEAD(&node->list);
356 atomic_set(&node->ae.used, 1);
357 avc_cache_stats_incr(allocations);
359 atomic_inc(&avc_cache.active_nodes);
360 if ( atomic_read(&avc_cache.active_nodes) > avc_cache_threshold )
361 avc_reclaim_node();
363 out:
364 return node;
365 }
367 static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tclass, struct avc_entry *ae)
368 {
369 node->ae.ssid = ssid;
370 node->ae.tsid = tsid;
371 node->ae.tclass = tclass;
372 memcpy(&node->ae.avd, &ae->avd, sizeof(node->ae.avd));
373 }
375 static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass)
376 {
377 struct avc_node *node, *ret = NULL;
378 int hvalue;
380 hvalue = avc_hash(ssid, tsid, tclass);
381 list_for_each_entry_rcu(node, &avc_cache.slots[hvalue], list)
382 {
383 if ( ssid == node->ae.ssid && tclass == node->ae.tclass &&
384 tsid == node->ae.tsid )
385 {
386 ret = node;
387 break;
388 }
389 }
391 if ( ret == NULL )
392 {
393 /* cache miss */
394 goto out;
395 }
397 /* cache hit */
398 if ( atomic_read(&ret->ae.used) != 1 )
399 atomic_set(&ret->ae.used, 1);
400 out:
401 return ret;
402 }
404 /**
405 * avc_lookup - Look up an AVC entry.
406 * @ssid: source security identifier
407 * @tsid: target security identifier
408 * @tclass: target security class
409 * @requested: requested permissions, interpreted based on @tclass
410 *
411 * Look up an AVC entry that is valid for the
412 * @requested permissions between the SID pair
413 * (@ssid, @tsid), interpreting the permissions
414 * based on @tclass. If a valid AVC entry exists,
415 * then this function return the avc_node.
416 * Otherwise, this function returns NULL.
417 */
418 static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass, u32 requested)
419 {
420 struct avc_node *node;
422 avc_cache_stats_incr(lookups);
423 node = avc_search_node(ssid, tsid, tclass);
425 if ( node && ((node->ae.avd.decided & requested) == requested) )
426 {
427 avc_cache_stats_incr(hits);
428 goto out;
429 }
431 node = NULL;
432 avc_cache_stats_incr(misses);
433 out:
434 return node;
435 }
437 static int avc_latest_notif_update(int seqno, int is_insert)
438 {
439 int ret = 0;
440 static DEFINE_SPINLOCK(notif_lock);
441 unsigned long flag;
443 spin_lock_irqsave(&notif_lock, flag);
444 if ( is_insert )
445 {
446 if ( seqno < avc_cache.latest_notif )
447 {
448 printk(KERN_WARNING "avc: seqno %d < latest_notif %d\n",
449 seqno, avc_cache.latest_notif);
450 ret = -EAGAIN;
451 }
452 }
453 else
454 {
455 if ( seqno > avc_cache.latest_notif )
456 avc_cache.latest_notif = seqno;
457 }
458 spin_unlock_irqrestore(&notif_lock, flag);
460 return ret;
461 }
463 /**
464 * avc_insert - Insert an AVC entry.
465 * @ssid: source security identifier
466 * @tsid: target security identifier
467 * @tclass: target security class
468 * @ae: AVC entry
469 *
470 * Insert an AVC entry for the SID pair
471 * (@ssid, @tsid) and class @tclass.
472 * The access vectors and the sequence number are
473 * normally provided by the security server in
474 * response to a security_compute_av() call. If the
475 * sequence number @ae->avd.seqno is not less than the latest
476 * revocation notification, then the function copies
477 * the access vectors into a cache entry, returns
478 * avc_node inserted. Otherwise, this function returns NULL.
479 */
480 static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct avc_entry *ae)
481 {
482 struct avc_node *pos, *node = NULL;
483 int hvalue;
484 unsigned long flag;
486 if ( avc_latest_notif_update(ae->avd.seqno, 1) )
487 goto out;
489 node = avc_alloc_node();
490 if ( node )
491 {
492 hvalue = avc_hash(ssid, tsid, tclass);
493 avc_node_populate(node, ssid, tsid, tclass, ae);
495 spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flag);
496 list_for_each_entry(pos, &avc_cache.slots[hvalue], list)
497 {
498 if ( pos->ae.ssid == ssid && pos->ae.tsid == tsid &&
499 pos->ae.tclass == tclass )
500 {
501 avc_node_replace(node, pos);
502 goto found;
503 }
504 }
505 list_add_rcu(&node->list, &avc_cache.slots[hvalue]);
506 found:
507 spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flag);
508 }
509 out:
510 return node;
511 }
513 /**
514 * avc_audit - Audit the granting or denial of permissions.
515 * @ssid: source security identifier
516 * @tsid: target security identifier
517 * @tclass: target security class
518 * @requested: requested permissions
519 * @avd: access vector decisions
520 * @result: result from avc_has_perm_noaudit
521 * @a: auxiliary audit data
522 *
523 * Audit the granting or denial of permissions in accordance
524 * with the policy. This function is typically called by
525 * avc_has_perm() after a permission check, but can also be
526 * called directly by callers who use avc_has_perm_noaudit()
527 * in order to separate the permission check from the auditing.
528 * For example, this separation is useful when the permission check must
529 * be performed under a lock, to allow the lock to be released
530 * before calling the auditing code.
531 */
532 void avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
533 struct av_decision *avd, int result, struct avc_audit_data *a)
534 {
535 struct domain *d = current->domain;
536 u32 denied, audited;
538 denied = requested & ~avd->allowed;
539 if ( denied )
540 {
541 audited = denied;
542 if ( !(audited & avd->auditdeny) )
543 return;
544 }
545 else if ( result )
546 {
547 audited = denied = requested;
548 }
549 else
550 {
551 audited = requested;
552 if ( !(audited & avd->auditallow) )
553 return;
554 }
556 printk("avc: %s ", denied ? "denied" : "granted");
557 avc_dump_av(tclass, audited);
558 printk(" for ");
560 if ( a && a->d )
561 d = a->d;
562 if ( d )
563 printk("domid=%d", d->domain_id);
565 printk("\n");
566 avc_dump_query(ssid, tsid, tclass);
567 printk("\n");
569 }
571 /**
572 * avc_add_callback - Register a callback for security events.
573 * @callback: callback function
574 * @events: security events
575 * @ssid: source security identifier or %SECSID_WILD
576 * @tsid: target security identifier or %SECSID_WILD
577 * @tclass: target security class
578 * @perms: permissions
579 *
580 * Register a callback function for events in the set @events
581 * related to the SID pair (@ssid, @tsid) and
582 * and the permissions @perms, interpreting
583 * @perms based on @tclass. Returns %0 on success or
584 * -%ENOMEM if insufficient memory exists to add the callback.
585 */
586 int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, u16 tclass,
587 u32 perms, u32 *out_retained), u32 events, u32 ssid, u32 tsid,
588 u16 tclass, u32 perms)
589 {
590 struct avc_callback_node *c;
591 int rc = 0;
593 c = xmalloc(struct avc_callback_node);
594 if ( !c )
595 {
596 rc = -ENOMEM;
597 goto out;
598 }
600 c->callback = callback;
601 c->events = events;
602 c->ssid = ssid;
603 c->tsid = tsid;
604 c->perms = perms;
605 c->next = avc_callbacks;
606 avc_callbacks = c;
607 out:
608 return rc;
609 }
611 static inline int avc_sidcmp(u32 x, u32 y)
612 {
613 return (x == y || x == SECSID_WILD || y == SECSID_WILD);
614 }
616 /**
617 * avc_update_node Update an AVC entry
618 * @event : Updating event
619 * @perms : Permission mask bits
620 * @ssid,@tsid,@tclass : identifier of an AVC entry
621 *
622 * if a valid AVC entry doesn't exist,this function returns -ENOENT.
623 * if kmalloc() called internal returns NULL, this function returns -ENOMEM.
624 * otherwise, this function update the AVC entry. The original AVC-entry object
625 * will release later by RCU.
626 */
627 static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass)
628 {
629 int hvalue, rc = 0;
630 unsigned long flag;
631 struct avc_node *pos, *node, *orig = NULL;
633 node = avc_alloc_node();
634 if ( !node )
635 {
636 rc = -ENOMEM;
637 goto out;
638 }
640 hvalue = avc_hash(ssid, tsid, tclass);
641 spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flag);
643 list_for_each_entry(pos, &avc_cache.slots[hvalue], list)
644 {
645 if ( ssid==pos->ae.ssid && tsid==pos->ae.tsid &&
646 tclass==pos->ae.tclass )
647 {
648 orig = pos;
649 break;
650 }
651 }
653 if ( !orig )
654 {
655 rc = -ENOENT;
656 avc_node_kill(node);
657 goto out_unlock;
658 }
660 /*
661 * Copy and replace original node.
662 */
664 avc_node_populate(node, ssid, tsid, tclass, &orig->ae);
666 switch ( event )
667 {
668 case AVC_CALLBACK_GRANT:
669 node->ae.avd.allowed |= perms;
670 break;
671 case AVC_CALLBACK_TRY_REVOKE:
672 case AVC_CALLBACK_REVOKE:
673 node->ae.avd.allowed &= ~perms;
674 break;
675 case AVC_CALLBACK_AUDITALLOW_ENABLE:
676 node->ae.avd.auditallow |= perms;
677 break;
678 case AVC_CALLBACK_AUDITALLOW_DISABLE:
679 node->ae.avd.auditallow &= ~perms;
680 break;
681 case AVC_CALLBACK_AUDITDENY_ENABLE:
682 node->ae.avd.auditdeny |= perms;
683 break;
684 case AVC_CALLBACK_AUDITDENY_DISABLE:
685 node->ae.avd.auditdeny &= ~perms;
686 break;
687 }
688 avc_node_replace(node, orig);
689 out_unlock:
690 spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flag);
691 out:
692 return rc;
693 }
695 /**
696 * avc_ss_reset - Flush the cache and revalidate migrated permissions.
697 * @seqno: policy sequence number
698 */
699 int avc_ss_reset(u32 seqno)
700 {
701 struct avc_callback_node *c;
702 int i, rc = 0;
703 unsigned long flag;
704 struct avc_node *node;
706 for ( i = 0; i < AVC_CACHE_SLOTS; i++ )
707 {
708 spin_lock_irqsave(&avc_cache.slots_lock[i], flag);
709 list_for_each_entry(node, &avc_cache.slots[i], list)
710 avc_node_delete(node);
711 spin_unlock_irqrestore(&avc_cache.slots_lock[i], flag);
712 }
714 for ( c = avc_callbacks; c; c = c->next )
715 {
716 if ( c->events & AVC_CALLBACK_RESET )
717 {
718 rc = c->callback(AVC_CALLBACK_RESET,
719 0, 0, 0, 0, NULL);
720 if ( rc )
721 goto out;
722 }
723 }
725 avc_latest_notif_update(seqno, 0);
726 out:
727 return rc;
728 }
730 /**
731 * avc_has_perm_noaudit - Check permissions but perform no auditing.
732 * @ssid: source security identifier
733 * @tsid: target security identifier
734 * @tclass: target security class
735 * @requested: requested permissions, interpreted based on @tclass
736 * @avd: access vector decisions
737 *
738 * Check the AVC to determine whether the @requested permissions are granted
739 * for the SID pair (@ssid, @tsid), interpreting the permissions
740 * based on @tclass, and call the security server on a cache miss to obtain
741 * a new decision and add it to the cache. Return a copy of the decisions
742 * in @avd. Return %0 if all @requested permissions are granted,
743 * -%EACCES if any permissions are denied, or another -errno upon
744 * other errors. This function is typically called by avc_has_perm(),
745 * but may also be called directly to separate permission checking from
746 * auditing, e.g. in cases where a lock must be held for the check but
747 * should be released for the auditing.
748 */
749 int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
750 struct av_decision *avd)
751 {
752 struct avc_node *node;
753 struct avc_entry entry, *p_ae;
754 int rc = 0;
755 u32 denied;
757 rcu_read_lock();
759 node = avc_lookup(ssid, tsid, tclass, requested);
760 if ( !node )
761 {
762 rcu_read_unlock();
763 rc = security_compute_av(ssid,tsid,tclass,requested,&entry.avd);
764 if ( rc )
765 goto out;
766 rcu_read_lock();
767 node = avc_insert(ssid,tsid,tclass,&entry);
768 }
770 p_ae = node ? &node->ae : &entry;
772 if ( avd )
773 memcpy(avd, &p_ae->avd, sizeof(*avd));
775 denied = requested & ~(p_ae->avd.allowed);
777 if ( !requested || denied )
778 {
779 if ( flask_enforcing )
780 rc = -EACCES;
781 else
782 if ( node )
783 avc_update_node(AVC_CALLBACK_GRANT,requested,
784 ssid,tsid,tclass);
785 }
787 rcu_read_unlock();
788 out:
789 return rc;
790 }
792 /**
793 * avc_has_perm - Check permissions and perform any appropriate auditing.
794 * @ssid: source security identifier
795 * @tsid: target security identifier
796 * @tclass: target security class
797 * @requested: requested permissions, interpreted based on @tclass
798 * @auditdata: auxiliary audit data
799 *
800 * Check the AVC to determine whether the @requested permissions are granted
801 * for the SID pair (@ssid, @tsid), interpreting the permissions
802 * based on @tclass, and call the security server on a cache miss to obtain
803 * a new decision and add it to the cache. Audit the granting or denial of
804 * permissions in accordance with the policy. Return %0 if all @requested
805 * permissions are granted, -%EACCES if any permissions are denied, or
806 * another -errno upon other errors.
807 */
808 int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,
809 u32 requested, struct avc_audit_data *auditdata)
810 {
811 struct av_decision avd;
812 int rc;
814 rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, &avd);
815 avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
816 return rc;
817 }