diff options
Diffstat (limited to 'security/selinux/avc.c')
-rw-r--r-- | security/selinux/avc.c | 282 |
1 files changed, 163 insertions, 119 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 2380b8d72cec..f3aedf077509 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -82,14 +82,42 @@ struct avc_callback_node { | |||
82 | struct avc_callback_node *next; | 82 | struct avc_callback_node *next; |
83 | }; | 83 | }; |
84 | 84 | ||
85 | /* Exported via selinufs */ | ||
86 | unsigned int avc_cache_threshold = AVC_DEF_CACHE_THRESHOLD; | ||
87 | |||
88 | #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS | 85 | #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS |
89 | DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 }; | 86 | DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 }; |
90 | #endif | 87 | #endif |
91 | 88 | ||
92 | static struct avc_cache avc_cache; | 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(struct selinux_avc **avc) | ||
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(&selinux_avc.avc_cache.active_nodes, 0); | ||
106 | atomic_set(&selinux_avc.avc_cache.lru_hint, 0); | ||
107 | *avc = &selinux_avc; | ||
108 | } | ||
109 | |||
110 | unsigned int avc_get_cache_threshold(struct selinux_avc *avc) | ||
111 | { | ||
112 | return avc->avc_cache_threshold; | ||
113 | } | ||
114 | |||
115 | void avc_set_cache_threshold(struct selinux_avc *avc, | ||
116 | unsigned int cache_threshold) | ||
117 | { | ||
118 | avc->avc_cache_threshold = cache_threshold; | ||
119 | } | ||
120 | |||
93 | static struct avc_callback_node *avc_callbacks; | 121 | static struct avc_callback_node *avc_callbacks; |
94 | static struct kmem_cache *avc_node_cachep; | 122 | static struct kmem_cache *avc_node_cachep; |
95 | static struct kmem_cache *avc_xperms_data_cachep; | 123 | static struct kmem_cache *avc_xperms_data_cachep; |
@@ -143,13 +171,14 @@ static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) | |||
143 | * @tsid: target security identifier | 171 | * @tsid: target security identifier |
144 | * @tclass: target security class | 172 | * @tclass: target security class |
145 | */ | 173 | */ |
146 | static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tclass) | 174 | static void avc_dump_query(struct audit_buffer *ab, struct selinux_state *state, |
175 | u32 ssid, u32 tsid, u16 tclass) | ||
147 | { | 176 | { |
148 | int rc; | 177 | int rc; |
149 | char *scontext; | 178 | char *scontext; |
150 | u32 scontext_len; | 179 | u32 scontext_len; |
151 | 180 | ||
152 | rc = security_sid_to_context(ssid, &scontext, &scontext_len); | 181 | rc = security_sid_to_context(state, ssid, &scontext, &scontext_len); |
153 | if (rc) | 182 | if (rc) |
154 | audit_log_format(ab, "ssid=%d", ssid); | 183 | audit_log_format(ab, "ssid=%d", ssid); |
155 | else { | 184 | else { |
@@ -157,7 +186,7 @@ static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tcla | |||
157 | kfree(scontext); | 186 | kfree(scontext); |
158 | } | 187 | } |
159 | 188 | ||
160 | rc = security_sid_to_context(tsid, &scontext, &scontext_len); | 189 | rc = security_sid_to_context(state, tsid, &scontext, &scontext_len); |
161 | if (rc) | 190 | if (rc) |
162 | audit_log_format(ab, " tsid=%d", tsid); | 191 | audit_log_format(ab, " tsid=%d", tsid); |
163 | else { | 192 | else { |
@@ -176,15 +205,6 @@ static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tcla | |||
176 | */ | 205 | */ |
177 | void __init avc_init(void) | 206 | void __init avc_init(void) |
178 | { | 207 | { |
179 | int i; | ||
180 | |||
181 | for (i = 0; i < AVC_CACHE_SLOTS; i++) { | ||
182 | INIT_HLIST_HEAD(&avc_cache.slots[i]); | ||
183 | spin_lock_init(&avc_cache.slots_lock[i]); | ||
184 | } | ||
185 | atomic_set(&avc_cache.active_nodes, 0); | ||
186 | atomic_set(&avc_cache.lru_hint, 0); | ||
187 | |||
188 | avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), | 208 | avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), |
189 | 0, SLAB_PANIC, NULL); | 209 | 0, SLAB_PANIC, NULL); |
190 | avc_xperms_cachep = kmem_cache_create("avc_xperms_node", | 210 | avc_xperms_cachep = kmem_cache_create("avc_xperms_node", |
@@ -199,7 +219,7 @@ void __init avc_init(void) | |||
199 | 0, SLAB_PANIC, NULL); | 219 | 0, SLAB_PANIC, NULL); |
200 | } | 220 | } |
201 | 221 | ||
202 | int avc_get_hash_stats(char *page) | 222 | int avc_get_hash_stats(struct selinux_avc *avc, char *page) |
203 | { | 223 | { |
204 | int i, chain_len, max_chain_len, slots_used; | 224 | int i, chain_len, max_chain_len, slots_used; |
205 | struct avc_node *node; | 225 | struct avc_node *node; |
@@ -210,7 +230,7 @@ int avc_get_hash_stats(char *page) | |||
210 | slots_used = 0; | 230 | slots_used = 0; |
211 | max_chain_len = 0; | 231 | max_chain_len = 0; |
212 | for (i = 0; i < AVC_CACHE_SLOTS; i++) { | 232 | for (i = 0; i < AVC_CACHE_SLOTS; i++) { |
213 | head = &avc_cache.slots[i]; | 233 | head = &avc->avc_cache.slots[i]; |
214 | if (!hlist_empty(head)) { | 234 | if (!hlist_empty(head)) { |
215 | slots_used++; | 235 | slots_used++; |
216 | chain_len = 0; | 236 | chain_len = 0; |
@@ -225,7 +245,7 @@ int avc_get_hash_stats(char *page) | |||
225 | 245 | ||
226 | return scnprintf(page, PAGE_SIZE, "entries: %d\nbuckets used: %d/%d\n" | 246 | return scnprintf(page, PAGE_SIZE, "entries: %d\nbuckets used: %d/%d\n" |
227 | "longest chain: %d\n", | 247 | "longest chain: %d\n", |
228 | atomic_read(&avc_cache.active_nodes), | 248 | atomic_read(&avc->avc_cache.active_nodes), |
229 | slots_used, AVC_CACHE_SLOTS, max_chain_len); | 249 | slots_used, AVC_CACHE_SLOTS, max_chain_len); |
230 | } | 250 | } |
231 | 251 | ||
@@ -462,11 +482,12 @@ static inline u32 avc_xperms_audit_required(u32 requested, | |||
462 | return audited; | 482 | return audited; |
463 | } | 483 | } |
464 | 484 | ||
465 | static inline int avc_xperms_audit(u32 ssid, u32 tsid, u16 tclass, | 485 | static inline int avc_xperms_audit(struct selinux_state *state, |
466 | u32 requested, struct av_decision *avd, | 486 | u32 ssid, u32 tsid, u16 tclass, |
467 | struct extended_perms_decision *xpd, | 487 | u32 requested, struct av_decision *avd, |
468 | u8 perm, int result, | 488 | struct extended_perms_decision *xpd, |
469 | struct common_audit_data *ad) | 489 | u8 perm, int result, |
490 | struct common_audit_data *ad) | ||
470 | { | 491 | { |
471 | u32 audited, denied; | 492 | u32 audited, denied; |
472 | 493 | ||
@@ -474,7 +495,7 @@ static inline int avc_xperms_audit(u32 ssid, u32 tsid, u16 tclass, | |||
474 | requested, avd, xpd, perm, result, &denied); | 495 | requested, avd, xpd, perm, result, &denied); |
475 | if (likely(!audited)) | 496 | if (likely(!audited)) |
476 | return 0; | 497 | return 0; |
477 | return slow_avc_audit(ssid, tsid, tclass, requested, | 498 | return slow_avc_audit(state, ssid, tsid, tclass, requested, |
478 | audited, denied, result, ad, 0); | 499 | audited, denied, result, ad, 0); |
479 | } | 500 | } |
480 | 501 | ||
@@ -486,29 +507,30 @@ static void avc_node_free(struct rcu_head *rhead) | |||
486 | avc_cache_stats_incr(frees); | 507 | avc_cache_stats_incr(frees); |
487 | } | 508 | } |
488 | 509 | ||
489 | static void avc_node_delete(struct avc_node *node) | 510 | static void avc_node_delete(struct selinux_avc *avc, struct avc_node *node) |
490 | { | 511 | { |
491 | hlist_del_rcu(&node->list); | 512 | hlist_del_rcu(&node->list); |
492 | call_rcu(&node->rhead, avc_node_free); | 513 | call_rcu(&node->rhead, avc_node_free); |
493 | atomic_dec(&avc_cache.active_nodes); | 514 | atomic_dec(&avc->avc_cache.active_nodes); |
494 | } | 515 | } |
495 | 516 | ||
496 | static void avc_node_kill(struct avc_node *node) | 517 | static void avc_node_kill(struct selinux_avc *avc, struct avc_node *node) |
497 | { | 518 | { |
498 | avc_xperms_free(node->ae.xp_node); | 519 | avc_xperms_free(node->ae.xp_node); |
499 | kmem_cache_free(avc_node_cachep, node); | 520 | kmem_cache_free(avc_node_cachep, node); |
500 | avc_cache_stats_incr(frees); | 521 | avc_cache_stats_incr(frees); |
501 | atomic_dec(&avc_cache.active_nodes); | 522 | atomic_dec(&avc->avc_cache.active_nodes); |
502 | } | 523 | } |
503 | 524 | ||
504 | static void avc_node_replace(struct avc_node *new, struct avc_node *old) | 525 | static void avc_node_replace(struct selinux_avc *avc, |
526 | struct avc_node *new, struct avc_node *old) | ||
505 | { | 527 | { |
506 | hlist_replace_rcu(&old->list, &new->list); | 528 | hlist_replace_rcu(&old->list, &new->list); |
507 | call_rcu(&old->rhead, avc_node_free); | 529 | call_rcu(&old->rhead, avc_node_free); |
508 | atomic_dec(&avc_cache.active_nodes); | 530 | atomic_dec(&avc->avc_cache.active_nodes); |
509 | } | 531 | } |
510 | 532 | ||
511 | static inline int avc_reclaim_node(void) | 533 | static inline int avc_reclaim_node(struct selinux_avc *avc) |
512 | { | 534 | { |
513 | struct avc_node *node; | 535 | struct avc_node *node; |
514 | int hvalue, try, ecx; | 536 | int hvalue, try, ecx; |
@@ -517,16 +539,17 @@ static inline int avc_reclaim_node(void) | |||
517 | spinlock_t *lock; | 539 | spinlock_t *lock; |
518 | 540 | ||
519 | for (try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++) { | 541 | for (try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++) { |
520 | hvalue = atomic_inc_return(&avc_cache.lru_hint) & (AVC_CACHE_SLOTS - 1); | 542 | hvalue = atomic_inc_return(&avc->avc_cache.lru_hint) & |
521 | head = &avc_cache.slots[hvalue]; | 543 | (AVC_CACHE_SLOTS - 1); |
522 | lock = &avc_cache.slots_lock[hvalue]; | 544 | head = &avc->avc_cache.slots[hvalue]; |
545 | lock = &avc->avc_cache.slots_lock[hvalue]; | ||
523 | 546 | ||
524 | if (!spin_trylock_irqsave(lock, flags)) | 547 | if (!spin_trylock_irqsave(lock, flags)) |
525 | continue; | 548 | continue; |
526 | 549 | ||
527 | rcu_read_lock(); | 550 | rcu_read_lock(); |
528 | hlist_for_each_entry(node, head, list) { | 551 | hlist_for_each_entry(node, head, list) { |
529 | avc_node_delete(node); | 552 | avc_node_delete(avc, node); |
530 | avc_cache_stats_incr(reclaims); | 553 | avc_cache_stats_incr(reclaims); |
531 | ecx++; | 554 | ecx++; |
532 | if (ecx >= AVC_CACHE_RECLAIM) { | 555 | if (ecx >= AVC_CACHE_RECLAIM) { |
@@ -542,7 +565,7 @@ out: | |||
542 | return ecx; | 565 | return ecx; |
543 | } | 566 | } |
544 | 567 | ||
545 | static struct avc_node *avc_alloc_node(void) | 568 | static struct avc_node *avc_alloc_node(struct selinux_avc *avc) |
546 | { | 569 | { |
547 | struct avc_node *node; | 570 | struct avc_node *node; |
548 | 571 | ||
@@ -553,8 +576,9 @@ static struct avc_node *avc_alloc_node(void) | |||
553 | INIT_HLIST_NODE(&node->list); | 576 | INIT_HLIST_NODE(&node->list); |
554 | avc_cache_stats_incr(allocations); | 577 | avc_cache_stats_incr(allocations); |
555 | 578 | ||
556 | if (atomic_inc_return(&avc_cache.active_nodes) > avc_cache_threshold) | 579 | if (atomic_inc_return(&avc->avc_cache.active_nodes) > |
557 | avc_reclaim_node(); | 580 | avc->avc_cache_threshold) |
581 | avc_reclaim_node(avc); | ||
558 | 582 | ||
559 | out: | 583 | out: |
560 | return node; | 584 | return node; |
@@ -568,14 +592,15 @@ static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tcl | |||
568 | memcpy(&node->ae.avd, avd, sizeof(node->ae.avd)); | 592 | memcpy(&node->ae.avd, avd, sizeof(node->ae.avd)); |
569 | } | 593 | } |
570 | 594 | ||
571 | static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass) | 595 | static inline struct avc_node *avc_search_node(struct selinux_avc *avc, |
596 | u32 ssid, u32 tsid, u16 tclass) | ||
572 | { | 597 | { |
573 | struct avc_node *node, *ret = NULL; | 598 | struct avc_node *node, *ret = NULL; |
574 | int hvalue; | 599 | int hvalue; |
575 | struct hlist_head *head; | 600 | struct hlist_head *head; |
576 | 601 | ||
577 | hvalue = avc_hash(ssid, tsid, tclass); | 602 | hvalue = avc_hash(ssid, tsid, tclass); |
578 | head = &avc_cache.slots[hvalue]; | 603 | head = &avc->avc_cache.slots[hvalue]; |
579 | hlist_for_each_entry_rcu(node, head, list) { | 604 | hlist_for_each_entry_rcu(node, head, list) { |
580 | if (ssid == node->ae.ssid && | 605 | if (ssid == node->ae.ssid && |
581 | tclass == node->ae.tclass && | 606 | tclass == node->ae.tclass && |
@@ -600,12 +625,13 @@ static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass) | |||
600 | * then this function returns the avc_node. | 625 | * then this function returns the avc_node. |
601 | * Otherwise, this function returns NULL. | 626 | * Otherwise, this function returns NULL. |
602 | */ | 627 | */ |
603 | static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass) | 628 | static struct avc_node *avc_lookup(struct selinux_avc *avc, |
629 | u32 ssid, u32 tsid, u16 tclass) | ||
604 | { | 630 | { |
605 | struct avc_node *node; | 631 | struct avc_node *node; |
606 | 632 | ||
607 | avc_cache_stats_incr(lookups); | 633 | avc_cache_stats_incr(lookups); |
608 | node = avc_search_node(ssid, tsid, tclass); | 634 | node = avc_search_node(avc, ssid, tsid, tclass); |
609 | 635 | ||
610 | if (node) | 636 | if (node) |
611 | return node; | 637 | return node; |
@@ -614,7 +640,8 @@ static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass) | |||
614 | return NULL; | 640 | return NULL; |
615 | } | 641 | } |
616 | 642 | ||
617 | static int avc_latest_notif_update(int seqno, int is_insert) | 643 | static int avc_latest_notif_update(struct selinux_avc *avc, |
644 | int seqno, int is_insert) | ||
618 | { | 645 | { |
619 | int ret = 0; | 646 | int ret = 0; |
620 | static DEFINE_SPINLOCK(notif_lock); | 647 | static DEFINE_SPINLOCK(notif_lock); |
@@ -622,14 +649,14 @@ static int avc_latest_notif_update(int seqno, int is_insert) | |||
622 | 649 | ||
623 | spin_lock_irqsave(¬if_lock, flag); | 650 | spin_lock_irqsave(¬if_lock, flag); |
624 | if (is_insert) { | 651 | if (is_insert) { |
625 | if (seqno < avc_cache.latest_notif) { | 652 | if (seqno < avc->avc_cache.latest_notif) { |
626 | printk(KERN_WARNING "SELinux: avc: seqno %d < latest_notif %d\n", | 653 | printk(KERN_WARNING "SELinux: avc: seqno %d < latest_notif %d\n", |
627 | seqno, avc_cache.latest_notif); | 654 | seqno, avc->avc_cache.latest_notif); |
628 | ret = -EAGAIN; | 655 | ret = -EAGAIN; |
629 | } | 656 | } |
630 | } else { | 657 | } else { |
631 | if (seqno > avc_cache.latest_notif) | 658 | if (seqno > avc->avc_cache.latest_notif) |
632 | avc_cache.latest_notif = seqno; | 659 | avc->avc_cache.latest_notif = seqno; |
633 | } | 660 | } |
634 | spin_unlock_irqrestore(¬if_lock, flag); | 661 | spin_unlock_irqrestore(¬if_lock, flag); |
635 | 662 | ||
@@ -654,18 +681,19 @@ static int avc_latest_notif_update(int seqno, int is_insert) | |||
654 | * the access vectors into a cache entry, returns | 681 | * the access vectors into a cache entry, returns |
655 | * avc_node inserted. Otherwise, this function returns NULL. | 682 | * avc_node inserted. Otherwise, this function returns NULL. |
656 | */ | 683 | */ |
657 | static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, | 684 | static struct avc_node *avc_insert(struct selinux_avc *avc, |
658 | struct av_decision *avd, | 685 | u32 ssid, u32 tsid, u16 tclass, |
659 | struct avc_xperms_node *xp_node) | 686 | struct av_decision *avd, |
687 | struct avc_xperms_node *xp_node) | ||
660 | { | 688 | { |
661 | struct avc_node *pos, *node = NULL; | 689 | struct avc_node *pos, *node = NULL; |
662 | int hvalue; | 690 | int hvalue; |
663 | unsigned long flag; | 691 | unsigned long flag; |
664 | 692 | ||
665 | if (avc_latest_notif_update(avd->seqno, 1)) | 693 | if (avc_latest_notif_update(avc, avd->seqno, 1)) |
666 | goto out; | 694 | goto out; |
667 | 695 | ||
668 | node = avc_alloc_node(); | 696 | node = avc_alloc_node(avc); |
669 | if (node) { | 697 | if (node) { |
670 | struct hlist_head *head; | 698 | struct hlist_head *head; |
671 | spinlock_t *lock; | 699 | spinlock_t *lock; |
@@ -678,15 +706,15 @@ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, | |||
678 | kmem_cache_free(avc_node_cachep, node); | 706 | kmem_cache_free(avc_node_cachep, node); |
679 | return NULL; | 707 | return NULL; |
680 | } | 708 | } |
681 | head = &avc_cache.slots[hvalue]; | 709 | head = &avc->avc_cache.slots[hvalue]; |
682 | lock = &avc_cache.slots_lock[hvalue]; | 710 | lock = &avc->avc_cache.slots_lock[hvalue]; |
683 | 711 | ||
684 | spin_lock_irqsave(lock, flag); | 712 | spin_lock_irqsave(lock, flag); |
685 | hlist_for_each_entry(pos, head, list) { | 713 | hlist_for_each_entry(pos, head, list) { |
686 | if (pos->ae.ssid == ssid && | 714 | if (pos->ae.ssid == ssid && |
687 | pos->ae.tsid == tsid && | 715 | pos->ae.tsid == tsid && |
688 | pos->ae.tclass == tclass) { | 716 | pos->ae.tclass == tclass) { |
689 | avc_node_replace(node, pos); | 717 | avc_node_replace(avc, node, pos); |
690 | goto found; | 718 | goto found; |
691 | } | 719 | } |
692 | } | 720 | } |
@@ -724,9 +752,10 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) | |||
724 | { | 752 | { |
725 | struct common_audit_data *ad = a; | 753 | struct common_audit_data *ad = a; |
726 | audit_log_format(ab, " "); | 754 | audit_log_format(ab, " "); |
727 | avc_dump_query(ab, ad->selinux_audit_data->ssid, | 755 | avc_dump_query(ab, ad->selinux_audit_data->state, |
728 | ad->selinux_audit_data->tsid, | 756 | ad->selinux_audit_data->ssid, |
729 | ad->selinux_audit_data->tclass); | 757 | ad->selinux_audit_data->tsid, |
758 | ad->selinux_audit_data->tclass); | ||
730 | if (ad->selinux_audit_data->denied) { | 759 | if (ad->selinux_audit_data->denied) { |
731 | audit_log_format(ab, " permissive=%u", | 760 | audit_log_format(ab, " permissive=%u", |
732 | ad->selinux_audit_data->result ? 0 : 1); | 761 | ad->selinux_audit_data->result ? 0 : 1); |
@@ -734,10 +763,11 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) | |||
734 | } | 763 | } |
735 | 764 | ||
736 | /* This is the slow part of avc audit with big stack footprint */ | 765 | /* This is the slow part of avc audit with big stack footprint */ |
737 | noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, | 766 | noinline int slow_avc_audit(struct selinux_state *state, |
738 | u32 requested, u32 audited, u32 denied, int result, | 767 | u32 ssid, u32 tsid, u16 tclass, |
739 | struct common_audit_data *a, | 768 | u32 requested, u32 audited, u32 denied, int result, |
740 | unsigned flags) | 769 | struct common_audit_data *a, |
770 | unsigned int flags) | ||
741 | { | 771 | { |
742 | struct common_audit_data stack_data; | 772 | struct common_audit_data stack_data; |
743 | struct selinux_audit_data sad; | 773 | struct selinux_audit_data sad; |
@@ -765,6 +795,7 @@ noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, | |||
765 | sad.audited = audited; | 795 | sad.audited = audited; |
766 | sad.denied = denied; | 796 | sad.denied = denied; |
767 | sad.result = result; | 797 | sad.result = result; |
798 | sad.state = state; | ||
768 | 799 | ||
769 | a->selinux_audit_data = &sad; | 800 | a->selinux_audit_data = &sad; |
770 | 801 | ||
@@ -813,10 +844,11 @@ out: | |||
813 | * otherwise, this function updates the AVC entry. The original AVC-entry object | 844 | * otherwise, this function updates the AVC entry. The original AVC-entry object |
814 | * will release later by RCU. | 845 | * will release later by RCU. |
815 | */ | 846 | */ |
816 | static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, | 847 | static int avc_update_node(struct selinux_avc *avc, |
817 | u32 tsid, u16 tclass, u32 seqno, | 848 | u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, |
818 | struct extended_perms_decision *xpd, | 849 | u32 tsid, u16 tclass, u32 seqno, |
819 | u32 flags) | 850 | struct extended_perms_decision *xpd, |
851 | u32 flags) | ||
820 | { | 852 | { |
821 | int hvalue, rc = 0; | 853 | int hvalue, rc = 0; |
822 | unsigned long flag; | 854 | unsigned long flag; |
@@ -824,7 +856,7 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, | |||
824 | struct hlist_head *head; | 856 | struct hlist_head *head; |
825 | spinlock_t *lock; | 857 | spinlock_t *lock; |
826 | 858 | ||
827 | node = avc_alloc_node(); | 859 | node = avc_alloc_node(avc); |
828 | if (!node) { | 860 | if (!node) { |
829 | rc = -ENOMEM; | 861 | rc = -ENOMEM; |
830 | goto out; | 862 | goto out; |
@@ -833,8 +865,8 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, | |||
833 | /* Lock the target slot */ | 865 | /* Lock the target slot */ |
834 | hvalue = avc_hash(ssid, tsid, tclass); | 866 | hvalue = avc_hash(ssid, tsid, tclass); |
835 | 867 | ||
836 | head = &avc_cache.slots[hvalue]; | 868 | head = &avc->avc_cache.slots[hvalue]; |
837 | lock = &avc_cache.slots_lock[hvalue]; | 869 | lock = &avc->avc_cache.slots_lock[hvalue]; |
838 | 870 | ||
839 | spin_lock_irqsave(lock, flag); | 871 | spin_lock_irqsave(lock, flag); |
840 | 872 | ||
@@ -850,7 +882,7 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, | |||
850 | 882 | ||
851 | if (!orig) { | 883 | if (!orig) { |
852 | rc = -ENOENT; | 884 | rc = -ENOENT; |
853 | avc_node_kill(node); | 885 | avc_node_kill(avc, node); |
854 | goto out_unlock; | 886 | goto out_unlock; |
855 | } | 887 | } |
856 | 888 | ||
@@ -894,7 +926,7 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, | |||
894 | avc_add_xperms_decision(node, xpd); | 926 | avc_add_xperms_decision(node, xpd); |
895 | break; | 927 | break; |
896 | } | 928 | } |
897 | avc_node_replace(node, orig); | 929 | avc_node_replace(avc, node, orig); |
898 | out_unlock: | 930 | out_unlock: |
899 | spin_unlock_irqrestore(lock, flag); | 931 | spin_unlock_irqrestore(lock, flag); |
900 | out: | 932 | out: |
@@ -904,7 +936,7 @@ out: | |||
904 | /** | 936 | /** |
905 | * avc_flush - Flush the cache | 937 | * avc_flush - Flush the cache |
906 | */ | 938 | */ |
907 | static void avc_flush(void) | 939 | static void avc_flush(struct selinux_avc *avc) |
908 | { | 940 | { |
909 | struct hlist_head *head; | 941 | struct hlist_head *head; |
910 | struct avc_node *node; | 942 | struct avc_node *node; |
@@ -913,8 +945,8 @@ static void avc_flush(void) | |||
913 | int i; | 945 | int i; |
914 | 946 | ||
915 | for (i = 0; i < AVC_CACHE_SLOTS; i++) { | 947 | for (i = 0; i < AVC_CACHE_SLOTS; i++) { |
916 | head = &avc_cache.slots[i]; | 948 | head = &avc->avc_cache.slots[i]; |
917 | lock = &avc_cache.slots_lock[i]; | 949 | lock = &avc->avc_cache.slots_lock[i]; |
918 | 950 | ||
919 | spin_lock_irqsave(lock, flag); | 951 | spin_lock_irqsave(lock, flag); |
920 | /* | 952 | /* |
@@ -923,7 +955,7 @@ static void avc_flush(void) | |||
923 | */ | 955 | */ |
924 | rcu_read_lock(); | 956 | rcu_read_lock(); |
925 | hlist_for_each_entry(node, head, list) | 957 | hlist_for_each_entry(node, head, list) |
926 | avc_node_delete(node); | 958 | avc_node_delete(avc, node); |
927 | rcu_read_unlock(); | 959 | rcu_read_unlock(); |
928 | spin_unlock_irqrestore(lock, flag); | 960 | spin_unlock_irqrestore(lock, flag); |
929 | } | 961 | } |
@@ -933,12 +965,12 @@ static void avc_flush(void) | |||
933 | * avc_ss_reset - Flush the cache and revalidate migrated permissions. | 965 | * avc_ss_reset - Flush the cache and revalidate migrated permissions. |
934 | * @seqno: policy sequence number | 966 | * @seqno: policy sequence number |
935 | */ | 967 | */ |
936 | int avc_ss_reset(u32 seqno) | 968 | int avc_ss_reset(struct selinux_avc *avc, u32 seqno) |
937 | { | 969 | { |
938 | struct avc_callback_node *c; | 970 | struct avc_callback_node *c; |
939 | int rc = 0, tmprc; | 971 | int rc = 0, tmprc; |
940 | 972 | ||
941 | avc_flush(); | 973 | avc_flush(avc); |
942 | 974 | ||
943 | for (c = avc_callbacks; c; c = c->next) { | 975 | for (c = avc_callbacks; c; c = c->next) { |
944 | if (c->events & AVC_CALLBACK_RESET) { | 976 | if (c->events & AVC_CALLBACK_RESET) { |
@@ -950,7 +982,7 @@ int avc_ss_reset(u32 seqno) | |||
950 | } | 982 | } |
951 | } | 983 | } |
952 | 984 | ||
953 | avc_latest_notif_update(seqno, 0); | 985 | avc_latest_notif_update(avc, seqno, 0); |
954 | return rc; | 986 | return rc; |
955 | } | 987 | } |
956 | 988 | ||
@@ -963,30 +995,34 @@ int avc_ss_reset(u32 seqno) | |||
963 | * Don't inline this, since it's the slow-path and just | 995 | * Don't inline this, since it's the slow-path and just |
964 | * results in a bigger stack frame. | 996 | * results in a bigger stack frame. |
965 | */ | 997 | */ |
966 | static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid, | 998 | static noinline |
967 | u16 tclass, struct av_decision *avd, | 999 | struct avc_node *avc_compute_av(struct selinux_state *state, |
968 | struct avc_xperms_node *xp_node) | 1000 | u32 ssid, u32 tsid, |
1001 | u16 tclass, struct av_decision *avd, | ||
1002 | struct avc_xperms_node *xp_node) | ||
969 | { | 1003 | { |
970 | rcu_read_unlock(); | 1004 | rcu_read_unlock(); |
971 | INIT_LIST_HEAD(&xp_node->xpd_head); | 1005 | INIT_LIST_HEAD(&xp_node->xpd_head); |
972 | security_compute_av(ssid, tsid, tclass, avd, &xp_node->xp); | 1006 | security_compute_av(state, ssid, tsid, tclass, avd, &xp_node->xp); |
973 | rcu_read_lock(); | 1007 | rcu_read_lock(); |
974 | return avc_insert(ssid, tsid, tclass, avd, xp_node); | 1008 | return avc_insert(state->avc, ssid, tsid, tclass, avd, xp_node); |
975 | } | 1009 | } |
976 | 1010 | ||
977 | static noinline int avc_denied(u32 ssid, u32 tsid, | 1011 | static noinline int avc_denied(struct selinux_state *state, |
978 | u16 tclass, u32 requested, | 1012 | u32 ssid, u32 tsid, |
979 | u8 driver, u8 xperm, unsigned flags, | 1013 | u16 tclass, u32 requested, |
980 | struct av_decision *avd) | 1014 | u8 driver, u8 xperm, unsigned int flags, |
1015 | struct av_decision *avd) | ||
981 | { | 1016 | { |
982 | if (flags & AVC_STRICT) | 1017 | if (flags & AVC_STRICT) |
983 | return -EACCES; | 1018 | return -EACCES; |
984 | 1019 | ||
985 | if (selinux_enforcing && !(avd->flags & AVD_FLAGS_PERMISSIVE)) | 1020 | if (enforcing_enabled(state) && |
1021 | !(avd->flags & AVD_FLAGS_PERMISSIVE)) | ||
986 | return -EACCES; | 1022 | return -EACCES; |
987 | 1023 | ||
988 | avc_update_node(AVC_CALLBACK_GRANT, requested, driver, xperm, ssid, | 1024 | avc_update_node(state->avc, AVC_CALLBACK_GRANT, requested, driver, |
989 | tsid, tclass, avd->seqno, NULL, flags); | 1025 | xperm, ssid, tsid, tclass, avd->seqno, NULL, flags); |
990 | return 0; | 1026 | return 0; |
991 | } | 1027 | } |
992 | 1028 | ||
@@ -997,8 +1033,9 @@ static noinline int avc_denied(u32 ssid, u32 tsid, | |||
997 | * as-is the case with ioctls, then multiple may be chained together and the | 1033 | * as-is the case with ioctls, then multiple may be chained together and the |
998 | * driver field is used to specify which set contains the permission. | 1034 | * driver field is used to specify which set contains the permission. |
999 | */ | 1035 | */ |
1000 | int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, | 1036 | int avc_has_extended_perms(struct selinux_state *state, |
1001 | u8 driver, u8 xperm, struct common_audit_data *ad) | 1037 | u32 ssid, u32 tsid, u16 tclass, u32 requested, |
1038 | u8 driver, u8 xperm, struct common_audit_data *ad) | ||
1002 | { | 1039 | { |
1003 | struct avc_node *node; | 1040 | struct avc_node *node; |
1004 | struct av_decision avd; | 1041 | struct av_decision avd; |
@@ -1017,9 +1054,9 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, | |||
1017 | 1054 | ||
1018 | rcu_read_lock(); | 1055 | rcu_read_lock(); |
1019 | 1056 | ||
1020 | node = avc_lookup(ssid, tsid, tclass); | 1057 | node = avc_lookup(state->avc, ssid, tsid, tclass); |
1021 | if (unlikely(!node)) { | 1058 | if (unlikely(!node)) { |
1022 | node = avc_compute_av(ssid, tsid, tclass, &avd, xp_node); | 1059 | node = avc_compute_av(state, ssid, tsid, tclass, &avd, xp_node); |
1023 | } else { | 1060 | } else { |
1024 | memcpy(&avd, &node->ae.avd, sizeof(avd)); | 1061 | memcpy(&avd, &node->ae.avd, sizeof(avd)); |
1025 | xp_node = node->ae.xp_node; | 1062 | xp_node = node->ae.xp_node; |
@@ -1043,11 +1080,12 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, | |||
1043 | goto decision; | 1080 | goto decision; |
1044 | } | 1081 | } |
1045 | rcu_read_unlock(); | 1082 | rcu_read_unlock(); |
1046 | security_compute_xperms_decision(ssid, tsid, tclass, driver, | 1083 | security_compute_xperms_decision(state, ssid, tsid, tclass, |
1047 | &local_xpd); | 1084 | driver, &local_xpd); |
1048 | rcu_read_lock(); | 1085 | rcu_read_lock(); |
1049 | avc_update_node(AVC_CALLBACK_ADD_XPERMS, requested, driver, xperm, | 1086 | avc_update_node(state->avc, AVC_CALLBACK_ADD_XPERMS, requested, |
1050 | ssid, tsid, tclass, avd.seqno, &local_xpd, 0); | 1087 | driver, xperm, ssid, tsid, tclass, avd.seqno, |
1088 | &local_xpd, 0); | ||
1051 | } else { | 1089 | } else { |
1052 | avc_quick_copy_xperms_decision(xperm, &local_xpd, xpd); | 1090 | avc_quick_copy_xperms_decision(xperm, &local_xpd, xpd); |
1053 | } | 1091 | } |
@@ -1059,12 +1097,12 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, | |||
1059 | decision: | 1097 | decision: |
1060 | denied = requested & ~(avd.allowed); | 1098 | denied = requested & ~(avd.allowed); |
1061 | if (unlikely(denied)) | 1099 | if (unlikely(denied)) |
1062 | rc = avc_denied(ssid, tsid, tclass, requested, driver, xperm, | 1100 | rc = avc_denied(state, ssid, tsid, tclass, requested, |
1063 | AVC_EXTENDED_PERMS, &avd); | 1101 | driver, xperm, AVC_EXTENDED_PERMS, &avd); |
1064 | 1102 | ||
1065 | rcu_read_unlock(); | 1103 | rcu_read_unlock(); |
1066 | 1104 | ||
1067 | rc2 = avc_xperms_audit(ssid, tsid, tclass, requested, | 1105 | rc2 = avc_xperms_audit(state, ssid, tsid, tclass, requested, |
1068 | &avd, xpd, xperm, rc, ad); | 1106 | &avd, xpd, xperm, rc, ad); |
1069 | if (rc2) | 1107 | if (rc2) |
1070 | return rc2; | 1108 | return rc2; |
@@ -1091,10 +1129,11 @@ decision: | |||
1091 | * auditing, e.g. in cases where a lock must be held for the check but | 1129 | * auditing, e.g. in cases where a lock must be held for the check but |
1092 | * should be released for the auditing. | 1130 | * should be released for the auditing. |
1093 | */ | 1131 | */ |
1094 | inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, | 1132 | inline int avc_has_perm_noaudit(struct selinux_state *state, |
1095 | u16 tclass, u32 requested, | 1133 | u32 ssid, u32 tsid, |
1096 | unsigned flags, | 1134 | u16 tclass, u32 requested, |
1097 | struct av_decision *avd) | 1135 | unsigned int flags, |
1136 | struct av_decision *avd) | ||
1098 | { | 1137 | { |
1099 | struct avc_node *node; | 1138 | struct avc_node *node; |
1100 | struct avc_xperms_node xp_node; | 1139 | struct avc_xperms_node xp_node; |
@@ -1105,15 +1144,16 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
1105 | 1144 | ||
1106 | rcu_read_lock(); | 1145 | rcu_read_lock(); |
1107 | 1146 | ||
1108 | node = avc_lookup(ssid, tsid, tclass); | 1147 | node = avc_lookup(state->avc, ssid, tsid, tclass); |
1109 | if (unlikely(!node)) | 1148 | if (unlikely(!node)) |
1110 | node = avc_compute_av(ssid, tsid, tclass, avd, &xp_node); | 1149 | node = avc_compute_av(state, ssid, tsid, tclass, avd, &xp_node); |
1111 | else | 1150 | else |
1112 | memcpy(avd, &node->ae.avd, sizeof(*avd)); | 1151 | memcpy(avd, &node->ae.avd, sizeof(*avd)); |
1113 | 1152 | ||
1114 | denied = requested & ~(avd->allowed); | 1153 | denied = requested & ~(avd->allowed); |
1115 | if (unlikely(denied)) | 1154 | if (unlikely(denied)) |
1116 | rc = avc_denied(ssid, tsid, tclass, requested, 0, 0, flags, avd); | 1155 | rc = avc_denied(state, ssid, tsid, tclass, requested, 0, 0, |
1156 | flags, avd); | ||
1117 | 1157 | ||
1118 | rcu_read_unlock(); | 1158 | rcu_read_unlock(); |
1119 | return rc; | 1159 | return rc; |
@@ -1135,39 +1175,43 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
1135 | * permissions are granted, -%EACCES if any permissions are denied, or | 1175 | * permissions are granted, -%EACCES if any permissions are denied, or |
1136 | * another -errno upon other errors. | 1176 | * another -errno upon other errors. |
1137 | */ | 1177 | */ |
1138 | int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, | 1178 | int avc_has_perm(struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass, |
1139 | u32 requested, struct common_audit_data *auditdata) | 1179 | u32 requested, struct common_audit_data *auditdata) |
1140 | { | 1180 | { |
1141 | struct av_decision avd; | 1181 | struct av_decision avd; |
1142 | int rc, rc2; | 1182 | int rc, rc2; |
1143 | 1183 | ||
1144 | rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd); | 1184 | rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested, 0, |
1185 | &avd); | ||
1145 | 1186 | ||
1146 | rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata, 0); | 1187 | rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc, |
1188 | auditdata, 0); | ||
1147 | if (rc2) | 1189 | if (rc2) |
1148 | return rc2; | 1190 | return rc2; |
1149 | return rc; | 1191 | return rc; |
1150 | } | 1192 | } |
1151 | 1193 | ||
1152 | int avc_has_perm_flags(u32 ssid, u32 tsid, u16 tclass, | 1194 | int avc_has_perm_flags(struct selinux_state *state, |
1153 | u32 requested, struct common_audit_data *auditdata, | 1195 | u32 ssid, u32 tsid, u16 tclass, u32 requested, |
1196 | struct common_audit_data *auditdata, | ||
1154 | int flags) | 1197 | int flags) |
1155 | { | 1198 | { |
1156 | struct av_decision avd; | 1199 | struct av_decision avd; |
1157 | int rc, rc2; | 1200 | int rc, rc2; |
1158 | 1201 | ||
1159 | rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd); | 1202 | rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested, 0, |
1203 | &avd); | ||
1160 | 1204 | ||
1161 | rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, | 1205 | rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc, |
1162 | auditdata, flags); | 1206 | auditdata, flags); |
1163 | if (rc2) | 1207 | if (rc2) |
1164 | return rc2; | 1208 | return rc2; |
1165 | return rc; | 1209 | return rc; |
1166 | } | 1210 | } |
1167 | 1211 | ||
1168 | u32 avc_policy_seqno(void) | 1212 | u32 avc_policy_seqno(struct selinux_state *state) |
1169 | { | 1213 | { |
1170 | return avc_cache.latest_notif; | 1214 | return state->avc->avc_cache.latest_notif; |
1171 | } | 1215 | } |
1172 | 1216 | ||
1173 | void avc_disable(void) | 1217 | void avc_disable(void) |
@@ -1184,7 +1228,7 @@ void avc_disable(void) | |||
1184 | * the cache and get that memory back. | 1228 | * the cache and get that memory back. |
1185 | */ | 1229 | */ |
1186 | if (avc_node_cachep) { | 1230 | if (avc_node_cachep) { |
1187 | avc_flush(); | 1231 | avc_flush(selinux_state.avc); |
1188 | /* kmem_cache_destroy(avc_node_cachep); */ | 1232 | /* kmem_cache_destroy(avc_node_cachep); */ |
1189 | } | 1233 | } |
1190 | } | 1234 | } |