1818#include <linux/errno.h>
1919#include <linux/err.h>
2020#include <linux/gfp.h>
21+ #include <linux/idr.h>
2122#include <linux/slab.h>
2223#include <linux/spinlock.h>
2324
3031/*
3132 * secids - do not pin labels with a refcount. They rely on the label
3233 * properly updating/freeing them
33- *
34- * A singly linked free list is used to track secids that have been
35- * freed and reuse them before allocating new ones
3634 */
3735
38- #define FREE_LIST_HEAD 1
39-
40- static RADIX_TREE (aa_secids_map , GFP_ATOMIC ) ;
36+ static DEFINE_IDR (aa_secids );
4137static DEFINE_SPINLOCK (secid_lock );
42- static u32 alloced_secid = FREE_LIST_HEAD ;
43- static u32 free_list = FREE_LIST_HEAD ;
44- static unsigned long free_count ;
4538
4639/*
4740 * TODO: allow policy to reserve a secid range?
4841 * TODO: add secid pinning
4942 * TODO: use secid_update in label replace
5043 */
5144
52- #define SECID_MAX U32_MAX
53-
54- /* TODO: mark free list as exceptional */
55- static void * to_ptr (u32 secid )
56- {
57- return (void * )
58- ((((unsigned long ) secid ) << RADIX_TREE_EXCEPTIONAL_SHIFT ));
59- }
60-
61- static u32 to_secid (void * ptr )
62- {
63- return (u32 ) (((unsigned long ) ptr ) >> RADIX_TREE_EXCEPTIONAL_SHIFT );
64- }
65-
66-
67- /* TODO: tag free_list entries to mark them as different */
68- static u32 __pop (struct aa_label * label )
69- {
70- u32 secid = free_list ;
71- void __rcu * * slot ;
72- void * entry ;
73-
74- if (free_list == FREE_LIST_HEAD )
75- return AA_SECID_INVALID ;
76-
77- slot = radix_tree_lookup_slot (& aa_secids_map , secid );
78- AA_BUG (!slot );
79- entry = radix_tree_deref_slot_protected (slot , & secid_lock );
80- free_list = to_secid (entry );
81- radix_tree_replace_slot (& aa_secids_map , slot , label );
82- free_count -- ;
83-
84- return secid ;
85- }
86-
87- static void __push (u32 secid )
88- {
89- void __rcu * * slot ;
90-
91- slot = radix_tree_lookup_slot (& aa_secids_map , secid );
92- AA_BUG (!slot );
93- radix_tree_replace_slot (& aa_secids_map , slot , to_ptr (free_list ));
94- free_list = secid ;
95- free_count ++ ;
96- }
97-
98- static struct aa_label * __secid_update (u32 secid , struct aa_label * label )
99- {
100- struct aa_label * old ;
101- void __rcu * * slot ;
102-
103- slot = radix_tree_lookup_slot (& aa_secids_map , secid );
104- AA_BUG (!slot );
105- old = radix_tree_deref_slot_protected (slot , & secid_lock );
106- radix_tree_replace_slot (& aa_secids_map , slot , label );
107-
108- return old ;
109- }
110-
11145/**
11246 * aa_secid_update - update a secid mapping to a new label
11347 * @secid: secid to update
11448 * @label: label the secid will now map to
11549 */
11650void aa_secid_update (u32 secid , struct aa_label * label )
11751{
118- struct aa_label * old ;
11952 unsigned long flags ;
12053
12154 spin_lock_irqsave (& secid_lock , flags );
122- old = __secid_update ( secid , label );
55+ idr_replace ( & aa_secids , label , secid );
12356 spin_unlock_irqrestore (& secid_lock , flags );
12457}
12558
@@ -132,7 +65,7 @@ struct aa_label *aa_secid_to_label(u32 secid)
13265 struct aa_label * label ;
13366
13467 rcu_read_lock ();
135- label = radix_tree_lookup ( & aa_secids_map , secid );
68+ label = idr_find ( & aa_secids , secid );
13669 rcu_read_unlock ();
13770
13871 return label ;
@@ -167,7 +100,6 @@ int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
167100 return 0 ;
168101}
169102
170-
171103int apparmor_secctx_to_secid (const char * secdata , u32 seclen , u32 * secid )
172104{
173105 struct aa_label * label ;
@@ -186,7 +118,6 @@ void apparmor_release_secctx(char *secdata, u32 seclen)
186118 kfree (secdata );
187119}
188120
189-
190121/**
191122 * aa_alloc_secid - allocate a new secid for a profile
192123 */
@@ -195,35 +126,12 @@ u32 aa_alloc_secid(struct aa_label *label, gfp_t gfp)
195126 unsigned long flags ;
196127 u32 secid ;
197128
198- /* racey, but at worst causes new allocation instead of reuse */
199- if (free_list == FREE_LIST_HEAD ) {
200- bool preload = 0 ;
201- int res ;
202-
203- retry :
204- if (gfpflags_allow_blocking (gfp ) && !radix_tree_preload (gfp ))
205- preload = 1 ;
206- spin_lock_irqsave (& secid_lock , flags );
207- if (alloced_secid != SECID_MAX ) {
208- secid = ++ alloced_secid ;
209- res = radix_tree_insert (& aa_secids_map , secid , label );
210- AA_BUG (res == - EEXIST );
211- } else {
212- secid = AA_SECID_INVALID ;
213- }
214- spin_unlock_irqrestore (& secid_lock , flags );
215- if (preload )
216- radix_tree_preload_end ();
217- } else {
218- spin_lock_irqsave (& secid_lock , flags );
219- /* remove entry from free list */
220- secid = __pop (label );
221- if (secid == AA_SECID_INVALID ) {
222- spin_unlock_irqrestore (& secid_lock , flags );
223- goto retry ;
224- }
225- spin_unlock_irqrestore (& secid_lock , flags );
226- }
129+ idr_preload (gfp );
130+ spin_lock_irqsave (& secid_lock , flags );
131+ secid = idr_alloc (& aa_secids , label , 0 , 0 , GFP_ATOMIC );
132+ /* XXX: Can return -ENOMEM */
133+ spin_unlock_irqrestore (& secid_lock , flags );
134+ idr_preload_end ();
227135
228136 return secid ;
229137}
@@ -237,6 +145,6 @@ void aa_free_secid(u32 secid)
237145 unsigned long flags ;
238146
239147 spin_lock_irqsave (& secid_lock , flags );
240- __push ( secid );
148+ idr_remove ( & aa_secids , secid );
241149 spin_unlock_irqrestore (& secid_lock , flags );
242150}
0 commit comments