1 /*
2 * Implementation of the SID table type.
3 *
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5 */
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>
11 #include "flask.h"
12 #include "security.h"
13 #include "sidtab.h"
14
15 #define SIDTAB_HASH(sid) \
16 (sid & SIDTAB_HASH_MASK)
17
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)
21
22 int sidtab_init(struct sidtab *s)
23 {
24 int i;
25
26 s->htable = kmalloc(sizeof(*(s->htable)) * SIDTAB_SIZE, GFP_ATOMIC);
27 if (!s->htable)
28 return -ENOMEM;
29 for (i = 0; i < SIDTAB_SIZE; i++)
30 s->htable[i] = NULL;
31 s->nel = 0;
32 s->next_sid = 1;
33 s->shutdown = 0;
34 INIT_SIDTAB_LOCK(s);
35 return 0;
36 }
37
38 int sidtab_insert(struct sidtab *s, u32 sid, struct context *context)
39 {
40 int hvalue, rc = 0;
41 struct sidtab_node *prev, *cur, *newnode;
42
43 if (!s) {
44 rc = -ENOMEM;
45 goto out;
46 }
47
48 hvalue = SIDTAB_HASH(sid);
49 prev = NULL;
50 cur = s->htable[hvalue];
51 while (cur != NULL && sid > cur->sid) {
52 prev = cur;
53 cur = cur->next;
54 }
55
56 if (cur && sid == cur->sid) {
57 rc = -EEXIST;
58 goto out;
59 }
60
61 newnode = kmalloc(sizeof(*newnode), GFP_ATOMIC);
62 if (newnode == NULL) {
63 rc = -ENOMEM;
64 goto out;
65 }
66 newnode->sid = sid;
67 if (context_cpy(&newnode->context, context)) {
68 kfree(newnode);
69 rc = -ENOMEM;
70 goto out;
71 }
72
73 if (prev) {
74 newnode->next = prev->next;
75 wmb();
76 prev->next = newnode;
77 } else {
78 newnode->next = s->htable[hvalue];
79 wmb();
80 s->htable[hvalue] = newnode;
81 }
82
83 s->nel++;
84 if (sid >= s->next_sid)
85 s->next_sid = sid + 1;
86 out:
87 return rc;
88 }
89
90 int sidtab_remove(struct sidtab *s, u32 sid)
91 {
92 int hvalue, rc = 0;
93 struct sidtab_node *cur, *last;
94
95 if (!s) {
96 rc = -ENOENT;
97 goto out;
98 }
99
100 hvalue = SIDTAB_HASH(sid);
101 last = NULL;
102 cur = s->htable[hvalue];
103 while (cur != NULL && sid > cur->sid) {
104 last = cur;
105 cur = cur->next;
106 }
107
108 if (cur == NULL || sid != cur->sid) {
109 rc = -ENOENT;
110 goto out;
111 }
112
113 if (last == NULL)
114 s->htable[hvalue] = cur->next;
115 else
116 last->next = cur->next;
117
118 context_destroy(&cur->context);
119
120 kfree(cur);
121 s->nel--;
122 out:
123 return rc;
124 }
125
126 struct context *sidtab_search(struct sidtab *s, u32 sid)
127 {
128 int hvalue;
129 struct sidtab_node *cur;
130
131 if (!s)
132 return NULL;
133
134 hvalue = SIDTAB_HASH(sid);
135 cur = s->htable[hvalue];
136 while (cur != NULL && sid > cur->sid)
137 cur = cur->next;
138
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)
145 cur = cur->next;
146 if (!cur || sid != cur->sid)
147 return NULL;
148 }
149
150 return &cur->context;
151 }
152
153 int sidtab_map(struct sidtab *s,
154 int (*apply) (u32 sid,
155 struct context *context,
156 void *args),
157 void *args)
158 {
159 int i, rc = 0;
160 struct sidtab_node *cur;
161
162 if (!s)
163 goto out;
164
165 for (i = 0; i < SIDTAB_SIZE; i++) {
166 cur = s->htable[i];
167 while (cur != NULL) {
168 rc = apply(cur->sid, &cur->context, args);
169 if (rc)
170 goto out;
171 cur = cur->next;
172 }
173 }
174 out:
175 return rc;
176 }
177
178 void sidtab_map_remove_on_error(struct sidtab *s,
179 int (*apply) (u32 sid,
180 struct context *context,
181 void *args),
182 void *args)
183 {
184 int i, ret;
185 struct sidtab_node *last, *cur, *temp;
186
187 if (!s)
188 return;
189
190 for (i = 0; i < SIDTAB_SIZE; i++) {
191 last = NULL;
192 cur = s->htable[i];
193 while (cur != NULL) {
194 ret = apply(cur->sid, &cur->context, args);
195 if (ret) {
196 if (last) {
197 last->next = cur->next;
198 } else {
199 s->htable[i] = cur->next;
200 }
201
202 temp = cur;
203 cur = cur->next;
204 context_destroy(&temp->context);
205 kfree(temp);
206 s->nel--;
207 } else {
208 last = cur;
209 cur = cur->next;
210 }
211 }
212 }
213
214 return;
215 }
216
217 static inline u32 sidtab_search_context(struct sidtab *s,
218 struct context *context)
219 {
220 int i;
221 struct sidtab_node *cur;
222
223 for (i = 0; i < SIDTAB_SIZE; i++) {
224 cur = s->htable[i];
225 while (cur != NULL) {
226 if (context_cmp(&cur->context, context))
227 return cur->sid;
228 cur = cur->next;
229 }
230 }
231 return 0;
232 }
233
234 int sidtab_context_to_sid(struct sidtab *s,
235 struct context *context,
236 u32 *out_sid)
237 {
238 u32 sid;
239 int ret = 0;
240 unsigned long flags;
241
242 *out_sid = SECSID_NULL;
243
244 sid = sidtab_search_context(s, context);
245 if (!sid) {
246 SIDTAB_LOCK(s, flags);
247 /* Rescan now that we hold the lock. */
248 sid = sidtab_search_context(s, context);
249 if (sid)
250 goto unlock_out;
251 /* No SID exists for the context. Allocate a new one. */
252 if (s->next_sid == UINT_MAX || s->shutdown) {
253 ret = -ENOMEM;
254 goto unlock_out;
255 }
256 sid = s->next_sid++;
257 ret = sidtab_insert(s, sid, context);
258 if (ret)
259 s->next_sid--;
260 unlock_out:
261 SIDTAB_UNLOCK(s, flags);
262 }
263
264 if (ret)
265 return ret;
266
267 *out_sid = sid;
268 return 0;
269 }
270
271 void sidtab_hash_eval(struct sidtab *h, char *tag)
272 {
273 int i, chain_len, slots_used, max_chain_len;
274 struct sidtab_node *cur;
275
276 slots_used = 0;
277 max_chain_len = 0;
278 for (i = 0; i < SIDTAB_SIZE; i++) {
279 cur = h->htable[i];
280 if (cur) {
281 slots_used++;
282 chain_len = 0;
283 while (cur) {
284 chain_len++;
285 cur = cur->next;
286 }
287
288 if (chain_len > max_chain_len)
289 max_chain_len = chain_len;
290 }
291 }
292
293 printk(KERN_INFO "%s: %d entries and %d/%d buckets used, longest "
294 "chain length %d\n", tag, h->nel, slots_used, SIDTAB_SIZE,
295 max_chain_len);
296 }
297
298 void sidtab_destroy(struct sidtab *s)
299 {
300 int i;
301 struct sidtab_node *cur, *temp;
302
303 if (!s)
304 return;
305
306 for (i = 0; i < SIDTAB_SIZE; i++) {
307 cur = s->htable[i];
308 while (cur != NULL) {
309 temp = cur;
310 cur = cur->next;
311 context_destroy(&temp->context);
312 kfree(temp);
313 }
314 s->htable[i] = NULL;
315 }
316 kfree(s->htable);
317 s->htable = NULL;
318 s->nel = 0;
319 s->next_sid = 1;
320 }
321
322 void sidtab_set(struct sidtab *dst, struct sidtab *src)
323 {
324 unsigned long flags;
325
326 SIDTAB_LOCK(src, flags);
327 dst->htable = src->htable;
328 dst->nel = src->nel;
329 dst->next_sid = src->next_sid;
330 dst->shutdown = 0;
331 SIDTAB_UNLOCK(src, flags);
332 }
333
334 void sidtab_shutdown(struct sidtab *s)
335 {
336 unsigned long flags;
337
338 SIDTAB_LOCK(s, flags);
339 s->shutdown = 1;
340 SIDTAB_UNLOCK(s, flags);
341 }
342
|
This page was automatically generated by the
LXR engine.
|