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 #define INIT_SIDTAB_LOCK(s) spin_lock_init(&s->lock)
18 #define SIDTAB_LOCK(s, x) spin_lock_irqsave(&s->lock, x)
19 #define SIDTAB_UNLOCK(s, x) spin_unlock_irqrestore(&s->lock, x)
21 int sidtab_init(struct sidtab
*s
)
25 s
->htable
= kmalloc(sizeof(*(s
->htable
)) * SIDTAB_SIZE
, GFP_ATOMIC
);
28 for (i
= 0; i
< SIDTAB_SIZE
; i
++)
37 int sidtab_insert(struct sidtab
*s
, u32 sid
, struct context
*context
)
40 struct sidtab_node
*prev
, *cur
, *newnode
;
47 hvalue
= SIDTAB_HASH(sid
);
49 cur
= s
->htable
[hvalue
];
50 while (cur
!= NULL
&& sid
> cur
->sid
) {
55 if (cur
&& sid
== cur
->sid
) {
60 newnode
= kmalloc(sizeof(*newnode
), GFP_ATOMIC
);
61 if (newnode
== NULL
) {
66 if (context_cpy(&newnode
->context
, context
)) {
73 newnode
->next
= prev
->next
;
77 newnode
->next
= s
->htable
[hvalue
];
79 s
->htable
[hvalue
] = newnode
;
83 if (sid
>= s
->next_sid
)
84 s
->next_sid
= sid
+ 1;
89 struct context
*sidtab_search(struct sidtab
*s
, u32 sid
)
92 struct sidtab_node
*cur
;
97 hvalue
= SIDTAB_HASH(sid
);
98 cur
= s
->htable
[hvalue
];
99 while (cur
!= NULL
&& sid
> cur
->sid
)
102 if (cur
== NULL
|| sid
!= cur
->sid
) {
103 /* Remap invalid SIDs to the unlabeled SID. */
104 sid
= SECINITSID_UNLABELED
;
105 hvalue
= SIDTAB_HASH(sid
);
106 cur
= s
->htable
[hvalue
];
107 while (cur
!= NULL
&& sid
> cur
->sid
)
109 if (!cur
|| sid
!= cur
->sid
)
113 return &cur
->context
;
116 int sidtab_map(struct sidtab
*s
,
117 int (*apply
) (u32 sid
,
118 struct context
*context
,
123 struct sidtab_node
*cur
;
128 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
130 while (cur
!= NULL
) {
131 rc
= apply(cur
->sid
, &cur
->context
, args
);
141 void sidtab_map_remove_on_error(struct sidtab
*s
,
142 int (*apply
) (u32 sid
,
143 struct context
*context
,
148 struct sidtab_node
*last
, *cur
, *temp
;
153 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
156 while (cur
!= NULL
) {
157 ret
= apply(cur
->sid
, &cur
->context
, args
);
160 last
->next
= cur
->next
;
162 s
->htable
[i
] = cur
->next
;
167 context_destroy(&temp
->context
);
180 static inline u32
sidtab_search_context(struct sidtab
*s
,
181 struct context
*context
)
184 struct sidtab_node
*cur
;
186 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
188 while (cur
!= NULL
) {
189 if (context_cmp(&cur
->context
, context
))
197 int sidtab_context_to_sid(struct sidtab
*s
,
198 struct context
*context
,
205 *out_sid
= SECSID_NULL
;
207 sid
= sidtab_search_context(s
, context
);
209 SIDTAB_LOCK(s
, flags
);
210 /* Rescan now that we hold the lock. */
211 sid
= sidtab_search_context(s
, context
);
214 /* No SID exists for the context. Allocate a new one. */
215 if (s
->next_sid
== UINT_MAX
|| s
->shutdown
) {
220 ret
= sidtab_insert(s
, sid
, context
);
224 SIDTAB_UNLOCK(s
, flags
);
234 void sidtab_hash_eval(struct sidtab
*h
, char *tag
)
236 int i
, chain_len
, slots_used
, max_chain_len
;
237 struct sidtab_node
*cur
;
241 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
251 if (chain_len
> max_chain_len
)
252 max_chain_len
= chain_len
;
256 printk(KERN_DEBUG
"%s: %d entries and %d/%d buckets used, longest "
257 "chain length %d\n", tag
, h
->nel
, slots_used
, SIDTAB_SIZE
,
261 void sidtab_destroy(struct sidtab
*s
)
264 struct sidtab_node
*cur
, *temp
;
269 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
271 while (cur
!= NULL
) {
274 context_destroy(&temp
->context
);
285 void sidtab_set(struct sidtab
*dst
, struct sidtab
*src
)
289 SIDTAB_LOCK(src
, flags
);
290 dst
->htable
= src
->htable
;
292 dst
->next_sid
= src
->next_sid
;
294 SIDTAB_UNLOCK(src
, flags
);
297 void sidtab_shutdown(struct sidtab
*s
)
301 SIDTAB_LOCK(s
, flags
);
303 SIDTAB_UNLOCK(s
, flags
);