• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Implementation of the access vector table type.
3  *
4  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5  */
6 
7 /* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
8  *
9  *	Added conditional policy language extensions
10  *
11  * Copyright (C) 2003 Tresys Technology, LLC
12  *	This program is free software; you can redistribute it and/or modify
13  *	it under the terms of the GNU General Public License as published by
14  *	the Free Software Foundation, version 2.
15  *
16  * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
17  *	Tuned number of hash slots for avtab to reduce memory usage
18  */
19 
20 #include <linux/kernel.h>
21 #include <linux/slab.h>
22 #include <linux/errno.h>
23 #include "avtab.h"
24 #include "policydb.h"
25 
26 static struct kmem_cache *avtab_node_cachep;
27 static struct kmem_cache *avtab_xperms_cachep;
28 
avtab_hash(struct avtab_key * keyp,u16 mask)29 static inline int avtab_hash(struct avtab_key *keyp, u16 mask)
30 {
31 	return ((keyp->target_class + (keyp->target_type << 2) +
32 		 (keyp->source_type << 9)) & mask);
33 }
34 
35 static struct avtab_node*
avtab_insert_node(struct avtab * h,int hvalue,struct avtab_node * prev,struct avtab_node * cur,struct avtab_key * key,struct avtab_datum * datum)36 avtab_insert_node(struct avtab *h, int hvalue,
37 		  struct avtab_node *prev, struct avtab_node *cur,
38 		  struct avtab_key *key, struct avtab_datum *datum)
39 {
40 	struct avtab_node *newnode;
41 	struct avtab_extended_perms *xperms;
42 	newnode = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL);
43 	if (newnode == NULL)
44 		return NULL;
45 	newnode->key = *key;
46 
47 	if (key->specified & AVTAB_XPERMS) {
48 		xperms = kmem_cache_zalloc(avtab_xperms_cachep, GFP_KERNEL);
49 		if (xperms == NULL) {
50 			kmem_cache_free(avtab_node_cachep, newnode);
51 			return NULL;
52 		}
53 		*xperms = *(datum->u.xperms);
54 		newnode->datum.u.xperms = xperms;
55 	} else {
56 		newnode->datum.u.data = datum->u.data;
57 	}
58 
59 	if (prev) {
60 		newnode->next = prev->next;
61 		prev->next = newnode;
62 	} else {
63 		newnode->next = h->htable[hvalue];
64 		h->htable[hvalue] = newnode;
65 	}
66 
67 	h->nel++;
68 	return newnode;
69 }
70 
avtab_insert(struct avtab * h,struct avtab_key * key,struct avtab_datum * datum)71 static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
72 {
73 	int hvalue;
74 	struct avtab_node *prev, *cur, *newnode;
75 	u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
76 
77 	if (!h || !h->htable)
78 		return -EINVAL;
79 
80 	hvalue = avtab_hash(key, h->mask);
81 	for (prev = NULL, cur = h->htable[hvalue];
82 	     cur;
83 	     prev = cur, cur = cur->next) {
84 		if (key->source_type == cur->key.source_type &&
85 		    key->target_type == cur->key.target_type &&
86 		    key->target_class == cur->key.target_class &&
87 		    (specified & cur->key.specified)) {
88 			/* extended perms may not be unique */
89 			if (specified & AVTAB_XPERMS)
90 				break;
91 			return -EEXIST;
92 		}
93 		if (key->source_type < cur->key.source_type)
94 			break;
95 		if (key->source_type == cur->key.source_type &&
96 		    key->target_type < cur->key.target_type)
97 			break;
98 		if (key->source_type == cur->key.source_type &&
99 		    key->target_type == cur->key.target_type &&
100 		    key->target_class < cur->key.target_class)
101 			break;
102 	}
103 
104 	newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
105 	if (!newnode)
106 		return -ENOMEM;
107 
108 	return 0;
109 }
110 
111 /* Unlike avtab_insert(), this function allow multiple insertions of the same
112  * key/specified mask into the table, as needed by the conditional avtab.
113  * It also returns a pointer to the node inserted.
114  */
115 struct avtab_node *
avtab_insert_nonunique(struct avtab * h,struct avtab_key * key,struct avtab_datum * datum)116 avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
117 {
118 	int hvalue;
119 	struct avtab_node *prev, *cur;
120 	u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
121 
122 	if (!h || !h->htable)
123 		return NULL;
124 	hvalue = avtab_hash(key, h->mask);
125 	for (prev = NULL, cur = h->htable[hvalue];
126 	     cur;
127 	     prev = cur, cur = cur->next) {
128 		if (key->source_type == cur->key.source_type &&
129 		    key->target_type == cur->key.target_type &&
130 		    key->target_class == cur->key.target_class &&
131 		    (specified & cur->key.specified))
132 			break;
133 		if (key->source_type < cur->key.source_type)
134 			break;
135 		if (key->source_type == cur->key.source_type &&
136 		    key->target_type < cur->key.target_type)
137 			break;
138 		if (key->source_type == cur->key.source_type &&
139 		    key->target_type == cur->key.target_type &&
140 		    key->target_class < cur->key.target_class)
141 			break;
142 	}
143 	return avtab_insert_node(h, hvalue, prev, cur, key, datum);
144 }
145 
avtab_search(struct avtab * h,struct avtab_key * key)146 struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key)
147 {
148 	int hvalue;
149 	struct avtab_node *cur;
150 	u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
151 
152 	if (!h || !h->htable)
153 		return NULL;
154 
155 	hvalue = avtab_hash(key, h->mask);
156 	for (cur = h->htable[hvalue]; cur; cur = cur->next) {
157 		if (key->source_type == cur->key.source_type &&
158 		    key->target_type == cur->key.target_type &&
159 		    key->target_class == cur->key.target_class &&
160 		    (specified & cur->key.specified))
161 			return &cur->datum;
162 
163 		if (key->source_type < cur->key.source_type)
164 			break;
165 		if (key->source_type == cur->key.source_type &&
166 		    key->target_type < cur->key.target_type)
167 			break;
168 		if (key->source_type == cur->key.source_type &&
169 		    key->target_type == cur->key.target_type &&
170 		    key->target_class < cur->key.target_class)
171 			break;
172 	}
173 
174 	return NULL;
175 }
176 
177 /* This search function returns a node pointer, and can be used in
178  * conjunction with avtab_search_next_node()
179  */
180 struct avtab_node*
avtab_search_node(struct avtab * h,struct avtab_key * key)181 avtab_search_node(struct avtab *h, struct avtab_key *key)
182 {
183 	int hvalue;
184 	struct avtab_node *cur;
185 	u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
186 
187 	if (!h || !h->htable)
188 		return NULL;
189 
190 	hvalue = avtab_hash(key, h->mask);
191 	for (cur = h->htable[hvalue]; cur; cur = cur->next) {
192 		if (key->source_type == cur->key.source_type &&
193 		    key->target_type == cur->key.target_type &&
194 		    key->target_class == cur->key.target_class &&
195 		    (specified & cur->key.specified))
196 			return cur;
197 
198 		if (key->source_type < cur->key.source_type)
199 			break;
200 		if (key->source_type == cur->key.source_type &&
201 		    key->target_type < cur->key.target_type)
202 			break;
203 		if (key->source_type == cur->key.source_type &&
204 		    key->target_type == cur->key.target_type &&
205 		    key->target_class < cur->key.target_class)
206 			break;
207 	}
208 	return NULL;
209 }
210 
211 struct avtab_node*
avtab_search_node_next(struct avtab_node * node,int specified)212 avtab_search_node_next(struct avtab_node *node, int specified)
213 {
214 	struct avtab_node *cur;
215 
216 	if (!node)
217 		return NULL;
218 
219 	specified &= ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
220 	for (cur = node->next; cur; cur = cur->next) {
221 		if (node->key.source_type == cur->key.source_type &&
222 		    node->key.target_type == cur->key.target_type &&
223 		    node->key.target_class == cur->key.target_class &&
224 		    (specified & cur->key.specified))
225 			return cur;
226 
227 		if (node->key.source_type < cur->key.source_type)
228 			break;
229 		if (node->key.source_type == cur->key.source_type &&
230 		    node->key.target_type < cur->key.target_type)
231 			break;
232 		if (node->key.source_type == cur->key.source_type &&
233 		    node->key.target_type == cur->key.target_type &&
234 		    node->key.target_class < cur->key.target_class)
235 			break;
236 	}
237 	return NULL;
238 }
239 
avtab_destroy(struct avtab * h)240 void avtab_destroy(struct avtab *h)
241 {
242 	int i;
243 	struct avtab_node *cur, *temp;
244 
245 	if (!h || !h->htable)
246 		return;
247 
248 	for (i = 0; i < h->nslot; i++) {
249 		cur = h->htable[i];
250 		while (cur) {
251 			temp = cur;
252 			cur = cur->next;
253 			if (temp->key.specified & AVTAB_XPERMS)
254 				kmem_cache_free(avtab_xperms_cachep,
255 						temp->datum.u.xperms);
256 			kmem_cache_free(avtab_node_cachep, temp);
257 		}
258 		h->htable[i] = NULL;
259 	}
260 	kfree(h->htable);
261 	h->htable = NULL;
262 	h->nslot = 0;
263 	h->mask = 0;
264 }
265 
avtab_init(struct avtab * h)266 int avtab_init(struct avtab *h)
267 {
268 	h->htable = NULL;
269 	h->nel = 0;
270 	return 0;
271 }
272 
avtab_alloc(struct avtab * h,u32 nrules)273 int avtab_alloc(struct avtab *h, u32 nrules)
274 {
275 	u16 mask = 0;
276 	u32 shift = 0;
277 	u32 work = nrules;
278 	u32 nslot = 0;
279 
280 	if (nrules == 0)
281 		goto avtab_alloc_out;
282 
283 	while (work) {
284 		work  = work >> 1;
285 		shift++;
286 	}
287 	if (shift > 2)
288 		shift = shift - 2;
289 	nslot = 1 << shift;
290 	if (nslot > MAX_AVTAB_HASH_BUCKETS)
291 		nslot = MAX_AVTAB_HASH_BUCKETS;
292 	mask = nslot - 1;
293 
294 	h->htable = kcalloc(nslot, sizeof(*(h->htable)), GFP_KERNEL);
295 	if (!h->htable)
296 		return -ENOMEM;
297 
298  avtab_alloc_out:
299 	h->nel = 0;
300 	h->nslot = nslot;
301 	h->mask = mask;
302 	printk(KERN_DEBUG "SELinux: %d avtab hash slots, %d rules.\n",
303 	       h->nslot, nrules);
304 	return 0;
305 }
306 
avtab_hash_eval(struct avtab * h,char * tag)307 void avtab_hash_eval(struct avtab *h, char *tag)
308 {
309 	int i, chain_len, slots_used, max_chain_len;
310 	unsigned long long chain2_len_sum;
311 	struct avtab_node *cur;
312 
313 	slots_used = 0;
314 	max_chain_len = 0;
315 	chain2_len_sum = 0;
316 	for (i = 0; i < h->nslot; i++) {
317 		cur = h->htable[i];
318 		if (cur) {
319 			slots_used++;
320 			chain_len = 0;
321 			while (cur) {
322 				chain_len++;
323 				cur = cur->next;
324 			}
325 
326 			if (chain_len > max_chain_len)
327 				max_chain_len = chain_len;
328 			chain2_len_sum += chain_len * chain_len;
329 		}
330 	}
331 
332 	printk(KERN_DEBUG "SELinux: %s:  %d entries and %d/%d buckets used, "
333 	       "longest chain length %d sum of chain length^2 %llu\n",
334 	       tag, h->nel, slots_used, h->nslot, max_chain_len,
335 	       chain2_len_sum);
336 }
337 
338 /*
339  * extended permissions compatibility. Make ToT Android kernels compatible
340  * with Android M releases
341  */
342 #define AVTAB_OPTYPE_ALLOWED	0x1000
343 #define AVTAB_OPTYPE_AUDITALLOW	0x2000
344 #define AVTAB_OPTYPE_DONTAUDIT	0x4000
345 #define AVTAB_OPTYPE		(AVTAB_OPTYPE_ALLOWED | \
346 				AVTAB_OPTYPE_AUDITALLOW | \
347 				AVTAB_OPTYPE_DONTAUDIT)
348 #define AVTAB_XPERMS_OPTYPE	4
349 
350 #define avtab_xperms_to_optype(x) (x << AVTAB_XPERMS_OPTYPE)
351 #define avtab_optype_to_xperms(x) (x >> AVTAB_XPERMS_OPTYPE)
352 
353 static unsigned int avtab_android_m_compat;
354 
avtab_android_m_compat_set(void)355 static void avtab_android_m_compat_set(void)
356 {
357 	if (!avtab_android_m_compat) {
358 		pr_info("SELinux:  Android master kernel running Android"
359 				" M policy in compatibility mode.\n");
360 		avtab_android_m_compat = 1;
361 	}
362 }
363 
364 static uint16_t spec_order[] = {
365 	AVTAB_ALLOWED,
366 	AVTAB_AUDITDENY,
367 	AVTAB_AUDITALLOW,
368 	AVTAB_TRANSITION,
369 	AVTAB_CHANGE,
370 	AVTAB_MEMBER,
371 	AVTAB_XPERMS_ALLOWED,
372 	AVTAB_XPERMS_AUDITALLOW,
373 	AVTAB_XPERMS_DONTAUDIT
374 };
375 
avtab_read_item(struct avtab * a,void * fp,struct policydb * pol,int (* insertf)(struct avtab * a,struct avtab_key * k,struct avtab_datum * d,void * p),void * p)376 int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
377 		    int (*insertf)(struct avtab *a, struct avtab_key *k,
378 				   struct avtab_datum *d, void *p),
379 		    void *p)
380 {
381 	__le16 buf16[4];
382 	u16 enabled;
383 	u32 items, items2, val, vers = pol->policyvers;
384 	struct avtab_key key;
385 	struct avtab_datum datum;
386 	struct avtab_extended_perms xperms;
387 	__le32 buf32[ARRAY_SIZE(xperms.perms.p)];
388 	unsigned int android_m_compat_optype = 0;
389 	int i, rc;
390 	unsigned set;
391 
392 	memset(&key, 0, sizeof(struct avtab_key));
393 	memset(&datum, 0, sizeof(struct avtab_datum));
394 
395 	if (vers < POLICYDB_VERSION_AVTAB) {
396 		rc = next_entry(buf32, fp, sizeof(u32));
397 		if (rc) {
398 			printk(KERN_ERR "SELinux: avtab: truncated entry\n");
399 			return rc;
400 		}
401 		items2 = le32_to_cpu(buf32[0]);
402 		if (items2 > ARRAY_SIZE(buf32)) {
403 			printk(KERN_ERR "SELinux: avtab: entry overflow\n");
404 			return -EINVAL;
405 
406 		}
407 		rc = next_entry(buf32, fp, sizeof(u32)*items2);
408 		if (rc) {
409 			printk(KERN_ERR "SELinux: avtab: truncated entry\n");
410 			return rc;
411 		}
412 		items = 0;
413 
414 		val = le32_to_cpu(buf32[items++]);
415 		key.source_type = (u16)val;
416 		if (key.source_type != val) {
417 			printk(KERN_ERR "SELinux: avtab: truncated source type\n");
418 			return -EINVAL;
419 		}
420 		val = le32_to_cpu(buf32[items++]);
421 		key.target_type = (u16)val;
422 		if (key.target_type != val) {
423 			printk(KERN_ERR "SELinux: avtab: truncated target type\n");
424 			return -EINVAL;
425 		}
426 		val = le32_to_cpu(buf32[items++]);
427 		key.target_class = (u16)val;
428 		if (key.target_class != val) {
429 			printk(KERN_ERR "SELinux: avtab: truncated target class\n");
430 			return -EINVAL;
431 		}
432 
433 		val = le32_to_cpu(buf32[items++]);
434 		enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0;
435 
436 		if (!(val & (AVTAB_AV | AVTAB_TYPE))) {
437 			printk(KERN_ERR "SELinux: avtab: null entry\n");
438 			return -EINVAL;
439 		}
440 		if ((val & AVTAB_AV) &&
441 		    (val & AVTAB_TYPE)) {
442 			printk(KERN_ERR "SELinux: avtab: entry has both access vectors and types\n");
443 			return -EINVAL;
444 		}
445 		if (val & AVTAB_XPERMS) {
446 			printk(KERN_ERR "SELinux: avtab: entry has extended permissions\n");
447 			return -EINVAL;
448 		}
449 
450 		for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
451 			if (val & spec_order[i]) {
452 				key.specified = spec_order[i] | enabled;
453 				datum.u.data = le32_to_cpu(buf32[items++]);
454 				rc = insertf(a, &key, &datum, p);
455 				if (rc)
456 					return rc;
457 			}
458 		}
459 
460 		if (items != items2) {
461 			printk(KERN_ERR "SELinux: avtab: entry only had %d items, expected %d\n", items2, items);
462 			return -EINVAL;
463 		}
464 		return 0;
465 	}
466 
467 	rc = next_entry(buf16, fp, sizeof(u16)*4);
468 	if (rc) {
469 		printk(KERN_ERR "SELinux: avtab: truncated entry\n");
470 		return rc;
471 	}
472 
473 	items = 0;
474 	key.source_type = le16_to_cpu(buf16[items++]);
475 	key.target_type = le16_to_cpu(buf16[items++]);
476 	key.target_class = le16_to_cpu(buf16[items++]);
477 	key.specified = le16_to_cpu(buf16[items++]);
478 
479 	if ((key.specified & AVTAB_OPTYPE) &&
480 			(vers == POLICYDB_VERSION_XPERMS_IOCTL)) {
481 		key.specified = avtab_optype_to_xperms(key.specified);
482 		android_m_compat_optype = 1;
483 		avtab_android_m_compat_set();
484 	}
485 
486 	if (!policydb_type_isvalid(pol, key.source_type) ||
487 	    !policydb_type_isvalid(pol, key.target_type) ||
488 	    !policydb_class_isvalid(pol, key.target_class)) {
489 		printk(KERN_ERR "SELinux: avtab: invalid type or class\n");
490 		return -EINVAL;
491 	}
492 
493 	set = 0;
494 	for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
495 		if (key.specified & spec_order[i])
496 			set++;
497 	}
498 	if (!set || set > 1) {
499 		printk(KERN_ERR "SELinux:  avtab:  more than one specifier\n");
500 		return -EINVAL;
501 	}
502 
503 	if ((vers < POLICYDB_VERSION_XPERMS_IOCTL) &&
504 			(key.specified & AVTAB_XPERMS)) {
505 		printk(KERN_ERR "SELinux:  avtab:  policy version %u does not "
506 				"support extended permissions rules and one "
507 				"was specified\n", vers);
508 		return -EINVAL;
509 	} else if (key.specified & AVTAB_XPERMS) {
510 		memset(&xperms, 0, sizeof(struct avtab_extended_perms));
511 		rc = next_entry(&xperms.specified, fp, sizeof(u8));
512 		if (rc) {
513 			printk(KERN_ERR "SELinux: avtab: truncated entry\n");
514 			return rc;
515 		}
516 		if (avtab_android_m_compat ||
517 			    ((xperms.specified != AVTAB_XPERMS_IOCTLFUNCTION) &&
518 			    (xperms.specified != AVTAB_XPERMS_IOCTLDRIVER) &&
519 			    (vers == POLICYDB_VERSION_XPERMS_IOCTL))) {
520 			xperms.driver = xperms.specified;
521 			if (android_m_compat_optype)
522 				xperms.specified = AVTAB_XPERMS_IOCTLDRIVER;
523 			else
524 				xperms.specified = AVTAB_XPERMS_IOCTLFUNCTION;
525 			avtab_android_m_compat_set();
526 		} else {
527 			rc = next_entry(&xperms.driver, fp, sizeof(u8));
528 			if (rc) {
529 				printk(KERN_ERR "SELinux: avtab: truncated entry\n");
530 				return rc;
531 			}
532 		}
533 		rc = next_entry(buf32, fp, sizeof(u32)*ARRAY_SIZE(xperms.perms.p));
534 		if (rc) {
535 			printk(KERN_ERR "SELinux: avtab: truncated entry\n");
536 			return rc;
537 		}
538 		for (i = 0; i < ARRAY_SIZE(xperms.perms.p); i++)
539 			xperms.perms.p[i] = le32_to_cpu(buf32[i]);
540 		datum.u.xperms = &xperms;
541 	} else {
542 		rc = next_entry(buf32, fp, sizeof(u32));
543 		if (rc) {
544 			printk(KERN_ERR "SELinux: avtab: truncated entry\n");
545 			return rc;
546 		}
547 		datum.u.data = le32_to_cpu(*buf32);
548 	}
549 	if ((key.specified & AVTAB_TYPE) &&
550 	    !policydb_type_isvalid(pol, datum.u.data)) {
551 		printk(KERN_ERR "SELinux: avtab: invalid type\n");
552 		return -EINVAL;
553 	}
554 	return insertf(a, &key, &datum, p);
555 }
556 
avtab_insertf(struct avtab * a,struct avtab_key * k,struct avtab_datum * d,void * p)557 static int avtab_insertf(struct avtab *a, struct avtab_key *k,
558 			 struct avtab_datum *d, void *p)
559 {
560 	return avtab_insert(a, k, d);
561 }
562 
avtab_read(struct avtab * a,void * fp,struct policydb * pol)563 int avtab_read(struct avtab *a, void *fp, struct policydb *pol)
564 {
565 	int rc;
566 	__le32 buf[1];
567 	u32 nel, i;
568 
569 
570 	rc = next_entry(buf, fp, sizeof(u32));
571 	if (rc < 0) {
572 		printk(KERN_ERR "SELinux: avtab: truncated table\n");
573 		goto bad;
574 	}
575 	nel = le32_to_cpu(buf[0]);
576 	if (!nel) {
577 		printk(KERN_ERR "SELinux: avtab: table is empty\n");
578 		rc = -EINVAL;
579 		goto bad;
580 	}
581 
582 	rc = avtab_alloc(a, nel);
583 	if (rc)
584 		goto bad;
585 
586 	for (i = 0; i < nel; i++) {
587 		rc = avtab_read_item(a, fp, pol, avtab_insertf, NULL);
588 		if (rc) {
589 			if (rc == -ENOMEM)
590 				printk(KERN_ERR "SELinux: avtab: out of memory\n");
591 			else if (rc == -EEXIST)
592 				printk(KERN_ERR "SELinux: avtab: duplicate entry\n");
593 
594 			goto bad;
595 		}
596 	}
597 
598 	rc = 0;
599 out:
600 	return rc;
601 
602 bad:
603 	avtab_destroy(a);
604 	goto out;
605 }
606 
avtab_write_item(struct policydb * p,struct avtab_node * cur,void * fp)607 int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp)
608 {
609 	__le16 buf16[4];
610 	__le32 buf32[ARRAY_SIZE(cur->datum.u.xperms->perms.p)];
611 	int rc;
612 	unsigned int i;
613 
614 	buf16[0] = cpu_to_le16(cur->key.source_type);
615 	buf16[1] = cpu_to_le16(cur->key.target_type);
616 	buf16[2] = cpu_to_le16(cur->key.target_class);
617 	if (avtab_android_m_compat && (cur->key.specified & AVTAB_XPERMS) &&
618 		    (cur->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER))
619 		buf16[3] = cpu_to_le16(avtab_xperms_to_optype(cur->key.specified));
620 	else
621 		buf16[3] = cpu_to_le16(cur->key.specified);
622 	rc = put_entry(buf16, sizeof(u16), 4, fp);
623 	if (rc)
624 		return rc;
625 
626 	if (cur->key.specified & AVTAB_XPERMS) {
627 		if (avtab_android_m_compat == 0) {
628 			rc = put_entry(&cur->datum.u.xperms->specified,
629 					sizeof(u8), 1, fp);
630 			if (rc)
631 				return rc;
632 		}
633 		rc = put_entry(&cur->datum.u.xperms->driver, sizeof(u8), 1, fp);
634 		if (rc)
635 			return rc;
636 		for (i = 0; i < ARRAY_SIZE(cur->datum.u.xperms->perms.p); i++)
637 			buf32[i] = cpu_to_le32(cur->datum.u.xperms->perms.p[i]);
638 		rc = put_entry(buf32, sizeof(u32),
639 				ARRAY_SIZE(cur->datum.u.xperms->perms.p), fp);
640 	} else {
641 		buf32[0] = cpu_to_le32(cur->datum.u.data);
642 		rc = put_entry(buf32, sizeof(u32), 1, fp);
643 	}
644 	if (rc)
645 		return rc;
646 	return 0;
647 }
648 
avtab_write(struct policydb * p,struct avtab * a,void * fp)649 int avtab_write(struct policydb *p, struct avtab *a, void *fp)
650 {
651 	unsigned int i;
652 	int rc = 0;
653 	struct avtab_node *cur;
654 	__le32 buf[1];
655 
656 	buf[0] = cpu_to_le32(a->nel);
657 	rc = put_entry(buf, sizeof(u32), 1, fp);
658 	if (rc)
659 		return rc;
660 
661 	for (i = 0; i < a->nslot; i++) {
662 		for (cur = a->htable[i]; cur; cur = cur->next) {
663 			rc = avtab_write_item(p, cur, fp);
664 			if (rc)
665 				return rc;
666 		}
667 	}
668 
669 	return rc;
670 }
avtab_cache_init(void)671 void avtab_cache_init(void)
672 {
673 	avtab_node_cachep = kmem_cache_create("avtab_node",
674 					      sizeof(struct avtab_node),
675 					      0, SLAB_PANIC, NULL);
676 	avtab_xperms_cachep = kmem_cache_create("avtab_extended_perms",
677 						sizeof(struct avtab_extended_perms),
678 						0, SLAB_PANIC, NULL);
679 }
680 
avtab_cache_destroy(void)681 void avtab_cache_destroy(void)
682 {
683 	kmem_cache_destroy(avtab_node_cachep);
684 	kmem_cache_destroy(avtab_xperms_cachep);
685 }
686