1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Implementation of the kernel access vector cache (AVC). |
4 | * |
5 | * Authors: Stephen Smalley, <stephen.smalley.work@gmail.com> |
6 | * James Morris <jmorris@redhat.com> |
7 | * |
8 | * Update: KaiGai, Kohei <kaigai@ak.jp.nec.com> |
9 | * Replaced the avc_lock spinlock by RCU. |
10 | * |
11 | * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> |
12 | */ |
13 | #include <linux/types.h> |
14 | #include <linux/stddef.h> |
15 | #include <linux/kernel.h> |
16 | #include <linux/slab.h> |
17 | #include <linux/fs.h> |
18 | #include <linux/dcache.h> |
19 | #include <linux/init.h> |
20 | #include <linux/skbuff.h> |
21 | #include <linux/percpu.h> |
22 | #include <linux/list.h> |
23 | #include <net/sock.h> |
24 | #include <linux/un.h> |
25 | #include <net/af_unix.h> |
26 | #include <linux/ip.h> |
27 | #include <linux/audit.h> |
28 | #include <linux/ipv6.h> |
29 | #include <net/ipv6.h> |
30 | #include "avc.h" |
31 | #include "avc_ss.h" |
32 | #include "classmap.h" |
33 | |
34 | #define CREATE_TRACE_POINTS |
35 | #include <trace/events/avc.h> |
36 | |
37 | #define AVC_CACHE_SLOTS 512 |
38 | #define AVC_DEF_CACHE_THRESHOLD 512 |
39 | #define AVC_CACHE_RECLAIM 16 |
40 | |
41 | #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS |
42 | #define avc_cache_stats_incr(field) this_cpu_inc(avc_cache_stats.field) |
43 | #else |
44 | #define avc_cache_stats_incr(field) do {} while (0) |
45 | #endif |
46 | |
47 | struct avc_entry { |
48 | u32 ssid; |
49 | u32 tsid; |
50 | u16 tclass; |
51 | struct av_decision avd; |
52 | struct avc_xperms_node *xp_node; |
53 | }; |
54 | |
55 | struct avc_node { |
56 | struct avc_entry ae; |
57 | struct hlist_node list; /* anchored in avc_cache->slots[i] */ |
58 | struct rcu_head rhead; |
59 | }; |
60 | |
61 | struct avc_xperms_decision_node { |
62 | struct extended_perms_decision xpd; |
63 | struct list_head xpd_list; /* list of extended_perms_decision */ |
64 | }; |
65 | |
66 | struct avc_xperms_node { |
67 | struct extended_perms xp; |
68 | struct list_head xpd_head; /* list head of extended_perms_decision */ |
69 | }; |
70 | |
71 | struct avc_cache { |
72 | struct hlist_head slots[AVC_CACHE_SLOTS]; /* head for avc_node->list */ |
73 | spinlock_t slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */ |
74 | atomic_t lru_hint; /* LRU hint for reclaim scan */ |
75 | atomic_t active_nodes; |
76 | u32 latest_notif; /* latest revocation notification */ |
77 | }; |
78 | |
79 | struct avc_callback_node { |
80 | int (*callback) (u32 event); |
81 | u32 events; |
82 | struct avc_callback_node *next; |
83 | }; |
84 | |
85 | #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS |
86 | DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 }; |
87 | #endif |
88 | |
89 | struct selinux_avc { |
90 | unsigned int avc_cache_threshold; |
91 | struct avc_cache avc_cache; |
92 | }; |
93 | |
94 | static struct selinux_avc selinux_avc; |
95 | |
96 | void selinux_avc_init(void) |
97 | { |
98 | int i; |
99 | |
100 | selinux_avc.avc_cache_threshold = AVC_DEF_CACHE_THRESHOLD; |
101 | for (i = 0; i < AVC_CACHE_SLOTS; i++) { |
102 | INIT_HLIST_HEAD(&selinux_avc.avc_cache.slots[i]); |
103 | spin_lock_init(&selinux_avc.avc_cache.slots_lock[i]); |
104 | } |
105 | atomic_set(v: &selinux_avc.avc_cache.active_nodes, i: 0); |
106 | atomic_set(v: &selinux_avc.avc_cache.lru_hint, i: 0); |
107 | } |
108 | |
109 | unsigned int avc_get_cache_threshold(void) |
110 | { |
111 | return selinux_avc.avc_cache_threshold; |
112 | } |
113 | |
114 | void avc_set_cache_threshold(unsigned int cache_threshold) |
115 | { |
116 | selinux_avc.avc_cache_threshold = cache_threshold; |
117 | } |
118 | |
119 | static struct avc_callback_node *avc_callbacks __ro_after_init; |
120 | static struct kmem_cache *avc_node_cachep __ro_after_init; |
121 | static struct kmem_cache *avc_xperms_data_cachep __ro_after_init; |
122 | static struct kmem_cache *avc_xperms_decision_cachep __ro_after_init; |
123 | static struct kmem_cache *avc_xperms_cachep __ro_after_init; |
124 | |
125 | static inline u32 avc_hash(u32 ssid, u32 tsid, u16 tclass) |
126 | { |
127 | return (ssid ^ (tsid<<2) ^ (tclass<<4)) & (AVC_CACHE_SLOTS - 1); |
128 | } |
129 | |
130 | /** |
131 | * avc_init - Initialize the AVC. |
132 | * |
133 | * Initialize the access vector cache. |
134 | */ |
135 | void __init avc_init(void) |
136 | { |
137 | avc_node_cachep = kmem_cache_create(name: "avc_node" , size: sizeof(struct avc_node), |
138 | align: 0, SLAB_PANIC, NULL); |
139 | avc_xperms_cachep = kmem_cache_create(name: "avc_xperms_node" , |
140 | size: sizeof(struct avc_xperms_node), |
141 | align: 0, SLAB_PANIC, NULL); |
142 | avc_xperms_decision_cachep = kmem_cache_create( |
143 | name: "avc_xperms_decision_node" , |
144 | size: sizeof(struct avc_xperms_decision_node), |
145 | align: 0, SLAB_PANIC, NULL); |
146 | avc_xperms_data_cachep = kmem_cache_create("avc_xperms_data" , |
147 | sizeof(struct extended_perms_data), |
148 | 0, SLAB_PANIC, NULL); |
149 | } |
150 | |
151 | int avc_get_hash_stats(char *page) |
152 | { |
153 | int i, chain_len, max_chain_len, slots_used; |
154 | struct avc_node *node; |
155 | struct hlist_head *head; |
156 | |
157 | rcu_read_lock(); |
158 | |
159 | slots_used = 0; |
160 | max_chain_len = 0; |
161 | for (i = 0; i < AVC_CACHE_SLOTS; i++) { |
162 | head = &selinux_avc.avc_cache.slots[i]; |
163 | if (!hlist_empty(h: head)) { |
164 | slots_used++; |
165 | chain_len = 0; |
166 | hlist_for_each_entry_rcu(node, head, list) |
167 | chain_len++; |
168 | if (chain_len > max_chain_len) |
169 | max_chain_len = chain_len; |
170 | } |
171 | } |
172 | |
173 | rcu_read_unlock(); |
174 | |
175 | return scnprintf(buf: page, PAGE_SIZE, fmt: "entries: %d\nbuckets used: %d/%d\n" |
176 | "longest chain: %d\n" , |
177 | atomic_read(v: &selinux_avc.avc_cache.active_nodes), |
178 | slots_used, AVC_CACHE_SLOTS, max_chain_len); |
179 | } |
180 | |
181 | /* |
182 | * using a linked list for extended_perms_decision lookup because the list is |
183 | * always small. i.e. less than 5, typically 1 |
184 | */ |
185 | static struct extended_perms_decision *avc_xperms_decision_lookup(u8 driver, |
186 | struct avc_xperms_node *xp_node) |
187 | { |
188 | struct avc_xperms_decision_node *xpd_node; |
189 | |
190 | list_for_each_entry(xpd_node, &xp_node->xpd_head, xpd_list) { |
191 | if (xpd_node->xpd.driver == driver) |
192 | return &xpd_node->xpd; |
193 | } |
194 | return NULL; |
195 | } |
196 | |
197 | static inline unsigned int |
198 | avc_xperms_has_perm(struct extended_perms_decision *xpd, |
199 | u8 perm, u8 which) |
200 | { |
201 | unsigned int rc = 0; |
202 | |
203 | if ((which == XPERMS_ALLOWED) && |
204 | (xpd->used & XPERMS_ALLOWED)) |
205 | rc = security_xperm_test(xpd->allowed->p, perm); |
206 | else if ((which == XPERMS_AUDITALLOW) && |
207 | (xpd->used & XPERMS_AUDITALLOW)) |
208 | rc = security_xperm_test(xpd->auditallow->p, perm); |
209 | else if ((which == XPERMS_DONTAUDIT) && |
210 | (xpd->used & XPERMS_DONTAUDIT)) |
211 | rc = security_xperm_test(xpd->dontaudit->p, perm); |
212 | return rc; |
213 | } |
214 | |
215 | static void avc_xperms_allow_perm(struct avc_xperms_node *xp_node, |
216 | u8 driver, u8 perm) |
217 | { |
218 | struct extended_perms_decision *xpd; |
219 | security_xperm_set(xp_node->xp.drivers.p, driver); |
220 | xpd = avc_xperms_decision_lookup(driver, xp_node); |
221 | if (xpd && xpd->allowed) |
222 | security_xperm_set(xpd->allowed->p, perm); |
223 | } |
224 | |
225 | static void avc_xperms_decision_free(struct avc_xperms_decision_node *xpd_node) |
226 | { |
227 | struct extended_perms_decision *xpd; |
228 | |
229 | xpd = &xpd_node->xpd; |
230 | if (xpd->allowed) |
231 | kmem_cache_free(s: avc_xperms_data_cachep, objp: xpd->allowed); |
232 | if (xpd->auditallow) |
233 | kmem_cache_free(s: avc_xperms_data_cachep, objp: xpd->auditallow); |
234 | if (xpd->dontaudit) |
235 | kmem_cache_free(s: avc_xperms_data_cachep, objp: xpd->dontaudit); |
236 | kmem_cache_free(s: avc_xperms_decision_cachep, objp: xpd_node); |
237 | } |
238 | |
239 | static void avc_xperms_free(struct avc_xperms_node *xp_node) |
240 | { |
241 | struct avc_xperms_decision_node *xpd_node, *tmp; |
242 | |
243 | if (!xp_node) |
244 | return; |
245 | |
246 | list_for_each_entry_safe(xpd_node, tmp, &xp_node->xpd_head, xpd_list) { |
247 | list_del(entry: &xpd_node->xpd_list); |
248 | avc_xperms_decision_free(xpd_node); |
249 | } |
250 | kmem_cache_free(s: avc_xperms_cachep, objp: xp_node); |
251 | } |
252 | |
253 | static void avc_copy_xperms_decision(struct extended_perms_decision *dest, |
254 | struct extended_perms_decision *src) |
255 | { |
256 | dest->driver = src->driver; |
257 | dest->used = src->used; |
258 | if (dest->used & XPERMS_ALLOWED) |
259 | memcpy(dest->allowed->p, src->allowed->p, |
260 | sizeof(src->allowed->p)); |
261 | if (dest->used & XPERMS_AUDITALLOW) |
262 | memcpy(dest->auditallow->p, src->auditallow->p, |
263 | sizeof(src->auditallow->p)); |
264 | if (dest->used & XPERMS_DONTAUDIT) |
265 | memcpy(dest->dontaudit->p, src->dontaudit->p, |
266 | sizeof(src->dontaudit->p)); |
267 | } |
268 | |
269 | /* |
270 | * similar to avc_copy_xperms_decision, but only copy decision |
271 | * information relevant to this perm |
272 | */ |
273 | static inline void avc_quick_copy_xperms_decision(u8 perm, |
274 | struct extended_perms_decision *dest, |
275 | struct extended_perms_decision *src) |
276 | { |
277 | /* |
278 | * compute index of the u32 of the 256 bits (8 u32s) that contain this |
279 | * command permission |
280 | */ |
281 | u8 i = perm >> 5; |
282 | |
283 | dest->used = src->used; |
284 | if (dest->used & XPERMS_ALLOWED) |
285 | dest->allowed->p[i] = src->allowed->p[i]; |
286 | if (dest->used & XPERMS_AUDITALLOW) |
287 | dest->auditallow->p[i] = src->auditallow->p[i]; |
288 | if (dest->used & XPERMS_DONTAUDIT) |
289 | dest->dontaudit->p[i] = src->dontaudit->p[i]; |
290 | } |
291 | |
292 | static struct avc_xperms_decision_node |
293 | *avc_xperms_decision_alloc(u8 which) |
294 | { |
295 | struct avc_xperms_decision_node *xpd_node; |
296 | struct extended_perms_decision *xpd; |
297 | |
298 | xpd_node = kmem_cache_zalloc(k: avc_xperms_decision_cachep, |
299 | GFP_NOWAIT | __GFP_NOWARN); |
300 | if (!xpd_node) |
301 | return NULL; |
302 | |
303 | xpd = &xpd_node->xpd; |
304 | if (which & XPERMS_ALLOWED) { |
305 | xpd->allowed = kmem_cache_zalloc(k: avc_xperms_data_cachep, |
306 | GFP_NOWAIT | __GFP_NOWARN); |
307 | if (!xpd->allowed) |
308 | goto error; |
309 | } |
310 | if (which & XPERMS_AUDITALLOW) { |
311 | xpd->auditallow = kmem_cache_zalloc(k: avc_xperms_data_cachep, |
312 | GFP_NOWAIT | __GFP_NOWARN); |
313 | if (!xpd->auditallow) |
314 | goto error; |
315 | } |
316 | if (which & XPERMS_DONTAUDIT) { |
317 | xpd->dontaudit = kmem_cache_zalloc(k: avc_xperms_data_cachep, |
318 | GFP_NOWAIT | __GFP_NOWARN); |
319 | if (!xpd->dontaudit) |
320 | goto error; |
321 | } |
322 | return xpd_node; |
323 | error: |
324 | avc_xperms_decision_free(xpd_node); |
325 | return NULL; |
326 | } |
327 | |
328 | static int avc_add_xperms_decision(struct avc_node *node, |
329 | struct extended_perms_decision *src) |
330 | { |
331 | struct avc_xperms_decision_node *dest_xpd; |
332 | |
333 | node->ae.xp_node->xp.len++; |
334 | dest_xpd = avc_xperms_decision_alloc(which: src->used); |
335 | if (!dest_xpd) |
336 | return -ENOMEM; |
337 | avc_copy_xperms_decision(dest: &dest_xpd->xpd, src); |
338 | list_add(new: &dest_xpd->xpd_list, head: &node->ae.xp_node->xpd_head); |
339 | return 0; |
340 | } |
341 | |
342 | static struct avc_xperms_node *avc_xperms_alloc(void) |
343 | { |
344 | struct avc_xperms_node *xp_node; |
345 | |
346 | xp_node = kmem_cache_zalloc(k: avc_xperms_cachep, GFP_NOWAIT | __GFP_NOWARN); |
347 | if (!xp_node) |
348 | return xp_node; |
349 | INIT_LIST_HEAD(list: &xp_node->xpd_head); |
350 | return xp_node; |
351 | } |
352 | |
353 | static int avc_xperms_populate(struct avc_node *node, |
354 | struct avc_xperms_node *src) |
355 | { |
356 | struct avc_xperms_node *dest; |
357 | struct avc_xperms_decision_node *dest_xpd; |
358 | struct avc_xperms_decision_node *src_xpd; |
359 | |
360 | if (src->xp.len == 0) |
361 | return 0; |
362 | dest = avc_xperms_alloc(); |
363 | if (!dest) |
364 | return -ENOMEM; |
365 | |
366 | memcpy(dest->xp.drivers.p, src->xp.drivers.p, sizeof(dest->xp.drivers.p)); |
367 | dest->xp.len = src->xp.len; |
368 | |
369 | /* for each source xpd allocate a destination xpd and copy */ |
370 | list_for_each_entry(src_xpd, &src->xpd_head, xpd_list) { |
371 | dest_xpd = avc_xperms_decision_alloc(which: src_xpd->xpd.used); |
372 | if (!dest_xpd) |
373 | goto error; |
374 | avc_copy_xperms_decision(dest: &dest_xpd->xpd, src: &src_xpd->xpd); |
375 | list_add(new: &dest_xpd->xpd_list, head: &dest->xpd_head); |
376 | } |
377 | node->ae.xp_node = dest; |
378 | return 0; |
379 | error: |
380 | avc_xperms_free(xp_node: dest); |
381 | return -ENOMEM; |
382 | |
383 | } |
384 | |
385 | static inline u32 avc_xperms_audit_required(u32 requested, |
386 | struct av_decision *avd, |
387 | struct extended_perms_decision *xpd, |
388 | u8 perm, |
389 | int result, |
390 | u32 *deniedp) |
391 | { |
392 | u32 denied, audited; |
393 | |
394 | denied = requested & ~avd->allowed; |
395 | if (unlikely(denied)) { |
396 | audited = denied & avd->auditdeny; |
397 | if (audited && xpd) { |
398 | if (avc_xperms_has_perm(xpd, perm, which: XPERMS_DONTAUDIT)) |
399 | audited &= ~requested; |
400 | } |
401 | } else if (result) { |
402 | audited = denied = requested; |
403 | } else { |
404 | audited = requested & avd->auditallow; |
405 | if (audited && xpd) { |
406 | if (!avc_xperms_has_perm(xpd, perm, which: XPERMS_AUDITALLOW)) |
407 | audited &= ~requested; |
408 | } |
409 | } |
410 | |
411 | *deniedp = denied; |
412 | return audited; |
413 | } |
414 | |
415 | static inline int avc_xperms_audit(u32 ssid, u32 tsid, u16 tclass, |
416 | u32 requested, struct av_decision *avd, |
417 | struct extended_perms_decision *xpd, |
418 | u8 perm, int result, |
419 | struct common_audit_data *ad) |
420 | { |
421 | u32 audited, denied; |
422 | |
423 | audited = avc_xperms_audit_required( |
424 | requested, avd, xpd, perm, result, deniedp: &denied); |
425 | if (likely(!audited)) |
426 | return 0; |
427 | return slow_avc_audit(ssid, tsid, tclass, requested, |
428 | audited, denied, result, ad); |
429 | } |
430 | |
431 | static void avc_node_free(struct rcu_head *rhead) |
432 | { |
433 | struct avc_node *node = container_of(rhead, struct avc_node, rhead); |
434 | avc_xperms_free(xp_node: node->ae.xp_node); |
435 | kmem_cache_free(s: avc_node_cachep, objp: node); |
436 | avc_cache_stats_incr(frees); |
437 | } |
438 | |
439 | static void avc_node_delete(struct avc_node *node) |
440 | { |
441 | hlist_del_rcu(n: &node->list); |
442 | call_rcu(head: &node->rhead, func: avc_node_free); |
443 | atomic_dec(v: &selinux_avc.avc_cache.active_nodes); |
444 | } |
445 | |
446 | static void avc_node_kill(struct avc_node *node) |
447 | { |
448 | avc_xperms_free(xp_node: node->ae.xp_node); |
449 | kmem_cache_free(s: avc_node_cachep, objp: node); |
450 | avc_cache_stats_incr(frees); |
451 | atomic_dec(v: &selinux_avc.avc_cache.active_nodes); |
452 | } |
453 | |
454 | static void avc_node_replace(struct avc_node *new, struct avc_node *old) |
455 | { |
456 | hlist_replace_rcu(old: &old->list, new: &new->list); |
457 | call_rcu(head: &old->rhead, func: avc_node_free); |
458 | atomic_dec(v: &selinux_avc.avc_cache.active_nodes); |
459 | } |
460 | |
461 | static inline int avc_reclaim_node(void) |
462 | { |
463 | struct avc_node *node; |
464 | int hvalue, try, ecx; |
465 | unsigned long flags; |
466 | struct hlist_head *head; |
467 | spinlock_t *lock; |
468 | |
469 | for (try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++) { |
470 | hvalue = atomic_inc_return(v: &selinux_avc.avc_cache.lru_hint) & |
471 | (AVC_CACHE_SLOTS - 1); |
472 | head = &selinux_avc.avc_cache.slots[hvalue]; |
473 | lock = &selinux_avc.avc_cache.slots_lock[hvalue]; |
474 | |
475 | if (!spin_trylock_irqsave(lock, flags)) |
476 | continue; |
477 | |
478 | rcu_read_lock(); |
479 | hlist_for_each_entry(node, head, list) { |
480 | avc_node_delete(node); |
481 | avc_cache_stats_incr(reclaims); |
482 | ecx++; |
483 | if (ecx >= AVC_CACHE_RECLAIM) { |
484 | rcu_read_unlock(); |
485 | spin_unlock_irqrestore(lock, flags); |
486 | goto out; |
487 | } |
488 | } |
489 | rcu_read_unlock(); |
490 | spin_unlock_irqrestore(lock, flags); |
491 | } |
492 | out: |
493 | return ecx; |
494 | } |
495 | |
496 | static struct avc_node *avc_alloc_node(void) |
497 | { |
498 | struct avc_node *node; |
499 | |
500 | node = kmem_cache_zalloc(k: avc_node_cachep, GFP_NOWAIT | __GFP_NOWARN); |
501 | if (!node) |
502 | goto out; |
503 | |
504 | INIT_HLIST_NODE(h: &node->list); |
505 | avc_cache_stats_incr(allocations); |
506 | |
507 | if (atomic_inc_return(v: &selinux_avc.avc_cache.active_nodes) > |
508 | selinux_avc.avc_cache_threshold) |
509 | avc_reclaim_node(); |
510 | |
511 | out: |
512 | return node; |
513 | } |
514 | |
515 | static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd) |
516 | { |
517 | node->ae.ssid = ssid; |
518 | node->ae.tsid = tsid; |
519 | node->ae.tclass = tclass; |
520 | memcpy(&node->ae.avd, avd, sizeof(node->ae.avd)); |
521 | } |
522 | |
523 | static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass) |
524 | { |
525 | struct avc_node *node, *ret = NULL; |
526 | u32 hvalue; |
527 | struct hlist_head *head; |
528 | |
529 | hvalue = avc_hash(ssid, tsid, tclass); |
530 | head = &selinux_avc.avc_cache.slots[hvalue]; |
531 | hlist_for_each_entry_rcu(node, head, list) { |
532 | if (ssid == node->ae.ssid && |
533 | tclass == node->ae.tclass && |
534 | tsid == node->ae.tsid) { |
535 | ret = node; |
536 | break; |
537 | } |
538 | } |
539 | |
540 | return ret; |
541 | } |
542 | |
543 | /** |
544 | * avc_lookup - Look up an AVC entry. |
545 | * @ssid: source security identifier |
546 | * @tsid: target security identifier |
547 | * @tclass: target security class |
548 | * |
549 | * Look up an AVC entry that is valid for the |
550 | * (@ssid, @tsid), interpreting the permissions |
551 | * based on @tclass. If a valid AVC entry exists, |
552 | * then this function returns the avc_node. |
553 | * Otherwise, this function returns NULL. |
554 | */ |
555 | static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass) |
556 | { |
557 | struct avc_node *node; |
558 | |
559 | avc_cache_stats_incr(lookups); |
560 | node = avc_search_node(ssid, tsid, tclass); |
561 | |
562 | if (node) |
563 | return node; |
564 | |
565 | avc_cache_stats_incr(misses); |
566 | return NULL; |
567 | } |
568 | |
569 | static int avc_latest_notif_update(u32 seqno, int is_insert) |
570 | { |
571 | int ret = 0; |
572 | static DEFINE_SPINLOCK(notif_lock); |
573 | unsigned long flag; |
574 | |
575 | spin_lock_irqsave(¬if_lock, flag); |
576 | if (is_insert) { |
577 | if (seqno < selinux_avc.avc_cache.latest_notif) { |
578 | pr_warn("SELinux: avc: seqno %d < latest_notif %d\n" , |
579 | seqno, selinux_avc.avc_cache.latest_notif); |
580 | ret = -EAGAIN; |
581 | } |
582 | } else { |
583 | if (seqno > selinux_avc.avc_cache.latest_notif) |
584 | selinux_avc.avc_cache.latest_notif = seqno; |
585 | } |
586 | spin_unlock_irqrestore(lock: ¬if_lock, flags: flag); |
587 | |
588 | return ret; |
589 | } |
590 | |
591 | /** |
592 | * avc_insert - Insert an AVC entry. |
593 | * @ssid: source security identifier |
594 | * @tsid: target security identifier |
595 | * @tclass: target security class |
596 | * @avd: resulting av decision |
597 | * @xp_node: resulting extended permissions |
598 | * |
599 | * Insert an AVC entry for the SID pair |
600 | * (@ssid, @tsid) and class @tclass. |
601 | * The access vectors and the sequence number are |
602 | * normally provided by the security server in |
603 | * response to a security_compute_av() call. If the |
604 | * sequence number @avd->seqno is not less than the latest |
605 | * revocation notification, then the function copies |
606 | * the access vectors into a cache entry. |
607 | */ |
608 | static void avc_insert(u32 ssid, u32 tsid, u16 tclass, |
609 | struct av_decision *avd, struct avc_xperms_node *xp_node) |
610 | { |
611 | struct avc_node *pos, *node = NULL; |
612 | u32 hvalue; |
613 | unsigned long flag; |
614 | spinlock_t *lock; |
615 | struct hlist_head *head; |
616 | |
617 | if (avc_latest_notif_update(seqno: avd->seqno, is_insert: 1)) |
618 | return; |
619 | |
620 | node = avc_alloc_node(); |
621 | if (!node) |
622 | return; |
623 | |
624 | avc_node_populate(node, ssid, tsid, tclass, avd); |
625 | if (avc_xperms_populate(node, src: xp_node)) { |
626 | avc_node_kill(node); |
627 | return; |
628 | } |
629 | |
630 | hvalue = avc_hash(ssid, tsid, tclass); |
631 | head = &selinux_avc.avc_cache.slots[hvalue]; |
632 | lock = &selinux_avc.avc_cache.slots_lock[hvalue]; |
633 | spin_lock_irqsave(lock, flag); |
634 | hlist_for_each_entry(pos, head, list) { |
635 | if (pos->ae.ssid == ssid && |
636 | pos->ae.tsid == tsid && |
637 | pos->ae.tclass == tclass) { |
638 | avc_node_replace(new: node, old: pos); |
639 | goto found; |
640 | } |
641 | } |
642 | hlist_add_head_rcu(n: &node->list, h: head); |
643 | found: |
644 | spin_unlock_irqrestore(lock, flags: flag); |
645 | } |
646 | |
647 | /** |
648 | * avc_audit_pre_callback - SELinux specific information |
649 | * will be called by generic audit code |
650 | * @ab: the audit buffer |
651 | * @a: audit_data |
652 | */ |
653 | static void avc_audit_pre_callback(struct audit_buffer *ab, void *a) |
654 | { |
655 | struct common_audit_data *ad = a; |
656 | struct selinux_audit_data *sad = ad->selinux_audit_data; |
657 | u32 av = sad->audited, perm; |
658 | const char *const *perms; |
659 | u32 i; |
660 | |
661 | audit_log_format(ab, fmt: "avc: %s " , sad->denied ? "denied" : "granted" ); |
662 | |
663 | if (av == 0) { |
664 | audit_log_format(ab, fmt: " null" ); |
665 | return; |
666 | } |
667 | |
668 | perms = secclass_map[sad->tclass-1].perms; |
669 | |
670 | audit_log_format(ab, fmt: " {" ); |
671 | i = 0; |
672 | perm = 1; |
673 | while (i < (sizeof(av) * 8)) { |
674 | if ((perm & av) && perms[i]) { |
675 | audit_log_format(ab, fmt: " %s" , perms[i]); |
676 | av &= ~perm; |
677 | } |
678 | i++; |
679 | perm <<= 1; |
680 | } |
681 | |
682 | if (av) |
683 | audit_log_format(ab, fmt: " 0x%x" , av); |
684 | |
685 | audit_log_format(ab, fmt: " } for " ); |
686 | } |
687 | |
688 | /** |
689 | * avc_audit_post_callback - SELinux specific information |
690 | * will be called by generic audit code |
691 | * @ab: the audit buffer |
692 | * @a: audit_data |
693 | */ |
694 | static void avc_audit_post_callback(struct audit_buffer *ab, void *a) |
695 | { |
696 | struct common_audit_data *ad = a; |
697 | struct selinux_audit_data *sad = ad->selinux_audit_data; |
698 | char *scontext = NULL; |
699 | char *tcontext = NULL; |
700 | const char *tclass = NULL; |
701 | u32 scontext_len; |
702 | u32 tcontext_len; |
703 | int rc; |
704 | |
705 | rc = security_sid_to_context(sad->ssid, &scontext, |
706 | &scontext_len); |
707 | if (rc) |
708 | audit_log_format(ab, fmt: " ssid=%d" , sad->ssid); |
709 | else |
710 | audit_log_format(ab, fmt: " scontext=%s" , scontext); |
711 | |
712 | rc = security_sid_to_context(sad->tsid, &tcontext, |
713 | &tcontext_len); |
714 | if (rc) |
715 | audit_log_format(ab, fmt: " tsid=%d" , sad->tsid); |
716 | else |
717 | audit_log_format(ab, fmt: " tcontext=%s" , tcontext); |
718 | |
719 | tclass = secclass_map[sad->tclass-1].name; |
720 | audit_log_format(ab, fmt: " tclass=%s" , tclass); |
721 | |
722 | if (sad->denied) |
723 | audit_log_format(ab, fmt: " permissive=%u" , sad->result ? 0 : 1); |
724 | |
725 | trace_selinux_audited(sad, scontext, tcontext, tclass); |
726 | kfree(objp: tcontext); |
727 | kfree(objp: scontext); |
728 | |
729 | /* in case of invalid context report also the actual context string */ |
730 | rc = security_sid_to_context_inval(sad->ssid, &scontext, |
731 | &scontext_len); |
732 | if (!rc && scontext) { |
733 | if (scontext_len && scontext[scontext_len - 1] == '\0') |
734 | scontext_len--; |
735 | audit_log_format(ab, fmt: " srawcon=" ); |
736 | audit_log_n_untrustedstring(ab, string: scontext, n: scontext_len); |
737 | kfree(objp: scontext); |
738 | } |
739 | |
740 | rc = security_sid_to_context_inval(sad->tsid, &scontext, |
741 | &scontext_len); |
742 | if (!rc && scontext) { |
743 | if (scontext_len && scontext[scontext_len - 1] == '\0') |
744 | scontext_len--; |
745 | audit_log_format(ab, fmt: " trawcon=" ); |
746 | audit_log_n_untrustedstring(ab, string: scontext, n: scontext_len); |
747 | kfree(objp: scontext); |
748 | } |
749 | } |
750 | |
751 | /* |
752 | * This is the slow part of avc audit with big stack footprint. |
753 | * Note that it is non-blocking and can be called from under |
754 | * rcu_read_lock(). |
755 | */ |
756 | noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, |
757 | u32 requested, u32 audited, u32 denied, int result, |
758 | struct common_audit_data *a) |
759 | { |
760 | struct common_audit_data stack_data; |
761 | struct selinux_audit_data sad; |
762 | |
763 | if (WARN_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map))) |
764 | return -EINVAL; |
765 | |
766 | if (!a) { |
767 | a = &stack_data; |
768 | a->type = LSM_AUDIT_DATA_NONE; |
769 | } |
770 | |
771 | sad.tclass = tclass; |
772 | sad.requested = requested; |
773 | sad.ssid = ssid; |
774 | sad.tsid = tsid; |
775 | sad.audited = audited; |
776 | sad.denied = denied; |
777 | sad.result = result; |
778 | |
779 | a->selinux_audit_data = &sad; |
780 | |
781 | common_lsm_audit(a, avc_audit_pre_callback, avc_audit_post_callback); |
782 | return 0; |
783 | } |
784 | |
785 | /** |
786 | * avc_add_callback - Register a callback for security events. |
787 | * @callback: callback function |
788 | * @events: security events |
789 | * |
790 | * Register a callback function for events in the set @events. |
791 | * Returns %0 on success or -%ENOMEM if insufficient memory |
792 | * exists to add the callback. |
793 | */ |
794 | int __init avc_add_callback(int (*callback)(u32 event), u32 events) |
795 | { |
796 | struct avc_callback_node *c; |
797 | int rc = 0; |
798 | |
799 | c = kmalloc(size: sizeof(*c), GFP_KERNEL); |
800 | if (!c) { |
801 | rc = -ENOMEM; |
802 | goto out; |
803 | } |
804 | |
805 | c->callback = callback; |
806 | c->events = events; |
807 | c->next = avc_callbacks; |
808 | avc_callbacks = c; |
809 | out: |
810 | return rc; |
811 | } |
812 | |
813 | /** |
814 | * avc_update_node - Update an AVC entry |
815 | * @event : Updating event |
816 | * @perms : Permission mask bits |
817 | * @driver: xperm driver information |
818 | * @xperm: xperm permissions |
819 | * @ssid: AVC entry source sid |
820 | * @tsid: AVC entry target sid |
821 | * @tclass : AVC entry target object class |
822 | * @seqno : sequence number when decision was made |
823 | * @xpd: extended_perms_decision to be added to the node |
824 | * @flags: the AVC_* flags, e.g. AVC_EXTENDED_PERMS, or 0. |
825 | * |
826 | * if a valid AVC entry doesn't exist,this function returns -ENOENT. |
827 | * if kmalloc() called internal returns NULL, this function returns -ENOMEM. |
828 | * otherwise, this function updates the AVC entry. The original AVC-entry object |
829 | * will release later by RCU. |
830 | */ |
831 | static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, |
832 | u32 tsid, u16 tclass, u32 seqno, |
833 | struct extended_perms_decision *xpd, |
834 | u32 flags) |
835 | { |
836 | u32 hvalue; |
837 | int rc = 0; |
838 | unsigned long flag; |
839 | struct avc_node *pos, *node, *orig = NULL; |
840 | struct hlist_head *head; |
841 | spinlock_t *lock; |
842 | |
843 | node = avc_alloc_node(); |
844 | if (!node) { |
845 | rc = -ENOMEM; |
846 | goto out; |
847 | } |
848 | |
849 | /* Lock the target slot */ |
850 | hvalue = avc_hash(ssid, tsid, tclass); |
851 | |
852 | head = &selinux_avc.avc_cache.slots[hvalue]; |
853 | lock = &selinux_avc.avc_cache.slots_lock[hvalue]; |
854 | |
855 | spin_lock_irqsave(lock, flag); |
856 | |
857 | hlist_for_each_entry(pos, head, list) { |
858 | if (ssid == pos->ae.ssid && |
859 | tsid == pos->ae.tsid && |
860 | tclass == pos->ae.tclass && |
861 | seqno == pos->ae.avd.seqno){ |
862 | orig = pos; |
863 | break; |
864 | } |
865 | } |
866 | |
867 | if (!orig) { |
868 | rc = -ENOENT; |
869 | avc_node_kill(node); |
870 | goto out_unlock; |
871 | } |
872 | |
873 | /* |
874 | * Copy and replace original node. |
875 | */ |
876 | |
877 | avc_node_populate(node, ssid, tsid, tclass, avd: &orig->ae.avd); |
878 | |
879 | if (orig->ae.xp_node) { |
880 | rc = avc_xperms_populate(node, src: orig->ae.xp_node); |
881 | if (rc) { |
882 | avc_node_kill(node); |
883 | goto out_unlock; |
884 | } |
885 | } |
886 | |
887 | switch (event) { |
888 | case AVC_CALLBACK_GRANT: |
889 | node->ae.avd.allowed |= perms; |
890 | if (node->ae.xp_node && (flags & AVC_EXTENDED_PERMS)) |
891 | avc_xperms_allow_perm(xp_node: node->ae.xp_node, driver, perm: xperm); |
892 | break; |
893 | case AVC_CALLBACK_TRY_REVOKE: |
894 | case AVC_CALLBACK_REVOKE: |
895 | node->ae.avd.allowed &= ~perms; |
896 | break; |
897 | case AVC_CALLBACK_AUDITALLOW_ENABLE: |
898 | node->ae.avd.auditallow |= perms; |
899 | break; |
900 | case AVC_CALLBACK_AUDITALLOW_DISABLE: |
901 | node->ae.avd.auditallow &= ~perms; |
902 | break; |
903 | case AVC_CALLBACK_AUDITDENY_ENABLE: |
904 | node->ae.avd.auditdeny |= perms; |
905 | break; |
906 | case AVC_CALLBACK_AUDITDENY_DISABLE: |
907 | node->ae.avd.auditdeny &= ~perms; |
908 | break; |
909 | case AVC_CALLBACK_ADD_XPERMS: |
910 | avc_add_xperms_decision(node, src: xpd); |
911 | break; |
912 | } |
913 | avc_node_replace(new: node, old: orig); |
914 | out_unlock: |
915 | spin_unlock_irqrestore(lock, flags: flag); |
916 | out: |
917 | return rc; |
918 | } |
919 | |
920 | /** |
921 | * avc_flush - Flush the cache |
922 | */ |
923 | static void avc_flush(void) |
924 | { |
925 | struct hlist_head *head; |
926 | struct avc_node *node; |
927 | spinlock_t *lock; |
928 | unsigned long flag; |
929 | int i; |
930 | |
931 | for (i = 0; i < AVC_CACHE_SLOTS; i++) { |
932 | head = &selinux_avc.avc_cache.slots[i]; |
933 | lock = &selinux_avc.avc_cache.slots_lock[i]; |
934 | |
935 | spin_lock_irqsave(lock, flag); |
936 | /* |
937 | * With preemptable RCU, the outer spinlock does not |
938 | * prevent RCU grace periods from ending. |
939 | */ |
940 | rcu_read_lock(); |
941 | hlist_for_each_entry(node, head, list) |
942 | avc_node_delete(node); |
943 | rcu_read_unlock(); |
944 | spin_unlock_irqrestore(lock, flags: flag); |
945 | } |
946 | } |
947 | |
948 | /** |
949 | * avc_ss_reset - Flush the cache and revalidate migrated permissions. |
950 | * @seqno: policy sequence number |
951 | */ |
952 | int avc_ss_reset(u32 seqno) |
953 | { |
954 | struct avc_callback_node *c; |
955 | int rc = 0, tmprc; |
956 | |
957 | avc_flush(); |
958 | |
959 | for (c = avc_callbacks; c; c = c->next) { |
960 | if (c->events & AVC_CALLBACK_RESET) { |
961 | tmprc = c->callback(AVC_CALLBACK_RESET); |
962 | /* save the first error encountered for the return |
963 | value and continue processing the callbacks */ |
964 | if (!rc) |
965 | rc = tmprc; |
966 | } |
967 | } |
968 | |
969 | avc_latest_notif_update(seqno, is_insert: 0); |
970 | return rc; |
971 | } |
972 | |
973 | /** |
974 | * avc_compute_av - Add an entry to the AVC based on the security policy |
975 | * @ssid: subject |
976 | * @tsid: object/target |
977 | * @tclass: object class |
978 | * @avd: access vector decision |
979 | * @xp_node: AVC extended permissions node |
980 | * |
981 | * Slow-path helper function for avc_has_perm_noaudit, when the avc_node lookup |
982 | * fails. Don't inline this, since it's the slow-path and just results in a |
983 | * bigger stack frame. |
984 | */ |
985 | static noinline void avc_compute_av(u32 ssid, u32 tsid, u16 tclass, |
986 | struct av_decision *avd, |
987 | struct avc_xperms_node *xp_node) |
988 | { |
989 | INIT_LIST_HEAD(list: &xp_node->xpd_head); |
990 | security_compute_av(ssid, tsid, tclass, avd, &xp_node->xp); |
991 | avc_insert(ssid, tsid, tclass, avd, xp_node); |
992 | } |
993 | |
994 | static noinline int avc_denied(u32 ssid, u32 tsid, |
995 | u16 tclass, u32 requested, |
996 | u8 driver, u8 xperm, unsigned int flags, |
997 | struct av_decision *avd) |
998 | { |
999 | if (flags & AVC_STRICT) |
1000 | return -EACCES; |
1001 | |
1002 | if (enforcing_enabled() && |
1003 | !(avd->flags & AVD_FLAGS_PERMISSIVE)) |
1004 | return -EACCES; |
1005 | |
1006 | avc_update_node(AVC_CALLBACK_GRANT, requested, driver, |
1007 | xperm, ssid, tsid, tclass, avd->seqno, NULL, flags); |
1008 | return 0; |
1009 | } |
1010 | |
1011 | /* |
1012 | * The avc extended permissions logic adds an additional 256 bits of |
1013 | * permissions to an avc node when extended permissions for that node are |
1014 | * specified in the avtab. If the additional 256 permissions is not adequate, |
1015 | * as-is the case with ioctls, then multiple may be chained together and the |
1016 | * driver field is used to specify which set contains the permission. |
1017 | */ |
1018 | int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, |
1019 | u8 driver, u8 xperm, struct common_audit_data *ad) |
1020 | { |
1021 | struct avc_node *node; |
1022 | struct av_decision avd; |
1023 | u32 denied; |
1024 | struct extended_perms_decision local_xpd; |
1025 | struct extended_perms_decision *xpd = NULL; |
1026 | struct extended_perms_data allowed; |
1027 | struct extended_perms_data auditallow; |
1028 | struct extended_perms_data dontaudit; |
1029 | struct avc_xperms_node local_xp_node; |
1030 | struct avc_xperms_node *xp_node; |
1031 | int rc = 0, rc2; |
1032 | |
1033 | xp_node = &local_xp_node; |
1034 | if (WARN_ON(!requested)) |
1035 | return -EACCES; |
1036 | |
1037 | rcu_read_lock(); |
1038 | |
1039 | node = avc_lookup(ssid, tsid, tclass); |
1040 | if (unlikely(!node)) { |
1041 | avc_compute_av(ssid, tsid, tclass, avd: &avd, xp_node); |
1042 | } else { |
1043 | memcpy(&avd, &node->ae.avd, sizeof(avd)); |
1044 | xp_node = node->ae.xp_node; |
1045 | } |
1046 | /* if extended permissions are not defined, only consider av_decision */ |
1047 | if (!xp_node || !xp_node->xp.len) |
1048 | goto decision; |
1049 | |
1050 | local_xpd.allowed = &allowed; |
1051 | local_xpd.auditallow = &auditallow; |
1052 | local_xpd.dontaudit = &dontaudit; |
1053 | |
1054 | xpd = avc_xperms_decision_lookup(driver, xp_node); |
1055 | if (unlikely(!xpd)) { |
1056 | /* |
1057 | * Compute the extended_perms_decision only if the driver |
1058 | * is flagged |
1059 | */ |
1060 | if (!security_xperm_test(xp_node->xp.drivers.p, driver)) { |
1061 | avd.allowed &= ~requested; |
1062 | goto decision; |
1063 | } |
1064 | rcu_read_unlock(); |
1065 | security_compute_xperms_decision(ssid, tsid, tclass, |
1066 | driver, &local_xpd); |
1067 | rcu_read_lock(); |
1068 | avc_update_node(AVC_CALLBACK_ADD_XPERMS, requested, |
1069 | driver, xperm, ssid, tsid, tclass, avd.seqno, |
1070 | &local_xpd, 0); |
1071 | } else { |
1072 | avc_quick_copy_xperms_decision(perm: xperm, dest: &local_xpd, src: xpd); |
1073 | } |
1074 | xpd = &local_xpd; |
1075 | |
1076 | if (!avc_xperms_has_perm(xpd, xperm, XPERMS_ALLOWED)) |
1077 | avd.allowed &= ~requested; |
1078 | |
1079 | decision: |
1080 | denied = requested & ~(avd.allowed); |
1081 | if (unlikely(denied)) |
1082 | rc = avc_denied(ssid, tsid, tclass, requested, |
1083 | driver, xperm, AVC_EXTENDED_PERMS, &avd); |
1084 | |
1085 | rcu_read_unlock(); |
1086 | |
1087 | rc2 = avc_xperms_audit(ssid, tsid, tclass, requested, |
1088 | avd: &avd, xpd, perm: xperm, result: rc, ad); |
1089 | if (rc2) |
1090 | return rc2; |
1091 | return rc; |
1092 | } |
1093 | |
1094 | /** |
1095 | * avc_perm_nonode - Add an entry to the AVC |
1096 | * @ssid: subject |
1097 | * @tsid: object/target |
1098 | * @tclass: object class |
1099 | * @requested: requested permissions |
1100 | * @flags: AVC flags |
1101 | * @avd: access vector decision |
1102 | * |
1103 | * This is the "we have no node" part of avc_has_perm_noaudit(), which is |
1104 | * unlikely and needs extra stack space for the new node that we generate, so |
1105 | * don't inline it. |
1106 | */ |
1107 | static noinline int avc_perm_nonode(u32 ssid, u32 tsid, u16 tclass, |
1108 | u32 requested, unsigned int flags, |
1109 | struct av_decision *avd) |
1110 | { |
1111 | u32 denied; |
1112 | struct avc_xperms_node xp_node; |
1113 | |
1114 | avc_compute_av(ssid, tsid, tclass, avd, xp_node: &xp_node); |
1115 | denied = requested & ~(avd->allowed); |
1116 | if (unlikely(denied)) |
1117 | return avc_denied(ssid, tsid, tclass, requested, driver: 0, xperm: 0, |
1118 | flags, avd); |
1119 | return 0; |
1120 | } |
1121 | |
1122 | /** |
1123 | * avc_has_perm_noaudit - Check permissions but perform no auditing. |
1124 | * @ssid: source security identifier |
1125 | * @tsid: target security identifier |
1126 | * @tclass: target security class |
1127 | * @requested: requested permissions, interpreted based on @tclass |
1128 | * @flags: AVC_STRICT or 0 |
1129 | * @avd: access vector decisions |
1130 | * |
1131 | * Check the AVC to determine whether the @requested permissions are granted |
1132 | * for the SID pair (@ssid, @tsid), interpreting the permissions |
1133 | * based on @tclass, and call the security server on a cache miss to obtain |
1134 | * a new decision and add it to the cache. Return a copy of the decisions |
1135 | * in @avd. Return %0 if all @requested permissions are granted, |
1136 | * -%EACCES if any permissions are denied, or another -errno upon |
1137 | * other errors. This function is typically called by avc_has_perm(), |
1138 | * but may also be called directly to separate permission checking from |
1139 | * auditing, e.g. in cases where a lock must be held for the check but |
1140 | * should be released for the auditing. |
1141 | */ |
1142 | inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, |
1143 | u16 tclass, u32 requested, |
1144 | unsigned int flags, |
1145 | struct av_decision *avd) |
1146 | { |
1147 | u32 denied; |
1148 | struct avc_node *node; |
1149 | |
1150 | if (WARN_ON(!requested)) |
1151 | return -EACCES; |
1152 | |
1153 | rcu_read_lock(); |
1154 | node = avc_lookup(ssid, tsid, tclass); |
1155 | if (unlikely(!node)) { |
1156 | rcu_read_unlock(); |
1157 | return avc_perm_nonode(ssid, tsid, tclass, requested, |
1158 | flags, avd); |
1159 | } |
1160 | denied = requested & ~node->ae.avd.allowed; |
1161 | memcpy(avd, &node->ae.avd, sizeof(*avd)); |
1162 | rcu_read_unlock(); |
1163 | |
1164 | if (unlikely(denied)) |
1165 | return avc_denied(ssid, tsid, tclass, requested, driver: 0, xperm: 0, |
1166 | flags, avd); |
1167 | return 0; |
1168 | } |
1169 | |
1170 | /** |
1171 | * avc_has_perm - Check permissions and perform any appropriate auditing. |
1172 | * @ssid: source security identifier |
1173 | * @tsid: target security identifier |
1174 | * @tclass: target security class |
1175 | * @requested: requested permissions, interpreted based on @tclass |
1176 | * @auditdata: auxiliary audit data |
1177 | * |
1178 | * Check the AVC to determine whether the @requested permissions are granted |
1179 | * for the SID pair (@ssid, @tsid), interpreting the permissions |
1180 | * based on @tclass, and call the security server on a cache miss to obtain |
1181 | * a new decision and add it to the cache. Audit the granting or denial of |
1182 | * permissions in accordance with the policy. Return %0 if all @requested |
1183 | * permissions are granted, -%EACCES if any permissions are denied, or |
1184 | * another -errno upon other errors. |
1185 | */ |
1186 | int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, |
1187 | u32 requested, struct common_audit_data *auditdata) |
1188 | { |
1189 | struct av_decision avd; |
1190 | int rc, rc2; |
1191 | |
1192 | rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, flags: 0, |
1193 | avd: &avd); |
1194 | |
1195 | rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, |
1196 | auditdata); |
1197 | if (rc2) |
1198 | return rc2; |
1199 | return rc; |
1200 | } |
1201 | |
1202 | u32 avc_policy_seqno(void) |
1203 | { |
1204 | return selinux_avc.avc_cache.latest_notif; |
1205 | } |
1206 | |