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>
10 #include <linux/sched.h>
15 #define SIDTAB_HASH(sid) \
16 (sid & SIDTAB_HASH_MASK)
18 #define INIT_SIDTAB_LOCK(s) spin_lock_init(&s->lock)
19 #define SIDTAB_LOCK(s, x) spin_lock_irqsave(&s->lock, x)
20 #define SIDTAB_UNLOCK(s, x) spin_unlock_irqrestore(&s->lock, x)
22 int sidtab_init(struct sidtab
*s
)
26 s
->htable
= kmalloc(sizeof(*(s
->htable
)) * SIDTAB_SIZE
, GFP_ATOMIC
);
29 for (i
= 0; i
< SIDTAB_SIZE
; i
++)
38 int sidtab_insert(struct sidtab
*s
, u32 sid
, struct context
*context
)
41 struct sidtab_node
*prev
, *cur
, *newnode
;
48 hvalue
= SIDTAB_HASH(sid
);
50 cur
= s
->htable
[hvalue
];
51 while (cur
!= NULL
&& sid
> cur
->sid
) {
56 if (cur
&& sid
== cur
->sid
) {
61 newnode
= kmalloc(sizeof(*newnode
), GFP_ATOMIC
);
62 if (newnode
== NULL
) {
67 if (context_cpy(&newnode
->context
, context
)) {
74 newnode
->next
= prev
->next
;
78 newnode
->next
= s
->htable
[hvalue
];
80 s
->htable
[hvalue
] = newnode
;
84 if (sid
>= s
->next_sid
)
85 s
->next_sid
= sid
+ 1;
90 struct context
*sidtab_search(struct sidtab
*s
, u32 sid
)
93 struct sidtab_node
*cur
;
98 hvalue
= SIDTAB_HASH(sid
);
99 cur
= s
->htable
[hvalue
];
100 while (cur
!= NULL
&& sid
> cur
->sid
)
103 if (cur
== NULL
|| sid
!= cur
->sid
) {
104 /* Remap invalid SIDs to the unlabeled SID. */
105 sid
= SECINITSID_UNLABELED
;
106 hvalue
= SIDTAB_HASH(sid
);
107 cur
= s
->htable
[hvalue
];
108 while (cur
!= NULL
&& sid
> cur
->sid
)
110 if (!cur
|| sid
!= cur
->sid
)
114 return &cur
->context
;
117 int sidtab_map(struct sidtab
*s
,
118 int (*apply
) (u32 sid
,
119 struct context
*context
,
124 struct sidtab_node
*cur
;
129 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
131 while (cur
!= NULL
) {
132 rc
= apply(cur
->sid
, &cur
->context
, args
);
142 void sidtab_map_remove_on_error(struct sidtab
*s
,
143 int (*apply
) (u32 sid
,
144 struct context
*context
,
149 struct sidtab_node
*last
, *cur
, *temp
;
154 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
157 while (cur
!= NULL
) {
158 ret
= apply(cur
->sid
, &cur
->context
, args
);
161 last
->next
= cur
->next
;
163 s
->htable
[i
] = cur
->next
;
168 context_destroy(&temp
->context
);
181 static inline u32
sidtab_search_context(struct sidtab
*s
,
182 struct context
*context
)
185 struct sidtab_node
*cur
;
187 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
189 while (cur
!= NULL
) {
190 if (context_cmp(&cur
->context
, context
))
198 int sidtab_context_to_sid(struct sidtab
*s
,
199 struct context
*context
,
206 *out_sid
= SECSID_NULL
;
208 sid
= sidtab_search_context(s
, context
);
210 SIDTAB_LOCK(s
, flags
);
211 /* Rescan now that we hold the lock. */
212 sid
= sidtab_search_context(s
, context
);
215 /* No SID exists for the context. Allocate a new one. */
216 if (s
->next_sid
== UINT_MAX
|| s
->shutdown
) {
221 ret
= sidtab_insert(s
, sid
, context
);
225 SIDTAB_UNLOCK(s
, flags
);
235 void sidtab_hash_eval(struct sidtab
*h
, char *tag
)
237 int i
, chain_len
, slots_used
, max_chain_len
;
238 struct sidtab_node
*cur
;
242 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
252 if (chain_len
> max_chain_len
)
253 max_chain_len
= chain_len
;
257 printk(KERN_INFO
"%s: %d entries and %d/%d buckets used, longest "
258 "chain length %d\n", tag
, h
->nel
, slots_used
, SIDTAB_SIZE
,
262 void sidtab_destroy(struct sidtab
*s
)
265 struct sidtab_node
*cur
, *temp
;
270 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
272 while (cur
!= NULL
) {
275 context_destroy(&temp
->context
);
286 void sidtab_set(struct sidtab
*dst
, struct sidtab
*src
)
290 SIDTAB_LOCK(src
, flags
);
291 dst
->htable
= src
->htable
;
293 dst
->next_sid
= src
->next_sid
;
295 SIDTAB_UNLOCK(src
, flags
);
298 void sidtab_shutdown(struct sidtab
*s
)
302 SIDTAB_LOCK(s
, flags
);
304 SIDTAB_UNLOCK(s
, flags
);