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) spin_lock_irq(&s->lock)
20 #define SIDTAB_UNLOCK(s) spin_unlock_irq(&s->lock)
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 int sidtab_remove(struct sidtab *s, u32 sid)
93 struct sidtab_node *cur, *last;
100 hvalue = SIDTAB_HASH(sid);
102 cur = s->htable[hvalue];
103 while (cur != NULL && sid > cur->sid) {
108 if (cur == NULL || sid != cur->sid) {
114 s->htable[hvalue] = cur->next;
116 last->next = cur->next;
118 context_destroy(&cur->context);
126 struct context *sidtab_search(struct sidtab *s, u32 sid)
129 struct sidtab_node *cur;
134 hvalue = SIDTAB_HASH(sid);
135 cur = s->htable[hvalue];
136 while (cur != NULL && sid > cur->sid)
139 if (cur == NULL || sid != cur->sid) {
140 /* Remap invalid SIDs to the unlabeled SID. */
141 sid = SECINITSID_UNLABELED;
142 hvalue = SIDTAB_HASH(sid);
143 cur = s->htable[hvalue];
144 while (cur != NULL && sid > cur->sid)
146 if (!cur || sid != cur->sid)
150 return &cur->context;
153 int sidtab_map(struct sidtab *s,
154 int (*apply) (u32 sid,
155 struct context *context,
160 struct sidtab_node *cur;
165 for (i = 0; i < SIDTAB_SIZE; i++) {
167 while (cur != NULL) {
168 rc = apply(cur->sid, &cur->context, args);
178 void sidtab_map_remove_on_error(struct sidtab *s,
179 int (*apply) (u32 sid,
180 struct context *context,
185 struct sidtab_node *last, *cur, *temp;
190 for (i = 0; i < SIDTAB_SIZE; i++) {
193 while (cur != NULL) {
194 ret = apply(cur->sid, &cur->context, args);
197 last->next = cur->next;
199 s->htable[i] = cur->next;
204 context_destroy(&temp->context);
217 static inline u32 sidtab_search_context(struct sidtab *s,
218 struct context *context)
221 struct sidtab_node *cur;
223 for (i = 0; i < SIDTAB_SIZE; i++) {
225 while (cur != NULL) {
226 if (context_cmp(&cur->context, context))
234 int sidtab_context_to_sid(struct sidtab *s,
235 struct context *context,
241 *out_sid = SECSID_NULL;
243 sid = sidtab_search_context(s, context);
246 /* Rescan now that we hold the lock. */
247 sid = sidtab_search_context(s, context);
250 /* No SID exists for the context. Allocate a new one. */
251 if (s->next_sid == UINT_MAX || s->shutdown) {
256 ret = sidtab_insert(s, sid, context);
270 void sidtab_hash_eval(struct sidtab *h, char *tag)
272 int i, chain_len, slots_used, max_chain_len;
273 struct sidtab_node *cur;
277 for (i = 0; i < SIDTAB_SIZE; i++) {
287 if (chain_len > max_chain_len)
288 max_chain_len = chain_len;
292 printk(KERN_INFO "%s: %d entries and %d/%d buckets used, longest "
293 "chain length %d\n", tag, h->nel, slots_used, SIDTAB_SIZE,
297 void sidtab_destroy(struct sidtab *s)
300 struct sidtab_node *cur, *temp;
305 for (i = 0; i < SIDTAB_SIZE; i++) {
307 while (cur != NULL) {
310 context_destroy(&temp->context);
321 void sidtab_set(struct sidtab *dst, struct sidtab *src)
324 dst->htable = src->htable;
326 dst->next_sid = src->next_sid;
331 void sidtab_shutdown(struct sidtab *s)