2 * Implementation of the SID table type.
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
6 #include <linux/kernel.h>
7 #include <linux/slab.h>
8 #include <linux/spinlock.h>
9 #include <linux/errno.h>
14 #define SIDTAB_HASH(sid) \
15 (sid & SIDTAB_HASH_MASK)
17 int sidtab_init(struct sidtab
*s
)
21 s
->htable
= kmalloc(sizeof(*(s
->htable
)) * SIDTAB_SIZE
, GFP_ATOMIC
);
24 for (i
= 0; i
< SIDTAB_SIZE
; i
++)
29 spin_lock_init(&s
->lock
);
33 int sidtab_insert(struct sidtab
*s
, u32 sid
, struct context
*context
)
36 struct sidtab_node
*prev
, *cur
, *newnode
;
43 hvalue
= SIDTAB_HASH(sid
);
45 cur
= s
->htable
[hvalue
];
46 while (cur
&& sid
> cur
->sid
) {
51 if (cur
&& sid
== cur
->sid
) {
56 newnode
= kmalloc(sizeof(*newnode
), GFP_ATOMIC
);
57 if (newnode
== NULL
) {
62 if (context_cpy(&newnode
->context
, context
)) {
69 newnode
->next
= prev
->next
;
73 newnode
->next
= s
->htable
[hvalue
];
75 s
->htable
[hvalue
] = newnode
;
79 if (sid
>= s
->next_sid
)
80 s
->next_sid
= sid
+ 1;
85 static struct context
*sidtab_search_core(struct sidtab
*s
, u32 sid
, int force
)
88 struct sidtab_node
*cur
;
93 hvalue
= SIDTAB_HASH(sid
);
94 cur
= s
->htable
[hvalue
];
95 while (cur
&& sid
> cur
->sid
)
98 if (force
&& cur
&& sid
== cur
->sid
&& cur
->context
.len
)
101 if (cur
== NULL
|| sid
!= cur
->sid
|| cur
->context
.len
) {
102 /* Remap invalid SIDs to the unlabeled SID. */
103 sid
= SECINITSID_UNLABELED
;
104 hvalue
= SIDTAB_HASH(sid
);
105 cur
= s
->htable
[hvalue
];
106 while (cur
&& sid
> cur
->sid
)
108 if (!cur
|| sid
!= cur
->sid
)
112 return &cur
->context
;
115 struct context
*sidtab_search(struct sidtab
*s
, u32 sid
)
117 return sidtab_search_core(s
, sid
, 0);
120 struct context
*sidtab_search_force(struct sidtab
*s
, u32 sid
)
122 return sidtab_search_core(s
, sid
, 1);
125 int sidtab_map(struct sidtab
*s
,
126 int (*apply
) (u32 sid
,
127 struct context
*context
,
132 struct sidtab_node
*cur
;
137 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
140 rc
= apply(cur
->sid
, &cur
->context
, args
);
150 static void sidtab_update_cache(struct sidtab
*s
, struct sidtab_node
*n
, int loc
)
152 BUG_ON(loc
>= SIDTAB_CACHE_LEN
);
155 s
->cache
[loc
] = s
->cache
[loc
- 1];
161 static inline u32
sidtab_search_context(struct sidtab
*s
,
162 struct context
*context
)
165 struct sidtab_node
*cur
;
167 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
170 if (context_cmp(&cur
->context
, context
)) {
171 sidtab_update_cache(s
, cur
, SIDTAB_CACHE_LEN
- 1);
180 static inline u32
sidtab_search_cache(struct sidtab
*s
, struct context
*context
)
183 struct sidtab_node
*node
;
185 for (i
= 0; i
< SIDTAB_CACHE_LEN
; i
++) {
189 if (context_cmp(&node
->context
, context
)) {
190 sidtab_update_cache(s
, node
, i
);
197 int sidtab_context_to_sid(struct sidtab
*s
,
198 struct context
*context
,
205 *out_sid
= SECSID_NULL
;
207 sid
= sidtab_search_cache(s
, context
);
209 sid
= sidtab_search_context(s
, context
);
211 spin_lock_irqsave(&s
->lock
, flags
);
212 /* Rescan now that we hold the lock. */
213 sid
= sidtab_search_context(s
, context
);
216 /* No SID exists for the context. Allocate a new one. */
217 if (s
->next_sid
== UINT_MAX
|| s
->shutdown
) {
224 "SELinux: Context %s is not valid (left unmapped).\n",
226 ret
= sidtab_insert(s
, sid
, context
);
230 spin_unlock_irqrestore(&s
->lock
, flags
);
240 void sidtab_hash_eval(struct sidtab
*h
, char *tag
)
242 int i
, chain_len
, slots_used
, max_chain_len
;
243 struct sidtab_node
*cur
;
247 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
257 if (chain_len
> max_chain_len
)
258 max_chain_len
= chain_len
;
262 printk(KERN_DEBUG
"%s: %d entries and %d/%d buckets used, longest "
263 "chain length %d\n", tag
, h
->nel
, slots_used
, SIDTAB_SIZE
,
267 void sidtab_destroy(struct sidtab
*s
)
270 struct sidtab_node
*cur
, *temp
;
275 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
280 context_destroy(&temp
->context
);
291 void sidtab_set(struct sidtab
*dst
, struct sidtab
*src
)
296 spin_lock_irqsave(&src
->lock
, flags
);
297 dst
->htable
= src
->htable
;
299 dst
->next_sid
= src
->next_sid
;
301 for (i
= 0; i
< SIDTAB_CACHE_LEN
; i
++)
302 dst
->cache
[i
] = NULL
;
303 spin_unlock_irqrestore(&src
->lock
, flags
);
306 void sidtab_shutdown(struct sidtab
*s
)
310 spin_lock_irqsave(&s
->lock
, flags
);
312 spin_unlock_irqrestore(&s
->lock
, flags
);