diff options
Diffstat (limited to 'security/selinux/ss/policydb.c')
-rw-r--r-- | security/selinux/ss/policydb.c | 1843 |
1 files changed, 1843 insertions, 0 deletions
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c new file mode 100644 index 000000000000..14190efbf333 --- /dev/null +++ b/security/selinux/ss/policydb.c | |||
@@ -0,0 +1,1843 @@ | |||
1 | /* | ||
2 | * Implementation of the policy database. | ||
3 | * | ||
4 | * Author : Stephen Smalley, <sds@epoch.ncsc.mil> | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> | ||
9 | * | ||
10 | * Support for enhanced MLS infrastructure. | ||
11 | * | ||
12 | * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> | ||
13 | * | ||
14 | * Added conditional policy language extensions | ||
15 | * | ||
16 | * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. | ||
17 | * Copyright (C) 2003 - 2004 Tresys Technology, LLC | ||
18 | * This program is free software; you can redistribute it and/or modify | ||
19 | * it under the terms of the GNU General Public License as published by | ||
20 | * the Free Software Foundation, version 2. | ||
21 | */ | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/string.h> | ||
26 | #include <linux/errno.h> | ||
27 | #include "security.h" | ||
28 | |||
29 | #include "policydb.h" | ||
30 | #include "conditional.h" | ||
31 | #include "mls.h" | ||
32 | |||
33 | #define _DEBUG_HASHES | ||
34 | |||
35 | #ifdef DEBUG_HASHES | ||
36 | static char *symtab_name[SYM_NUM] = { | ||
37 | "common prefixes", | ||
38 | "classes", | ||
39 | "roles", | ||
40 | "types", | ||
41 | "users", | ||
42 | "bools", | ||
43 | "levels", | ||
44 | "categories", | ||
45 | }; | ||
46 | #endif | ||
47 | |||
48 | int selinux_mls_enabled = 0; | ||
49 | |||
50 | static unsigned int symtab_sizes[SYM_NUM] = { | ||
51 | 2, | ||
52 | 32, | ||
53 | 16, | ||
54 | 512, | ||
55 | 128, | ||
56 | 16, | ||
57 | 16, | ||
58 | 16, | ||
59 | }; | ||
60 | |||
61 | struct policydb_compat_info { | ||
62 | int version; | ||
63 | int sym_num; | ||
64 | int ocon_num; | ||
65 | }; | ||
66 | |||
67 | /* These need to be updated if SYM_NUM or OCON_NUM changes */ | ||
68 | static struct policydb_compat_info policydb_compat[] = { | ||
69 | { | ||
70 | .version = POLICYDB_VERSION_BASE, | ||
71 | .sym_num = SYM_NUM - 3, | ||
72 | .ocon_num = OCON_NUM - 1, | ||
73 | }, | ||
74 | { | ||
75 | .version = POLICYDB_VERSION_BOOL, | ||
76 | .sym_num = SYM_NUM - 2, | ||
77 | .ocon_num = OCON_NUM - 1, | ||
78 | }, | ||
79 | { | ||
80 | .version = POLICYDB_VERSION_IPV6, | ||
81 | .sym_num = SYM_NUM - 2, | ||
82 | .ocon_num = OCON_NUM, | ||
83 | }, | ||
84 | { | ||
85 | .version = POLICYDB_VERSION_NLCLASS, | ||
86 | .sym_num = SYM_NUM - 2, | ||
87 | .ocon_num = OCON_NUM, | ||
88 | }, | ||
89 | { | ||
90 | .version = POLICYDB_VERSION_MLS, | ||
91 | .sym_num = SYM_NUM, | ||
92 | .ocon_num = OCON_NUM, | ||
93 | }, | ||
94 | }; | ||
95 | |||
96 | static struct policydb_compat_info *policydb_lookup_compat(int version) | ||
97 | { | ||
98 | int i; | ||
99 | struct policydb_compat_info *info = NULL; | ||
100 | |||
101 | for (i = 0; i < sizeof(policydb_compat)/sizeof(*info); i++) { | ||
102 | if (policydb_compat[i].version == version) { | ||
103 | info = &policydb_compat[i]; | ||
104 | break; | ||
105 | } | ||
106 | } | ||
107 | return info; | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | * Initialize the role table. | ||
112 | */ | ||
113 | static int roles_init(struct policydb *p) | ||
114 | { | ||
115 | char *key = NULL; | ||
116 | int rc; | ||
117 | struct role_datum *role; | ||
118 | |||
119 | role = kmalloc(sizeof(*role), GFP_KERNEL); | ||
120 | if (!role) { | ||
121 | rc = -ENOMEM; | ||
122 | goto out; | ||
123 | } | ||
124 | memset(role, 0, sizeof(*role)); | ||
125 | role->value = ++p->p_roles.nprim; | ||
126 | if (role->value != OBJECT_R_VAL) { | ||
127 | rc = -EINVAL; | ||
128 | goto out_free_role; | ||
129 | } | ||
130 | key = kmalloc(strlen(OBJECT_R)+1,GFP_KERNEL); | ||
131 | if (!key) { | ||
132 | rc = -ENOMEM; | ||
133 | goto out_free_role; | ||
134 | } | ||
135 | strcpy(key, OBJECT_R); | ||
136 | rc = hashtab_insert(p->p_roles.table, key, role); | ||
137 | if (rc) | ||
138 | goto out_free_key; | ||
139 | out: | ||
140 | return rc; | ||
141 | |||
142 | out_free_key: | ||
143 | kfree(key); | ||
144 | out_free_role: | ||
145 | kfree(role); | ||
146 | goto out; | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | * Initialize a policy database structure. | ||
151 | */ | ||
152 | static int policydb_init(struct policydb *p) | ||
153 | { | ||
154 | int i, rc; | ||
155 | |||
156 | memset(p, 0, sizeof(*p)); | ||
157 | |||
158 | for (i = 0; i < SYM_NUM; i++) { | ||
159 | rc = symtab_init(&p->symtab[i], symtab_sizes[i]); | ||
160 | if (rc) | ||
161 | goto out_free_symtab; | ||
162 | } | ||
163 | |||
164 | rc = avtab_init(&p->te_avtab); | ||
165 | if (rc) | ||
166 | goto out_free_symtab; | ||
167 | |||
168 | rc = roles_init(p); | ||
169 | if (rc) | ||
170 | goto out_free_avtab; | ||
171 | |||
172 | rc = cond_policydb_init(p); | ||
173 | if (rc) | ||
174 | goto out_free_avtab; | ||
175 | |||
176 | out: | ||
177 | return rc; | ||
178 | |||
179 | out_free_avtab: | ||
180 | avtab_destroy(&p->te_avtab); | ||
181 | |||
182 | out_free_symtab: | ||
183 | for (i = 0; i < SYM_NUM; i++) | ||
184 | hashtab_destroy(p->symtab[i].table); | ||
185 | goto out; | ||
186 | } | ||
187 | |||
188 | /* | ||
189 | * The following *_index functions are used to | ||
190 | * define the val_to_name and val_to_struct arrays | ||
191 | * in a policy database structure. The val_to_name | ||
192 | * arrays are used when converting security context | ||
193 | * structures into string representations. The | ||
194 | * val_to_struct arrays are used when the attributes | ||
195 | * of a class, role, or user are needed. | ||
196 | */ | ||
197 | |||
198 | static int common_index(void *key, void *datum, void *datap) | ||
199 | { | ||
200 | struct policydb *p; | ||
201 | struct common_datum *comdatum; | ||
202 | |||
203 | comdatum = datum; | ||
204 | p = datap; | ||
205 | if (!comdatum->value || comdatum->value > p->p_commons.nprim) | ||
206 | return -EINVAL; | ||
207 | p->p_common_val_to_name[comdatum->value - 1] = key; | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static int class_index(void *key, void *datum, void *datap) | ||
212 | { | ||
213 | struct policydb *p; | ||
214 | struct class_datum *cladatum; | ||
215 | |||
216 | cladatum = datum; | ||
217 | p = datap; | ||
218 | if (!cladatum->value || cladatum->value > p->p_classes.nprim) | ||
219 | return -EINVAL; | ||
220 | p->p_class_val_to_name[cladatum->value - 1] = key; | ||
221 | p->class_val_to_struct[cladatum->value - 1] = cladatum; | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static int role_index(void *key, void *datum, void *datap) | ||
226 | { | ||
227 | struct policydb *p; | ||
228 | struct role_datum *role; | ||
229 | |||
230 | role = datum; | ||
231 | p = datap; | ||
232 | if (!role->value || role->value > p->p_roles.nprim) | ||
233 | return -EINVAL; | ||
234 | p->p_role_val_to_name[role->value - 1] = key; | ||
235 | p->role_val_to_struct[role->value - 1] = role; | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static int type_index(void *key, void *datum, void *datap) | ||
240 | { | ||
241 | struct policydb *p; | ||
242 | struct type_datum *typdatum; | ||
243 | |||
244 | typdatum = datum; | ||
245 | p = datap; | ||
246 | |||
247 | if (typdatum->primary) { | ||
248 | if (!typdatum->value || typdatum->value > p->p_types.nprim) | ||
249 | return -EINVAL; | ||
250 | p->p_type_val_to_name[typdatum->value - 1] = key; | ||
251 | } | ||
252 | |||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | static int user_index(void *key, void *datum, void *datap) | ||
257 | { | ||
258 | struct policydb *p; | ||
259 | struct user_datum *usrdatum; | ||
260 | |||
261 | usrdatum = datum; | ||
262 | p = datap; | ||
263 | if (!usrdatum->value || usrdatum->value > p->p_users.nprim) | ||
264 | return -EINVAL; | ||
265 | p->p_user_val_to_name[usrdatum->value - 1] = key; | ||
266 | p->user_val_to_struct[usrdatum->value - 1] = usrdatum; | ||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int sens_index(void *key, void *datum, void *datap) | ||
271 | { | ||
272 | struct policydb *p; | ||
273 | struct level_datum *levdatum; | ||
274 | |||
275 | levdatum = datum; | ||
276 | p = datap; | ||
277 | |||
278 | if (!levdatum->isalias) { | ||
279 | if (!levdatum->level->sens || | ||
280 | levdatum->level->sens > p->p_levels.nprim) | ||
281 | return -EINVAL; | ||
282 | p->p_sens_val_to_name[levdatum->level->sens - 1] = key; | ||
283 | } | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static int cat_index(void *key, void *datum, void *datap) | ||
289 | { | ||
290 | struct policydb *p; | ||
291 | struct cat_datum *catdatum; | ||
292 | |||
293 | catdatum = datum; | ||
294 | p = datap; | ||
295 | |||
296 | if (!catdatum->isalias) { | ||
297 | if (!catdatum->value || catdatum->value > p->p_cats.nprim) | ||
298 | return -EINVAL; | ||
299 | p->p_cat_val_to_name[catdatum->value - 1] = key; | ||
300 | } | ||
301 | |||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) = | ||
306 | { | ||
307 | common_index, | ||
308 | class_index, | ||
309 | role_index, | ||
310 | type_index, | ||
311 | user_index, | ||
312 | cond_index_bool, | ||
313 | sens_index, | ||
314 | cat_index, | ||
315 | }; | ||
316 | |||
317 | /* | ||
318 | * Define the common val_to_name array and the class | ||
319 | * val_to_name and val_to_struct arrays in a policy | ||
320 | * database structure. | ||
321 | * | ||
322 | * Caller must clean up upon failure. | ||
323 | */ | ||
324 | static int policydb_index_classes(struct policydb *p) | ||
325 | { | ||
326 | int rc; | ||
327 | |||
328 | p->p_common_val_to_name = | ||
329 | kmalloc(p->p_commons.nprim * sizeof(char *), GFP_KERNEL); | ||
330 | if (!p->p_common_val_to_name) { | ||
331 | rc = -ENOMEM; | ||
332 | goto out; | ||
333 | } | ||
334 | |||
335 | rc = hashtab_map(p->p_commons.table, common_index, p); | ||
336 | if (rc) | ||
337 | goto out; | ||
338 | |||
339 | p->class_val_to_struct = | ||
340 | kmalloc(p->p_classes.nprim * sizeof(*(p->class_val_to_struct)), GFP_KERNEL); | ||
341 | if (!p->class_val_to_struct) { | ||
342 | rc = -ENOMEM; | ||
343 | goto out; | ||
344 | } | ||
345 | |||
346 | p->p_class_val_to_name = | ||
347 | kmalloc(p->p_classes.nprim * sizeof(char *), GFP_KERNEL); | ||
348 | if (!p->p_class_val_to_name) { | ||
349 | rc = -ENOMEM; | ||
350 | goto out; | ||
351 | } | ||
352 | |||
353 | rc = hashtab_map(p->p_classes.table, class_index, p); | ||
354 | out: | ||
355 | return rc; | ||
356 | } | ||
357 | |||
358 | #ifdef DEBUG_HASHES | ||
359 | static void symtab_hash_eval(struct symtab *s) | ||
360 | { | ||
361 | int i; | ||
362 | |||
363 | for (i = 0; i < SYM_NUM; i++) { | ||
364 | struct hashtab *h = s[i].table; | ||
365 | struct hashtab_info info; | ||
366 | |||
367 | hashtab_stat(h, &info); | ||
368 | printk(KERN_INFO "%s: %d entries and %d/%d buckets used, " | ||
369 | "longest chain length %d\n", symtab_name[i], h->nel, | ||
370 | info.slots_used, h->size, info.max_chain_len); | ||
371 | } | ||
372 | } | ||
373 | #endif | ||
374 | |||
375 | /* | ||
376 | * Define the other val_to_name and val_to_struct arrays | ||
377 | * in a policy database structure. | ||
378 | * | ||
379 | * Caller must clean up on failure. | ||
380 | */ | ||
381 | static int policydb_index_others(struct policydb *p) | ||
382 | { | ||
383 | int i, rc = 0; | ||
384 | |||
385 | printk(KERN_INFO "security: %d users, %d roles, %d types, %d bools", | ||
386 | p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim); | ||
387 | if (selinux_mls_enabled) | ||
388 | printk(", %d sens, %d cats", p->p_levels.nprim, | ||
389 | p->p_cats.nprim); | ||
390 | printk("\n"); | ||
391 | |||
392 | printk(KERN_INFO "security: %d classes, %d rules\n", | ||
393 | p->p_classes.nprim, p->te_avtab.nel); | ||
394 | |||
395 | #ifdef DEBUG_HASHES | ||
396 | avtab_hash_eval(&p->te_avtab, "rules"); | ||
397 | symtab_hash_eval(p->symtab); | ||
398 | #endif | ||
399 | |||
400 | p->role_val_to_struct = | ||
401 | kmalloc(p->p_roles.nprim * sizeof(*(p->role_val_to_struct)), | ||
402 | GFP_KERNEL); | ||
403 | if (!p->role_val_to_struct) { | ||
404 | rc = -ENOMEM; | ||
405 | goto out; | ||
406 | } | ||
407 | |||
408 | p->user_val_to_struct = | ||
409 | kmalloc(p->p_users.nprim * sizeof(*(p->user_val_to_struct)), | ||
410 | GFP_KERNEL); | ||
411 | if (!p->user_val_to_struct) { | ||
412 | rc = -ENOMEM; | ||
413 | goto out; | ||
414 | } | ||
415 | |||
416 | if (cond_init_bool_indexes(p)) { | ||
417 | rc = -ENOMEM; | ||
418 | goto out; | ||
419 | } | ||
420 | |||
421 | for (i = SYM_ROLES; i < SYM_NUM; i++) { | ||
422 | p->sym_val_to_name[i] = | ||
423 | kmalloc(p->symtab[i].nprim * sizeof(char *), GFP_KERNEL); | ||
424 | if (!p->sym_val_to_name[i]) { | ||
425 | rc = -ENOMEM; | ||
426 | goto out; | ||
427 | } | ||
428 | rc = hashtab_map(p->symtab[i].table, index_f[i], p); | ||
429 | if (rc) | ||
430 | goto out; | ||
431 | } | ||
432 | |||
433 | out: | ||
434 | return rc; | ||
435 | } | ||
436 | |||
437 | /* | ||
438 | * The following *_destroy functions are used to | ||
439 | * free any memory allocated for each kind of | ||
440 | * symbol data in the policy database. | ||
441 | */ | ||
442 | |||
443 | static int perm_destroy(void *key, void *datum, void *p) | ||
444 | { | ||
445 | kfree(key); | ||
446 | kfree(datum); | ||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | static int common_destroy(void *key, void *datum, void *p) | ||
451 | { | ||
452 | struct common_datum *comdatum; | ||
453 | |||
454 | kfree(key); | ||
455 | comdatum = datum; | ||
456 | hashtab_map(comdatum->permissions.table, perm_destroy, NULL); | ||
457 | hashtab_destroy(comdatum->permissions.table); | ||
458 | kfree(datum); | ||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | static int class_destroy(void *key, void *datum, void *p) | ||
463 | { | ||
464 | struct class_datum *cladatum; | ||
465 | struct constraint_node *constraint, *ctemp; | ||
466 | struct constraint_expr *e, *etmp; | ||
467 | |||
468 | kfree(key); | ||
469 | cladatum = datum; | ||
470 | hashtab_map(cladatum->permissions.table, perm_destroy, NULL); | ||
471 | hashtab_destroy(cladatum->permissions.table); | ||
472 | constraint = cladatum->constraints; | ||
473 | while (constraint) { | ||
474 | e = constraint->expr; | ||
475 | while (e) { | ||
476 | ebitmap_destroy(&e->names); | ||
477 | etmp = e; | ||
478 | e = e->next; | ||
479 | kfree(etmp); | ||
480 | } | ||
481 | ctemp = constraint; | ||
482 | constraint = constraint->next; | ||
483 | kfree(ctemp); | ||
484 | } | ||
485 | |||
486 | constraint = cladatum->validatetrans; | ||
487 | while (constraint) { | ||
488 | e = constraint->expr; | ||
489 | while (e) { | ||
490 | ebitmap_destroy(&e->names); | ||
491 | etmp = e; | ||
492 | e = e->next; | ||
493 | kfree(etmp); | ||
494 | } | ||
495 | ctemp = constraint; | ||
496 | constraint = constraint->next; | ||
497 | kfree(ctemp); | ||
498 | } | ||
499 | |||
500 | kfree(cladatum->comkey); | ||
501 | kfree(datum); | ||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | static int role_destroy(void *key, void *datum, void *p) | ||
506 | { | ||
507 | struct role_datum *role; | ||
508 | |||
509 | kfree(key); | ||
510 | role = datum; | ||
511 | ebitmap_destroy(&role->dominates); | ||
512 | ebitmap_destroy(&role->types); | ||
513 | kfree(datum); | ||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | static int type_destroy(void *key, void *datum, void *p) | ||
518 | { | ||
519 | kfree(key); | ||
520 | kfree(datum); | ||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | static int user_destroy(void *key, void *datum, void *p) | ||
525 | { | ||
526 | struct user_datum *usrdatum; | ||
527 | |||
528 | kfree(key); | ||
529 | usrdatum = datum; | ||
530 | ebitmap_destroy(&usrdatum->roles); | ||
531 | ebitmap_destroy(&usrdatum->range.level[0].cat); | ||
532 | ebitmap_destroy(&usrdatum->range.level[1].cat); | ||
533 | ebitmap_destroy(&usrdatum->dfltlevel.cat); | ||
534 | kfree(datum); | ||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | static int sens_destroy(void *key, void *datum, void *p) | ||
539 | { | ||
540 | struct level_datum *levdatum; | ||
541 | |||
542 | kfree(key); | ||
543 | levdatum = datum; | ||
544 | ebitmap_destroy(&levdatum->level->cat); | ||
545 | kfree(levdatum->level); | ||
546 | kfree(datum); | ||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | static int cat_destroy(void *key, void *datum, void *p) | ||
551 | { | ||
552 | kfree(key); | ||
553 | kfree(datum); | ||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = | ||
558 | { | ||
559 | common_destroy, | ||
560 | class_destroy, | ||
561 | role_destroy, | ||
562 | type_destroy, | ||
563 | user_destroy, | ||
564 | cond_destroy_bool, | ||
565 | sens_destroy, | ||
566 | cat_destroy, | ||
567 | }; | ||
568 | |||
569 | static void ocontext_destroy(struct ocontext *c, int i) | ||
570 | { | ||
571 | context_destroy(&c->context[0]); | ||
572 | context_destroy(&c->context[1]); | ||
573 | if (i == OCON_ISID || i == OCON_FS || | ||
574 | i == OCON_NETIF || i == OCON_FSUSE) | ||
575 | kfree(c->u.name); | ||
576 | kfree(c); | ||
577 | } | ||
578 | |||
579 | /* | ||
580 | * Free any memory allocated by a policy database structure. | ||
581 | */ | ||
582 | void policydb_destroy(struct policydb *p) | ||
583 | { | ||
584 | struct ocontext *c, *ctmp; | ||
585 | struct genfs *g, *gtmp; | ||
586 | int i; | ||
587 | |||
588 | for (i = 0; i < SYM_NUM; i++) { | ||
589 | hashtab_map(p->symtab[i].table, destroy_f[i], NULL); | ||
590 | hashtab_destroy(p->symtab[i].table); | ||
591 | } | ||
592 | |||
593 | for (i = 0; i < SYM_NUM; i++) { | ||
594 | if (p->sym_val_to_name[i]) | ||
595 | kfree(p->sym_val_to_name[i]); | ||
596 | } | ||
597 | |||
598 | if (p->class_val_to_struct) | ||
599 | kfree(p->class_val_to_struct); | ||
600 | if (p->role_val_to_struct) | ||
601 | kfree(p->role_val_to_struct); | ||
602 | if (p->user_val_to_struct) | ||
603 | kfree(p->user_val_to_struct); | ||
604 | |||
605 | avtab_destroy(&p->te_avtab); | ||
606 | |||
607 | for (i = 0; i < OCON_NUM; i++) { | ||
608 | c = p->ocontexts[i]; | ||
609 | while (c) { | ||
610 | ctmp = c; | ||
611 | c = c->next; | ||
612 | ocontext_destroy(ctmp,i); | ||
613 | } | ||
614 | } | ||
615 | |||
616 | g = p->genfs; | ||
617 | while (g) { | ||
618 | kfree(g->fstype); | ||
619 | c = g->head; | ||
620 | while (c) { | ||
621 | ctmp = c; | ||
622 | c = c->next; | ||
623 | ocontext_destroy(ctmp,OCON_FSUSE); | ||
624 | } | ||
625 | gtmp = g; | ||
626 | g = g->next; | ||
627 | kfree(gtmp); | ||
628 | } | ||
629 | |||
630 | cond_policydb_destroy(p); | ||
631 | |||
632 | return; | ||
633 | } | ||
634 | |||
635 | /* | ||
636 | * Load the initial SIDs specified in a policy database | ||
637 | * structure into a SID table. | ||
638 | */ | ||
639 | int policydb_load_isids(struct policydb *p, struct sidtab *s) | ||
640 | { | ||
641 | struct ocontext *head, *c; | ||
642 | int rc; | ||
643 | |||
644 | rc = sidtab_init(s); | ||
645 | if (rc) { | ||
646 | printk(KERN_ERR "security: out of memory on SID table init\n"); | ||
647 | goto out; | ||
648 | } | ||
649 | |||
650 | head = p->ocontexts[OCON_ISID]; | ||
651 | for (c = head; c; c = c->next) { | ||
652 | if (!c->context[0].user) { | ||
653 | printk(KERN_ERR "security: SID %s was never " | ||
654 | "defined.\n", c->u.name); | ||
655 | rc = -EINVAL; | ||
656 | goto out; | ||
657 | } | ||
658 | if (sidtab_insert(s, c->sid[0], &c->context[0])) { | ||
659 | printk(KERN_ERR "security: unable to load initial " | ||
660 | "SID %s.\n", c->u.name); | ||
661 | rc = -EINVAL; | ||
662 | goto out; | ||
663 | } | ||
664 | } | ||
665 | out: | ||
666 | return rc; | ||
667 | } | ||
668 | |||
669 | /* | ||
670 | * Return 1 if the fields in the security context | ||
671 | * structure `c' are valid. Return 0 otherwise. | ||
672 | */ | ||
673 | int policydb_context_isvalid(struct policydb *p, struct context *c) | ||
674 | { | ||
675 | struct role_datum *role; | ||
676 | struct user_datum *usrdatum; | ||
677 | |||
678 | if (!c->role || c->role > p->p_roles.nprim) | ||
679 | return 0; | ||
680 | |||
681 | if (!c->user || c->user > p->p_users.nprim) | ||
682 | return 0; | ||
683 | |||
684 | if (!c->type || c->type > p->p_types.nprim) | ||
685 | return 0; | ||
686 | |||
687 | if (c->role != OBJECT_R_VAL) { | ||
688 | /* | ||
689 | * Role must be authorized for the type. | ||
690 | */ | ||
691 | role = p->role_val_to_struct[c->role - 1]; | ||
692 | if (!ebitmap_get_bit(&role->types, | ||
693 | c->type - 1)) | ||
694 | /* role may not be associated with type */ | ||
695 | return 0; | ||
696 | |||
697 | /* | ||
698 | * User must be authorized for the role. | ||
699 | */ | ||
700 | usrdatum = p->user_val_to_struct[c->user - 1]; | ||
701 | if (!usrdatum) | ||
702 | return 0; | ||
703 | |||
704 | if (!ebitmap_get_bit(&usrdatum->roles, | ||
705 | c->role - 1)) | ||
706 | /* user may not be associated with role */ | ||
707 | return 0; | ||
708 | } | ||
709 | |||
710 | if (!mls_context_isvalid(p, c)) | ||
711 | return 0; | ||
712 | |||
713 | return 1; | ||
714 | } | ||
715 | |||
716 | /* | ||
717 | * Read a MLS range structure from a policydb binary | ||
718 | * representation file. | ||
719 | */ | ||
720 | static int mls_read_range_helper(struct mls_range *r, void *fp) | ||
721 | { | ||
722 | u32 buf[2], items; | ||
723 | int rc; | ||
724 | |||
725 | rc = next_entry(buf, fp, sizeof(u32)); | ||
726 | if (rc < 0) | ||
727 | goto out; | ||
728 | |||
729 | items = le32_to_cpu(buf[0]); | ||
730 | if (items > ARRAY_SIZE(buf)) { | ||
731 | printk(KERN_ERR "security: mls: range overflow\n"); | ||
732 | rc = -EINVAL; | ||
733 | goto out; | ||
734 | } | ||
735 | rc = next_entry(buf, fp, sizeof(u32) * items); | ||
736 | if (rc < 0) { | ||
737 | printk(KERN_ERR "security: mls: truncated range\n"); | ||
738 | goto out; | ||
739 | } | ||
740 | r->level[0].sens = le32_to_cpu(buf[0]); | ||
741 | if (items > 1) | ||
742 | r->level[1].sens = le32_to_cpu(buf[1]); | ||
743 | else | ||
744 | r->level[1].sens = r->level[0].sens; | ||
745 | |||
746 | rc = ebitmap_read(&r->level[0].cat, fp); | ||
747 | if (rc) { | ||
748 | printk(KERN_ERR "security: mls: error reading low " | ||
749 | "categories\n"); | ||
750 | goto out; | ||
751 | } | ||
752 | if (items > 1) { | ||
753 | rc = ebitmap_read(&r->level[1].cat, fp); | ||
754 | if (rc) { | ||
755 | printk(KERN_ERR "security: mls: error reading high " | ||
756 | "categories\n"); | ||
757 | goto bad_high; | ||
758 | } | ||
759 | } else { | ||
760 | rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat); | ||
761 | if (rc) { | ||
762 | printk(KERN_ERR "security: mls: out of memory\n"); | ||
763 | goto bad_high; | ||
764 | } | ||
765 | } | ||
766 | |||
767 | rc = 0; | ||
768 | out: | ||
769 | return rc; | ||
770 | bad_high: | ||
771 | ebitmap_destroy(&r->level[0].cat); | ||
772 | goto out; | ||
773 | } | ||
774 | |||
775 | /* | ||
776 | * Read and validate a security context structure | ||
777 | * from a policydb binary representation file. | ||
778 | */ | ||
779 | static int context_read_and_validate(struct context *c, | ||
780 | struct policydb *p, | ||
781 | void *fp) | ||
782 | { | ||
783 | u32 buf[3]; | ||
784 | int rc; | ||
785 | |||
786 | rc = next_entry(buf, fp, sizeof buf); | ||
787 | if (rc < 0) { | ||
788 | printk(KERN_ERR "security: context truncated\n"); | ||
789 | goto out; | ||
790 | } | ||
791 | c->user = le32_to_cpu(buf[0]); | ||
792 | c->role = le32_to_cpu(buf[1]); | ||
793 | c->type = le32_to_cpu(buf[2]); | ||
794 | if (p->policyvers >= POLICYDB_VERSION_MLS) { | ||
795 | if (mls_read_range_helper(&c->range, fp)) { | ||
796 | printk(KERN_ERR "security: error reading MLS range of " | ||
797 | "context\n"); | ||
798 | rc = -EINVAL; | ||
799 | goto out; | ||
800 | } | ||
801 | } | ||
802 | |||
803 | if (!policydb_context_isvalid(p, c)) { | ||
804 | printk(KERN_ERR "security: invalid security context\n"); | ||
805 | context_destroy(c); | ||
806 | rc = -EINVAL; | ||
807 | } | ||
808 | out: | ||
809 | return rc; | ||
810 | } | ||
811 | |||
812 | /* | ||
813 | * The following *_read functions are used to | ||
814 | * read the symbol data from a policy database | ||
815 | * binary representation file. | ||
816 | */ | ||
817 | |||
818 | static int perm_read(struct policydb *p, struct hashtab *h, void *fp) | ||
819 | { | ||
820 | char *key = NULL; | ||
821 | struct perm_datum *perdatum; | ||
822 | int rc; | ||
823 | u32 buf[2], len; | ||
824 | |||
825 | perdatum = kmalloc(sizeof(*perdatum), GFP_KERNEL); | ||
826 | if (!perdatum) { | ||
827 | rc = -ENOMEM; | ||
828 | goto out; | ||
829 | } | ||
830 | memset(perdatum, 0, sizeof(*perdatum)); | ||
831 | |||
832 | rc = next_entry(buf, fp, sizeof buf); | ||
833 | if (rc < 0) | ||
834 | goto bad; | ||
835 | |||
836 | len = le32_to_cpu(buf[0]); | ||
837 | perdatum->value = le32_to_cpu(buf[1]); | ||
838 | |||
839 | key = kmalloc(len + 1,GFP_KERNEL); | ||
840 | if (!key) { | ||
841 | rc = -ENOMEM; | ||
842 | goto bad; | ||
843 | } | ||
844 | rc = next_entry(key, fp, len); | ||
845 | if (rc < 0) | ||
846 | goto bad; | ||
847 | key[len] = 0; | ||
848 | |||
849 | rc = hashtab_insert(h, key, perdatum); | ||
850 | if (rc) | ||
851 | goto bad; | ||
852 | out: | ||
853 | return rc; | ||
854 | bad: | ||
855 | perm_destroy(key, perdatum, NULL); | ||
856 | goto out; | ||
857 | } | ||
858 | |||
859 | static int common_read(struct policydb *p, struct hashtab *h, void *fp) | ||
860 | { | ||
861 | char *key = NULL; | ||
862 | struct common_datum *comdatum; | ||
863 | u32 buf[4], len, nel; | ||
864 | int i, rc; | ||
865 | |||
866 | comdatum = kmalloc(sizeof(*comdatum), GFP_KERNEL); | ||
867 | if (!comdatum) { | ||
868 | rc = -ENOMEM; | ||
869 | goto out; | ||
870 | } | ||
871 | memset(comdatum, 0, sizeof(*comdatum)); | ||
872 | |||
873 | rc = next_entry(buf, fp, sizeof buf); | ||
874 | if (rc < 0) | ||
875 | goto bad; | ||
876 | |||
877 | len = le32_to_cpu(buf[0]); | ||
878 | comdatum->value = le32_to_cpu(buf[1]); | ||
879 | |||
880 | rc = symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE); | ||
881 | if (rc) | ||
882 | goto bad; | ||
883 | comdatum->permissions.nprim = le32_to_cpu(buf[2]); | ||
884 | nel = le32_to_cpu(buf[3]); | ||
885 | |||
886 | key = kmalloc(len + 1,GFP_KERNEL); | ||
887 | if (!key) { | ||
888 | rc = -ENOMEM; | ||
889 | goto bad; | ||
890 | } | ||
891 | rc = next_entry(key, fp, len); | ||
892 | if (rc < 0) | ||
893 | goto bad; | ||
894 | key[len] = 0; | ||
895 | |||
896 | for (i = 0; i < nel; i++) { | ||
897 | rc = perm_read(p, comdatum->permissions.table, fp); | ||
898 | if (rc) | ||
899 | goto bad; | ||
900 | } | ||
901 | |||
902 | rc = hashtab_insert(h, key, comdatum); | ||
903 | if (rc) | ||
904 | goto bad; | ||
905 | out: | ||
906 | return rc; | ||
907 | bad: | ||
908 | common_destroy(key, comdatum, NULL); | ||
909 | goto out; | ||
910 | } | ||
911 | |||
912 | static int read_cons_helper(struct constraint_node **nodep, int ncons, | ||
913 | int allowxtarget, void *fp) | ||
914 | { | ||
915 | struct constraint_node *c, *lc; | ||
916 | struct constraint_expr *e, *le; | ||
917 | u32 buf[3], nexpr; | ||
918 | int rc, i, j, depth; | ||
919 | |||
920 | lc = NULL; | ||
921 | for (i = 0; i < ncons; i++) { | ||
922 | c = kmalloc(sizeof(*c), GFP_KERNEL); | ||
923 | if (!c) | ||
924 | return -ENOMEM; | ||
925 | memset(c, 0, sizeof(*c)); | ||
926 | |||
927 | if (lc) { | ||
928 | lc->next = c; | ||
929 | } else { | ||
930 | *nodep = c; | ||
931 | } | ||
932 | |||
933 | rc = next_entry(buf, fp, (sizeof(u32) * 2)); | ||
934 | if (rc < 0) | ||
935 | return rc; | ||
936 | c->permissions = le32_to_cpu(buf[0]); | ||
937 | nexpr = le32_to_cpu(buf[1]); | ||
938 | le = NULL; | ||
939 | depth = -1; | ||
940 | for (j = 0; j < nexpr; j++) { | ||
941 | e = kmalloc(sizeof(*e), GFP_KERNEL); | ||
942 | if (!e) | ||
943 | return -ENOMEM; | ||
944 | memset(e, 0, sizeof(*e)); | ||
945 | |||
946 | if (le) { | ||
947 | le->next = e; | ||
948 | } else { | ||
949 | c->expr = e; | ||
950 | } | ||
951 | |||
952 | rc = next_entry(buf, fp, (sizeof(u32) * 3)); | ||
953 | if (rc < 0) | ||
954 | return rc; | ||
955 | e->expr_type = le32_to_cpu(buf[0]); | ||
956 | e->attr = le32_to_cpu(buf[1]); | ||
957 | e->op = le32_to_cpu(buf[2]); | ||
958 | |||
959 | switch (e->expr_type) { | ||
960 | case CEXPR_NOT: | ||
961 | if (depth < 0) | ||
962 | return -EINVAL; | ||
963 | break; | ||
964 | case CEXPR_AND: | ||
965 | case CEXPR_OR: | ||
966 | if (depth < 1) | ||
967 | return -EINVAL; | ||
968 | depth--; | ||
969 | break; | ||
970 | case CEXPR_ATTR: | ||
971 | if (depth == (CEXPR_MAXDEPTH - 1)) | ||
972 | return -EINVAL; | ||
973 | depth++; | ||
974 | break; | ||
975 | case CEXPR_NAMES: | ||
976 | if (!allowxtarget && (e->attr & CEXPR_XTARGET)) | ||
977 | return -EINVAL; | ||
978 | if (depth == (CEXPR_MAXDEPTH - 1)) | ||
979 | return -EINVAL; | ||
980 | depth++; | ||
981 | if (ebitmap_read(&e->names, fp)) | ||
982 | return -EINVAL; | ||
983 | break; | ||
984 | default: | ||
985 | return -EINVAL; | ||
986 | } | ||
987 | le = e; | ||
988 | } | ||
989 | if (depth != 0) | ||
990 | return -EINVAL; | ||
991 | lc = c; | ||
992 | } | ||
993 | |||
994 | return 0; | ||
995 | } | ||
996 | |||
997 | static int class_read(struct policydb *p, struct hashtab *h, void *fp) | ||
998 | { | ||
999 | char *key = NULL; | ||
1000 | struct class_datum *cladatum; | ||
1001 | u32 buf[6], len, len2, ncons, nel; | ||
1002 | int i, rc; | ||
1003 | |||
1004 | cladatum = kmalloc(sizeof(*cladatum), GFP_KERNEL); | ||
1005 | if (!cladatum) { | ||
1006 | rc = -ENOMEM; | ||
1007 | goto out; | ||
1008 | } | ||
1009 | memset(cladatum, 0, sizeof(*cladatum)); | ||
1010 | |||
1011 | rc = next_entry(buf, fp, sizeof(u32)*6); | ||
1012 | if (rc < 0) | ||
1013 | goto bad; | ||
1014 | |||
1015 | len = le32_to_cpu(buf[0]); | ||
1016 | len2 = le32_to_cpu(buf[1]); | ||
1017 | cladatum->value = le32_to_cpu(buf[2]); | ||
1018 | |||
1019 | rc = symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE); | ||
1020 | if (rc) | ||
1021 | goto bad; | ||
1022 | cladatum->permissions.nprim = le32_to_cpu(buf[3]); | ||
1023 | nel = le32_to_cpu(buf[4]); | ||
1024 | |||
1025 | ncons = le32_to_cpu(buf[5]); | ||
1026 | |||
1027 | key = kmalloc(len + 1,GFP_KERNEL); | ||
1028 | if (!key) { | ||
1029 | rc = -ENOMEM; | ||
1030 | goto bad; | ||
1031 | } | ||
1032 | rc = next_entry(key, fp, len); | ||
1033 | if (rc < 0) | ||
1034 | goto bad; | ||
1035 | key[len] = 0; | ||
1036 | |||
1037 | if (len2) { | ||
1038 | cladatum->comkey = kmalloc(len2 + 1,GFP_KERNEL); | ||
1039 | if (!cladatum->comkey) { | ||
1040 | rc = -ENOMEM; | ||
1041 | goto bad; | ||
1042 | } | ||
1043 | rc = next_entry(cladatum->comkey, fp, len2); | ||
1044 | if (rc < 0) | ||
1045 | goto bad; | ||
1046 | cladatum->comkey[len2] = 0; | ||
1047 | |||
1048 | cladatum->comdatum = hashtab_search(p->p_commons.table, | ||
1049 | cladatum->comkey); | ||
1050 | if (!cladatum->comdatum) { | ||
1051 | printk(KERN_ERR "security: unknown common %s\n", | ||
1052 | cladatum->comkey); | ||
1053 | rc = -EINVAL; | ||
1054 | goto bad; | ||
1055 | } | ||
1056 | } | ||
1057 | for (i = 0; i < nel; i++) { | ||
1058 | rc = perm_read(p, cladatum->permissions.table, fp); | ||
1059 | if (rc) | ||
1060 | goto bad; | ||
1061 | } | ||
1062 | |||
1063 | rc = read_cons_helper(&cladatum->constraints, ncons, 0, fp); | ||
1064 | if (rc) | ||
1065 | goto bad; | ||
1066 | |||
1067 | if (p->policyvers >= POLICYDB_VERSION_VALIDATETRANS) { | ||
1068 | /* grab the validatetrans rules */ | ||
1069 | rc = next_entry(buf, fp, sizeof(u32)); | ||
1070 | if (rc < 0) | ||
1071 | goto bad; | ||
1072 | ncons = le32_to_cpu(buf[0]); | ||
1073 | rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp); | ||
1074 | if (rc) | ||
1075 | goto bad; | ||
1076 | } | ||
1077 | |||
1078 | rc = hashtab_insert(h, key, cladatum); | ||
1079 | if (rc) | ||
1080 | goto bad; | ||
1081 | |||
1082 | rc = 0; | ||
1083 | out: | ||
1084 | return rc; | ||
1085 | bad: | ||
1086 | class_destroy(key, cladatum, NULL); | ||
1087 | goto out; | ||
1088 | } | ||
1089 | |||
1090 | static int role_read(struct policydb *p, struct hashtab *h, void *fp) | ||
1091 | { | ||
1092 | char *key = NULL; | ||
1093 | struct role_datum *role; | ||
1094 | int rc; | ||
1095 | u32 buf[2], len; | ||
1096 | |||
1097 | role = kmalloc(sizeof(*role), GFP_KERNEL); | ||
1098 | if (!role) { | ||
1099 | rc = -ENOMEM; | ||
1100 | goto out; | ||
1101 | } | ||
1102 | memset(role, 0, sizeof(*role)); | ||
1103 | |||
1104 | rc = next_entry(buf, fp, sizeof buf); | ||
1105 | if (rc < 0) | ||
1106 | goto bad; | ||
1107 | |||
1108 | len = le32_to_cpu(buf[0]); | ||
1109 | role->value = le32_to_cpu(buf[1]); | ||
1110 | |||
1111 | key = kmalloc(len + 1,GFP_KERNEL); | ||
1112 | if (!key) { | ||
1113 | rc = -ENOMEM; | ||
1114 | goto bad; | ||
1115 | } | ||
1116 | rc = next_entry(key, fp, len); | ||
1117 | if (rc < 0) | ||
1118 | goto bad; | ||
1119 | key[len] = 0; | ||
1120 | |||
1121 | rc = ebitmap_read(&role->dominates, fp); | ||
1122 | if (rc) | ||
1123 | goto bad; | ||
1124 | |||
1125 | rc = ebitmap_read(&role->types, fp); | ||
1126 | if (rc) | ||
1127 | goto bad; | ||
1128 | |||
1129 | if (strcmp(key, OBJECT_R) == 0) { | ||
1130 | if (role->value != OBJECT_R_VAL) { | ||
1131 | printk(KERN_ERR "Role %s has wrong value %d\n", | ||
1132 | OBJECT_R, role->value); | ||
1133 | rc = -EINVAL; | ||
1134 | goto bad; | ||
1135 | } | ||
1136 | rc = 0; | ||
1137 | goto bad; | ||
1138 | } | ||
1139 | |||
1140 | rc = hashtab_insert(h, key, role); | ||
1141 | if (rc) | ||
1142 | goto bad; | ||
1143 | out: | ||
1144 | return rc; | ||
1145 | bad: | ||
1146 | role_destroy(key, role, NULL); | ||
1147 | goto out; | ||
1148 | } | ||
1149 | |||
1150 | static int type_read(struct policydb *p, struct hashtab *h, void *fp) | ||
1151 | { | ||
1152 | char *key = NULL; | ||
1153 | struct type_datum *typdatum; | ||
1154 | int rc; | ||
1155 | u32 buf[3], len; | ||
1156 | |||
1157 | typdatum = kmalloc(sizeof(*typdatum),GFP_KERNEL); | ||
1158 | if (!typdatum) { | ||
1159 | rc = -ENOMEM; | ||
1160 | return rc; | ||
1161 | } | ||
1162 | memset(typdatum, 0, sizeof(*typdatum)); | ||
1163 | |||
1164 | rc = next_entry(buf, fp, sizeof buf); | ||
1165 | if (rc < 0) | ||
1166 | goto bad; | ||
1167 | |||
1168 | len = le32_to_cpu(buf[0]); | ||
1169 | typdatum->value = le32_to_cpu(buf[1]); | ||
1170 | typdatum->primary = le32_to_cpu(buf[2]); | ||
1171 | |||
1172 | key = kmalloc(len + 1,GFP_KERNEL); | ||
1173 | if (!key) { | ||
1174 | rc = -ENOMEM; | ||
1175 | goto bad; | ||
1176 | } | ||
1177 | rc = next_entry(key, fp, len); | ||
1178 | if (rc < 0) | ||
1179 | goto bad; | ||
1180 | key[len] = 0; | ||
1181 | |||
1182 | rc = hashtab_insert(h, key, typdatum); | ||
1183 | if (rc) | ||
1184 | goto bad; | ||
1185 | out: | ||
1186 | return rc; | ||
1187 | bad: | ||
1188 | type_destroy(key, typdatum, NULL); | ||
1189 | goto out; | ||
1190 | } | ||
1191 | |||
1192 | |||
1193 | /* | ||
1194 | * Read a MLS level structure from a policydb binary | ||
1195 | * representation file. | ||
1196 | */ | ||
1197 | static int mls_read_level(struct mls_level *lp, void *fp) | ||
1198 | { | ||
1199 | u32 buf[1]; | ||
1200 | int rc; | ||
1201 | |||
1202 | memset(lp, 0, sizeof(*lp)); | ||
1203 | |||
1204 | rc = next_entry(buf, fp, sizeof buf); | ||
1205 | if (rc < 0) { | ||
1206 | printk(KERN_ERR "security: mls: truncated level\n"); | ||
1207 | goto bad; | ||
1208 | } | ||
1209 | lp->sens = le32_to_cpu(buf[0]); | ||
1210 | |||
1211 | if (ebitmap_read(&lp->cat, fp)) { | ||
1212 | printk(KERN_ERR "security: mls: error reading level " | ||
1213 | "categories\n"); | ||
1214 | goto bad; | ||
1215 | } | ||
1216 | return 0; | ||
1217 | |||
1218 | bad: | ||
1219 | return -EINVAL; | ||
1220 | } | ||
1221 | |||
1222 | static int user_read(struct policydb *p, struct hashtab *h, void *fp) | ||
1223 | { | ||
1224 | char *key = NULL; | ||
1225 | struct user_datum *usrdatum; | ||
1226 | int rc; | ||
1227 | u32 buf[2], len; | ||
1228 | |||
1229 | usrdatum = kmalloc(sizeof(*usrdatum), GFP_KERNEL); | ||
1230 | if (!usrdatum) { | ||
1231 | rc = -ENOMEM; | ||
1232 | goto out; | ||
1233 | } | ||
1234 | memset(usrdatum, 0, sizeof(*usrdatum)); | ||
1235 | |||
1236 | rc = next_entry(buf, fp, sizeof buf); | ||
1237 | if (rc < 0) | ||
1238 | goto bad; | ||
1239 | |||
1240 | len = le32_to_cpu(buf[0]); | ||
1241 | usrdatum->value = le32_to_cpu(buf[1]); | ||
1242 | |||
1243 | key = kmalloc(len + 1,GFP_KERNEL); | ||
1244 | if (!key) { | ||
1245 | rc = -ENOMEM; | ||
1246 | goto bad; | ||
1247 | } | ||
1248 | rc = next_entry(key, fp, len); | ||
1249 | if (rc < 0) | ||
1250 | goto bad; | ||
1251 | key[len] = 0; | ||
1252 | |||
1253 | rc = ebitmap_read(&usrdatum->roles, fp); | ||
1254 | if (rc) | ||
1255 | goto bad; | ||
1256 | |||
1257 | if (p->policyvers >= POLICYDB_VERSION_MLS) { | ||
1258 | rc = mls_read_range_helper(&usrdatum->range, fp); | ||
1259 | if (rc) | ||
1260 | goto bad; | ||
1261 | rc = mls_read_level(&usrdatum->dfltlevel, fp); | ||
1262 | if (rc) | ||
1263 | goto bad; | ||
1264 | } | ||
1265 | |||
1266 | rc = hashtab_insert(h, key, usrdatum); | ||
1267 | if (rc) | ||
1268 | goto bad; | ||
1269 | out: | ||
1270 | return rc; | ||
1271 | bad: | ||
1272 | user_destroy(key, usrdatum, NULL); | ||
1273 | goto out; | ||
1274 | } | ||
1275 | |||
1276 | static int sens_read(struct policydb *p, struct hashtab *h, void *fp) | ||
1277 | { | ||
1278 | char *key = NULL; | ||
1279 | struct level_datum *levdatum; | ||
1280 | int rc; | ||
1281 | u32 buf[2], len; | ||
1282 | |||
1283 | levdatum = kmalloc(sizeof(*levdatum), GFP_ATOMIC); | ||
1284 | if (!levdatum) { | ||
1285 | rc = -ENOMEM; | ||
1286 | goto out; | ||
1287 | } | ||
1288 | memset(levdatum, 0, sizeof(*levdatum)); | ||
1289 | |||
1290 | rc = next_entry(buf, fp, sizeof buf); | ||
1291 | if (rc < 0) | ||
1292 | goto bad; | ||
1293 | |||
1294 | len = le32_to_cpu(buf[0]); | ||
1295 | levdatum->isalias = le32_to_cpu(buf[1]); | ||
1296 | |||
1297 | key = kmalloc(len + 1,GFP_ATOMIC); | ||
1298 | if (!key) { | ||
1299 | rc = -ENOMEM; | ||
1300 | goto bad; | ||
1301 | } | ||
1302 | rc = next_entry(key, fp, len); | ||
1303 | if (rc < 0) | ||
1304 | goto bad; | ||
1305 | key[len] = 0; | ||
1306 | |||
1307 | levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC); | ||
1308 | if (!levdatum->level) { | ||
1309 | rc = -ENOMEM; | ||
1310 | goto bad; | ||
1311 | } | ||
1312 | if (mls_read_level(levdatum->level, fp)) { | ||
1313 | rc = -EINVAL; | ||
1314 | goto bad; | ||
1315 | } | ||
1316 | |||
1317 | rc = hashtab_insert(h, key, levdatum); | ||
1318 | if (rc) | ||
1319 | goto bad; | ||
1320 | out: | ||
1321 | return rc; | ||
1322 | bad: | ||
1323 | sens_destroy(key, levdatum, NULL); | ||
1324 | goto out; | ||
1325 | } | ||
1326 | |||
1327 | static int cat_read(struct policydb *p, struct hashtab *h, void *fp) | ||
1328 | { | ||
1329 | char *key = NULL; | ||
1330 | struct cat_datum *catdatum; | ||
1331 | int rc; | ||
1332 | u32 buf[3], len; | ||
1333 | |||
1334 | catdatum = kmalloc(sizeof(*catdatum), GFP_ATOMIC); | ||
1335 | if (!catdatum) { | ||
1336 | rc = -ENOMEM; | ||
1337 | goto out; | ||
1338 | } | ||
1339 | memset(catdatum, 0, sizeof(*catdatum)); | ||
1340 | |||
1341 | rc = next_entry(buf, fp, sizeof buf); | ||
1342 | if (rc < 0) | ||
1343 | goto bad; | ||
1344 | |||
1345 | len = le32_to_cpu(buf[0]); | ||
1346 | catdatum->value = le32_to_cpu(buf[1]); | ||
1347 | catdatum->isalias = le32_to_cpu(buf[2]); | ||
1348 | |||
1349 | key = kmalloc(len + 1,GFP_ATOMIC); | ||
1350 | if (!key) { | ||
1351 | rc = -ENOMEM; | ||
1352 | goto bad; | ||
1353 | } | ||
1354 | rc = next_entry(key, fp, len); | ||
1355 | if (rc < 0) | ||
1356 | goto bad; | ||
1357 | key[len] = 0; | ||
1358 | |||
1359 | rc = hashtab_insert(h, key, catdatum); | ||
1360 | if (rc) | ||
1361 | goto bad; | ||
1362 | out: | ||
1363 | return rc; | ||
1364 | |||
1365 | bad: | ||
1366 | cat_destroy(key, catdatum, NULL); | ||
1367 | goto out; | ||
1368 | } | ||
1369 | |||
1370 | static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) = | ||
1371 | { | ||
1372 | common_read, | ||
1373 | class_read, | ||
1374 | role_read, | ||
1375 | type_read, | ||
1376 | user_read, | ||
1377 | cond_read_bool, | ||
1378 | sens_read, | ||
1379 | cat_read, | ||
1380 | }; | ||
1381 | |||
1382 | extern int ss_initialized; | ||
1383 | |||
1384 | /* | ||
1385 | * Read the configuration data from a policy database binary | ||
1386 | * representation file into a policy database structure. | ||
1387 | */ | ||
1388 | int policydb_read(struct policydb *p, void *fp) | ||
1389 | { | ||
1390 | struct role_allow *ra, *lra; | ||
1391 | struct role_trans *tr, *ltr; | ||
1392 | struct ocontext *l, *c, *newc; | ||
1393 | struct genfs *genfs_p, *genfs, *newgenfs; | ||
1394 | int i, j, rc; | ||
1395 | u32 buf[8], len, len2, config, nprim, nel, nel2; | ||
1396 | char *policydb_str; | ||
1397 | struct policydb_compat_info *info; | ||
1398 | struct range_trans *rt, *lrt; | ||
1399 | |||
1400 | config = 0; | ||
1401 | |||
1402 | rc = policydb_init(p); | ||
1403 | if (rc) | ||
1404 | goto out; | ||
1405 | |||
1406 | /* Read the magic number and string length. */ | ||
1407 | rc = next_entry(buf, fp, sizeof(u32)* 2); | ||
1408 | if (rc < 0) | ||
1409 | goto bad; | ||
1410 | |||
1411 | for (i = 0; i < 2; i++) | ||
1412 | buf[i] = le32_to_cpu(buf[i]); | ||
1413 | |||
1414 | if (buf[0] != POLICYDB_MAGIC) { | ||
1415 | printk(KERN_ERR "security: policydb magic number 0x%x does " | ||
1416 | "not match expected magic number 0x%x\n", | ||
1417 | buf[0], POLICYDB_MAGIC); | ||
1418 | goto bad; | ||
1419 | } | ||
1420 | |||
1421 | len = buf[1]; | ||
1422 | if (len != strlen(POLICYDB_STRING)) { | ||
1423 | printk(KERN_ERR "security: policydb string length %d does not " | ||
1424 | "match expected length %Zu\n", | ||
1425 | len, strlen(POLICYDB_STRING)); | ||
1426 | goto bad; | ||
1427 | } | ||
1428 | policydb_str = kmalloc(len + 1,GFP_KERNEL); | ||
1429 | if (!policydb_str) { | ||
1430 | printk(KERN_ERR "security: unable to allocate memory for policydb " | ||
1431 | "string of length %d\n", len); | ||
1432 | rc = -ENOMEM; | ||
1433 | goto bad; | ||
1434 | } | ||
1435 | rc = next_entry(policydb_str, fp, len); | ||
1436 | if (rc < 0) { | ||
1437 | printk(KERN_ERR "security: truncated policydb string identifier\n"); | ||
1438 | kfree(policydb_str); | ||
1439 | goto bad; | ||
1440 | } | ||
1441 | policydb_str[len] = 0; | ||
1442 | if (strcmp(policydb_str, POLICYDB_STRING)) { | ||
1443 | printk(KERN_ERR "security: policydb string %s does not match " | ||
1444 | "my string %s\n", policydb_str, POLICYDB_STRING); | ||
1445 | kfree(policydb_str); | ||
1446 | goto bad; | ||
1447 | } | ||
1448 | /* Done with policydb_str. */ | ||
1449 | kfree(policydb_str); | ||
1450 | policydb_str = NULL; | ||
1451 | |||
1452 | /* Read the version, config, and table sizes. */ | ||
1453 | rc = next_entry(buf, fp, sizeof(u32)*4); | ||
1454 | if (rc < 0) | ||
1455 | goto bad; | ||
1456 | for (i = 0; i < 4; i++) | ||
1457 | buf[i] = le32_to_cpu(buf[i]); | ||
1458 | |||
1459 | p->policyvers = buf[0]; | ||
1460 | if (p->policyvers < POLICYDB_VERSION_MIN || | ||
1461 | p->policyvers > POLICYDB_VERSION_MAX) { | ||
1462 | printk(KERN_ERR "security: policydb version %d does not match " | ||
1463 | "my version range %d-%d\n", | ||
1464 | buf[0], POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX); | ||
1465 | goto bad; | ||
1466 | } | ||
1467 | |||
1468 | if ((buf[1] & POLICYDB_CONFIG_MLS)) { | ||
1469 | if (ss_initialized && !selinux_mls_enabled) { | ||
1470 | printk(KERN_ERR "Cannot switch between non-MLS and MLS " | ||
1471 | "policies\n"); | ||
1472 | goto bad; | ||
1473 | } | ||
1474 | selinux_mls_enabled = 1; | ||
1475 | config |= POLICYDB_CONFIG_MLS; | ||
1476 | |||
1477 | if (p->policyvers < POLICYDB_VERSION_MLS) { | ||
1478 | printk(KERN_ERR "security policydb version %d (MLS) " | ||
1479 | "not backwards compatible\n", p->policyvers); | ||
1480 | goto bad; | ||
1481 | } | ||
1482 | } else { | ||
1483 | if (ss_initialized && selinux_mls_enabled) { | ||
1484 | printk(KERN_ERR "Cannot switch between MLS and non-MLS " | ||
1485 | "policies\n"); | ||
1486 | goto bad; | ||
1487 | } | ||
1488 | } | ||
1489 | |||
1490 | info = policydb_lookup_compat(p->policyvers); | ||
1491 | if (!info) { | ||
1492 | printk(KERN_ERR "security: unable to find policy compat info " | ||
1493 | "for version %d\n", p->policyvers); | ||
1494 | goto bad; | ||
1495 | } | ||
1496 | |||
1497 | if (buf[2] != info->sym_num || buf[3] != info->ocon_num) { | ||
1498 | printk(KERN_ERR "security: policydb table sizes (%d,%d) do " | ||
1499 | "not match mine (%d,%d)\n", buf[2], buf[3], | ||
1500 | info->sym_num, info->ocon_num); | ||
1501 | goto bad; | ||
1502 | } | ||
1503 | |||
1504 | for (i = 0; i < info->sym_num; i++) { | ||
1505 | rc = next_entry(buf, fp, sizeof(u32)*2); | ||
1506 | if (rc < 0) | ||
1507 | goto bad; | ||
1508 | nprim = le32_to_cpu(buf[0]); | ||
1509 | nel = le32_to_cpu(buf[1]); | ||
1510 | for (j = 0; j < nel; j++) { | ||
1511 | rc = read_f[i](p, p->symtab[i].table, fp); | ||
1512 | if (rc) | ||
1513 | goto bad; | ||
1514 | } | ||
1515 | |||
1516 | p->symtab[i].nprim = nprim; | ||
1517 | } | ||
1518 | |||
1519 | rc = avtab_read(&p->te_avtab, fp, config); | ||
1520 | if (rc) | ||
1521 | goto bad; | ||
1522 | |||
1523 | if (p->policyvers >= POLICYDB_VERSION_BOOL) { | ||
1524 | rc = cond_read_list(p, fp); | ||
1525 | if (rc) | ||
1526 | goto bad; | ||
1527 | } | ||
1528 | |||
1529 | rc = next_entry(buf, fp, sizeof(u32)); | ||
1530 | if (rc < 0) | ||
1531 | goto bad; | ||
1532 | nel = le32_to_cpu(buf[0]); | ||
1533 | ltr = NULL; | ||
1534 | for (i = 0; i < nel; i++) { | ||
1535 | tr = kmalloc(sizeof(*tr), GFP_KERNEL); | ||
1536 | if (!tr) { | ||
1537 | rc = -ENOMEM; | ||
1538 | goto bad; | ||
1539 | } | ||
1540 | memset(tr, 0, sizeof(*tr)); | ||
1541 | if (ltr) { | ||
1542 | ltr->next = tr; | ||
1543 | } else { | ||
1544 | p->role_tr = tr; | ||
1545 | } | ||
1546 | rc = next_entry(buf, fp, sizeof(u32)*3); | ||
1547 | if (rc < 0) | ||
1548 | goto bad; | ||
1549 | tr->role = le32_to_cpu(buf[0]); | ||
1550 | tr->type = le32_to_cpu(buf[1]); | ||
1551 | tr->new_role = le32_to_cpu(buf[2]); | ||
1552 | ltr = tr; | ||
1553 | } | ||
1554 | |||
1555 | rc = next_entry(buf, fp, sizeof(u32)); | ||
1556 | if (rc < 0) | ||
1557 | goto bad; | ||
1558 | nel = le32_to_cpu(buf[0]); | ||
1559 | lra = NULL; | ||
1560 | for (i = 0; i < nel; i++) { | ||
1561 | ra = kmalloc(sizeof(*ra), GFP_KERNEL); | ||
1562 | if (!ra) { | ||
1563 | rc = -ENOMEM; | ||
1564 | goto bad; | ||
1565 | } | ||
1566 | memset(ra, 0, sizeof(*ra)); | ||
1567 | if (lra) { | ||
1568 | lra->next = ra; | ||
1569 | } else { | ||
1570 | p->role_allow = ra; | ||
1571 | } | ||
1572 | rc = next_entry(buf, fp, sizeof(u32)*2); | ||
1573 | if (rc < 0) | ||
1574 | goto bad; | ||
1575 | ra->role = le32_to_cpu(buf[0]); | ||
1576 | ra->new_role = le32_to_cpu(buf[1]); | ||
1577 | lra = ra; | ||
1578 | } | ||
1579 | |||
1580 | rc = policydb_index_classes(p); | ||
1581 | if (rc) | ||
1582 | goto bad; | ||
1583 | |||
1584 | rc = policydb_index_others(p); | ||
1585 | if (rc) | ||
1586 | goto bad; | ||
1587 | |||
1588 | for (i = 0; i < info->ocon_num; i++) { | ||
1589 | rc = next_entry(buf, fp, sizeof(u32)); | ||
1590 | if (rc < 0) | ||
1591 | goto bad; | ||
1592 | nel = le32_to_cpu(buf[0]); | ||
1593 | l = NULL; | ||
1594 | for (j = 0; j < nel; j++) { | ||
1595 | c = kmalloc(sizeof(*c), GFP_KERNEL); | ||
1596 | if (!c) { | ||
1597 | rc = -ENOMEM; | ||
1598 | goto bad; | ||
1599 | } | ||
1600 | memset(c, 0, sizeof(*c)); | ||
1601 | if (l) { | ||
1602 | l->next = c; | ||
1603 | } else { | ||
1604 | p->ocontexts[i] = c; | ||
1605 | } | ||
1606 | l = c; | ||
1607 | rc = -EINVAL; | ||
1608 | switch (i) { | ||
1609 | case OCON_ISID: | ||
1610 | rc = next_entry(buf, fp, sizeof(u32)); | ||
1611 | if (rc < 0) | ||
1612 | goto bad; | ||
1613 | c->sid[0] = le32_to_cpu(buf[0]); | ||
1614 | rc = context_read_and_validate(&c->context[0], p, fp); | ||
1615 | if (rc) | ||
1616 | goto bad; | ||
1617 | break; | ||
1618 | case OCON_FS: | ||
1619 | case OCON_NETIF: | ||
1620 | rc = next_entry(buf, fp, sizeof(u32)); | ||
1621 | if (rc < 0) | ||
1622 | goto bad; | ||
1623 | len = le32_to_cpu(buf[0]); | ||
1624 | c->u.name = kmalloc(len + 1,GFP_KERNEL); | ||
1625 | if (!c->u.name) { | ||
1626 | rc = -ENOMEM; | ||
1627 | goto bad; | ||
1628 | } | ||
1629 | rc = next_entry(c->u.name, fp, len); | ||
1630 | if (rc < 0) | ||
1631 | goto bad; | ||
1632 | c->u.name[len] = 0; | ||
1633 | rc = context_read_and_validate(&c->context[0], p, fp); | ||
1634 | if (rc) | ||
1635 | goto bad; | ||
1636 | rc = context_read_and_validate(&c->context[1], p, fp); | ||
1637 | if (rc) | ||
1638 | goto bad; | ||
1639 | break; | ||
1640 | case OCON_PORT: | ||
1641 | rc = next_entry(buf, fp, sizeof(u32)*3); | ||
1642 | if (rc < 0) | ||
1643 | goto bad; | ||
1644 | c->u.port.protocol = le32_to_cpu(buf[0]); | ||
1645 | c->u.port.low_port = le32_to_cpu(buf[1]); | ||
1646 | c->u.port.high_port = le32_to_cpu(buf[2]); | ||
1647 | rc = context_read_and_validate(&c->context[0], p, fp); | ||
1648 | if (rc) | ||
1649 | goto bad; | ||
1650 | break; | ||
1651 | case OCON_NODE: | ||
1652 | rc = next_entry(buf, fp, sizeof(u32)* 2); | ||
1653 | if (rc < 0) | ||
1654 | goto bad; | ||
1655 | c->u.node.addr = le32_to_cpu(buf[0]); | ||
1656 | c->u.node.mask = le32_to_cpu(buf[1]); | ||
1657 | rc = context_read_and_validate(&c->context[0], p, fp); | ||
1658 | if (rc) | ||
1659 | goto bad; | ||
1660 | break; | ||
1661 | case OCON_FSUSE: | ||
1662 | rc = next_entry(buf, fp, sizeof(u32)*2); | ||
1663 | if (rc < 0) | ||
1664 | goto bad; | ||
1665 | c->v.behavior = le32_to_cpu(buf[0]); | ||
1666 | if (c->v.behavior > SECURITY_FS_USE_NONE) | ||
1667 | goto bad; | ||
1668 | len = le32_to_cpu(buf[1]); | ||
1669 | c->u.name = kmalloc(len + 1,GFP_KERNEL); | ||
1670 | if (!c->u.name) { | ||
1671 | rc = -ENOMEM; | ||
1672 | goto bad; | ||
1673 | } | ||
1674 | rc = next_entry(c->u.name, fp, len); | ||
1675 | if (rc < 0) | ||
1676 | goto bad; | ||
1677 | c->u.name[len] = 0; | ||
1678 | rc = context_read_and_validate(&c->context[0], p, fp); | ||
1679 | if (rc) | ||
1680 | goto bad; | ||
1681 | break; | ||
1682 | case OCON_NODE6: { | ||
1683 | int k; | ||
1684 | |||
1685 | rc = next_entry(buf, fp, sizeof(u32) * 8); | ||
1686 | if (rc < 0) | ||
1687 | goto bad; | ||
1688 | for (k = 0; k < 4; k++) | ||
1689 | c->u.node6.addr[k] = le32_to_cpu(buf[k]); | ||
1690 | for (k = 0; k < 4; k++) | ||
1691 | c->u.node6.mask[k] = le32_to_cpu(buf[k+4]); | ||
1692 | if (context_read_and_validate(&c->context[0], p, fp)) | ||
1693 | goto bad; | ||
1694 | break; | ||
1695 | } | ||
1696 | } | ||
1697 | } | ||
1698 | } | ||
1699 | |||
1700 | rc = next_entry(buf, fp, sizeof(u32)); | ||
1701 | if (rc < 0) | ||
1702 | goto bad; | ||
1703 | nel = le32_to_cpu(buf[0]); | ||
1704 | genfs_p = NULL; | ||
1705 | rc = -EINVAL; | ||
1706 | for (i = 0; i < nel; i++) { | ||
1707 | rc = next_entry(buf, fp, sizeof(u32)); | ||
1708 | if (rc < 0) | ||
1709 | goto bad; | ||
1710 | len = le32_to_cpu(buf[0]); | ||
1711 | newgenfs = kmalloc(sizeof(*newgenfs), GFP_KERNEL); | ||
1712 | if (!newgenfs) { | ||
1713 | rc = -ENOMEM; | ||
1714 | goto bad; | ||
1715 | } | ||
1716 | memset(newgenfs, 0, sizeof(*newgenfs)); | ||
1717 | |||
1718 | newgenfs->fstype = kmalloc(len + 1,GFP_KERNEL); | ||
1719 | if (!newgenfs->fstype) { | ||
1720 | rc = -ENOMEM; | ||
1721 | kfree(newgenfs); | ||
1722 | goto bad; | ||
1723 | } | ||
1724 | rc = next_entry(newgenfs->fstype, fp, len); | ||
1725 | if (rc < 0) { | ||
1726 | kfree(newgenfs->fstype); | ||
1727 | kfree(newgenfs); | ||
1728 | goto bad; | ||
1729 | } | ||
1730 | newgenfs->fstype[len] = 0; | ||
1731 | for (genfs_p = NULL, genfs = p->genfs; genfs; | ||
1732 | genfs_p = genfs, genfs = genfs->next) { | ||
1733 | if (strcmp(newgenfs->fstype, genfs->fstype) == 0) { | ||
1734 | printk(KERN_ERR "security: dup genfs " | ||
1735 | "fstype %s\n", newgenfs->fstype); | ||
1736 | kfree(newgenfs->fstype); | ||
1737 | kfree(newgenfs); | ||
1738 | goto bad; | ||
1739 | } | ||
1740 | if (strcmp(newgenfs->fstype, genfs->fstype) < 0) | ||
1741 | break; | ||
1742 | } | ||
1743 | newgenfs->next = genfs; | ||
1744 | if (genfs_p) | ||
1745 | genfs_p->next = newgenfs; | ||
1746 | else | ||
1747 | p->genfs = newgenfs; | ||
1748 | rc = next_entry(buf, fp, sizeof(u32)); | ||
1749 | if (rc < 0) | ||
1750 | goto bad; | ||
1751 | nel2 = le32_to_cpu(buf[0]); | ||
1752 | for (j = 0; j < nel2; j++) { | ||
1753 | rc = next_entry(buf, fp, sizeof(u32)); | ||
1754 | if (rc < 0) | ||
1755 | goto bad; | ||
1756 | len = le32_to_cpu(buf[0]); | ||
1757 | |||
1758 | newc = kmalloc(sizeof(*newc), GFP_KERNEL); | ||
1759 | if (!newc) { | ||
1760 | rc = -ENOMEM; | ||
1761 | goto bad; | ||
1762 | } | ||
1763 | memset(newc, 0, sizeof(*newc)); | ||
1764 | |||
1765 | newc->u.name = kmalloc(len + 1,GFP_KERNEL); | ||
1766 | if (!newc->u.name) { | ||
1767 | rc = -ENOMEM; | ||
1768 | goto bad_newc; | ||
1769 | } | ||
1770 | rc = next_entry(newc->u.name, fp, len); | ||
1771 | if (rc < 0) | ||
1772 | goto bad_newc; | ||
1773 | newc->u.name[len] = 0; | ||
1774 | rc = next_entry(buf, fp, sizeof(u32)); | ||
1775 | if (rc < 0) | ||
1776 | goto bad_newc; | ||
1777 | newc->v.sclass = le32_to_cpu(buf[0]); | ||
1778 | if (context_read_and_validate(&newc->context[0], p, fp)) | ||
1779 | goto bad_newc; | ||
1780 | for (l = NULL, c = newgenfs->head; c; | ||
1781 | l = c, c = c->next) { | ||
1782 | if (!strcmp(newc->u.name, c->u.name) && | ||
1783 | (!c->v.sclass || !newc->v.sclass || | ||
1784 | newc->v.sclass == c->v.sclass)) { | ||
1785 | printk(KERN_ERR "security: dup genfs " | ||
1786 | "entry (%s,%s)\n", | ||
1787 | newgenfs->fstype, c->u.name); | ||
1788 | goto bad_newc; | ||
1789 | } | ||
1790 | len = strlen(newc->u.name); | ||
1791 | len2 = strlen(c->u.name); | ||
1792 | if (len > len2) | ||
1793 | break; | ||
1794 | } | ||
1795 | |||
1796 | newc->next = c; | ||
1797 | if (l) | ||
1798 | l->next = newc; | ||
1799 | else | ||
1800 | newgenfs->head = newc; | ||
1801 | } | ||
1802 | } | ||
1803 | |||
1804 | if (p->policyvers >= POLICYDB_VERSION_MLS) { | ||
1805 | rc = next_entry(buf, fp, sizeof(u32)); | ||
1806 | if (rc < 0) | ||
1807 | goto bad; | ||
1808 | nel = le32_to_cpu(buf[0]); | ||
1809 | lrt = NULL; | ||
1810 | for (i = 0; i < nel; i++) { | ||
1811 | rt = kmalloc(sizeof(*rt), GFP_KERNEL); | ||
1812 | if (!rt) { | ||
1813 | rc = -ENOMEM; | ||
1814 | goto bad; | ||
1815 | } | ||
1816 | memset(rt, 0, sizeof(*rt)); | ||
1817 | if (lrt) | ||
1818 | lrt->next = rt; | ||
1819 | else | ||
1820 | p->range_tr = rt; | ||
1821 | rc = next_entry(buf, fp, (sizeof(u32) * 2)); | ||
1822 | if (rc < 0) | ||
1823 | goto bad; | ||
1824 | rt->dom = le32_to_cpu(buf[0]); | ||
1825 | rt->type = le32_to_cpu(buf[1]); | ||
1826 | rc = mls_read_range_helper(&rt->range, fp); | ||
1827 | if (rc) | ||
1828 | goto bad; | ||
1829 | lrt = rt; | ||
1830 | } | ||
1831 | } | ||
1832 | |||
1833 | rc = 0; | ||
1834 | out: | ||
1835 | return rc; | ||
1836 | bad_newc: | ||
1837 | ocontext_destroy(newc,OCON_FSUSE); | ||
1838 | bad: | ||
1839 | if (!rc) | ||
1840 | rc = -EINVAL; | ||
1841 | policydb_destroy(p); | ||
1842 | goto out; | ||
1843 | } | ||