avtab.c 16.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8
/*
 * Implementation of the access vector table type.
 *
 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
 */

/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
 *
9
 *	Added conditional policy language extensions
L
Linus Torvalds 已提交
10 11 12
 *
 * Copyright (C) 2003 Tresys Technology, LLC
 *	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
L
Linus Torvalds 已提交
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
L
Linus Torvalds 已提交
18 19 20 21 22 23 24 25
 */

#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include "avtab.h"
#include "policydb.h"

26
static struct kmem_cache *avtab_node_cachep;
27
static struct kmem_cache *avtab_xperms_cachep;
L
Linus Torvalds 已提交
28

29 30 31 32
/* Based on MurmurHash3, written by Austin Appleby and placed in the
 * public domain.
 */
static inline int avtab_hash(struct avtab_key *keyp, u32 mask)
33
{
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
	static const u32 c1 = 0xcc9e2d51;
	static const u32 c2 = 0x1b873593;
	static const u32 r1 = 15;
	static const u32 r2 = 13;
	static const u32 m  = 5;
	static const u32 n  = 0xe6546b64;

	u32 hash = 0;

#define mix(input) { \
	u32 v = input; \
	v *= c1; \
	v = (v << r1) | (v >> (32 - r1)); \
	v *= c2; \
	hash ^= v; \
	hash = (hash << r2) | (hash >> (32 - r2)); \
	hash = hash * m + n; \
}

	mix(keyp->target_class);
	mix(keyp->target_type);
	mix(keyp->source_type);

#undef mix

	hash ^= hash >> 16;
	hash *= 0x85ebca6b;
	hash ^= hash >> 13;
	hash *= 0xc2b2ae35;
	hash ^= hash >> 16;

	return hash & mask;
66 67
}

L
Linus Torvalds 已提交
68 69
static struct avtab_node*
avtab_insert_node(struct avtab *h, int hvalue,
70
		  struct avtab_node *prev, struct avtab_node *cur,
L
Linus Torvalds 已提交
71 72
		  struct avtab_key *key, struct avtab_datum *datum)
{
73
	struct avtab_node *newnode;
74
	struct avtab_extended_perms *xperms;
75
	newnode = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL);
L
Linus Torvalds 已提交
76 77 78
	if (newnode == NULL)
		return NULL;
	newnode->key = *key;
79 80 81 82 83 84 85 86 87 88 89 90 91

	if (key->specified & AVTAB_XPERMS) {
		xperms = kmem_cache_zalloc(avtab_xperms_cachep, GFP_KERNEL);
		if (xperms == NULL) {
			kmem_cache_free(avtab_node_cachep, newnode);
			return NULL;
		}
		*xperms = *(datum->u.xperms);
		newnode->datum.u.xperms = xperms;
	} else {
		newnode->datum.u.data = datum->u.data;
	}

L
Linus Torvalds 已提交
92 93 94 95
	if (prev) {
		newnode->next = prev->next;
		prev->next = newnode;
	} else {
96 97 98 99 100 101
		newnode->next = flex_array_get_ptr(h->htable, hvalue);
		if (flex_array_put_ptr(h->htable, hvalue, newnode,
				       GFP_KERNEL|__GFP_ZERO)) {
			kmem_cache_free(avtab_node_cachep, newnode);
			return NULL;
		}
L
Linus Torvalds 已提交
102 103 104 105 106 107 108 109 110 111
	}

	h->nel++;
	return newnode;
}

static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
{
	int hvalue;
	struct avtab_node *prev, *cur, *newnode;
112
	u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
L
Linus Torvalds 已提交
113

114
	if (!h || !h->htable)
L
Linus Torvalds 已提交
115 116
		return -EINVAL;

117
	hvalue = avtab_hash(key, h->mask);
118
	for (prev = NULL, cur = flex_array_get_ptr(h->htable, hvalue);
L
Linus Torvalds 已提交
119 120 121 122 123
	     cur;
	     prev = cur, cur = cur->next) {
		if (key->source_type == cur->key.source_type &&
		    key->target_type == cur->key.target_type &&
		    key->target_class == cur->key.target_class &&
124 125 126 127
		    (specified & cur->key.specified)) {
			/* extended perms may not be unique */
			if (specified & AVTAB_XPERMS)
				break;
L
Linus Torvalds 已提交
128
			return -EEXIST;
129
		}
L
Linus Torvalds 已提交
130 131 132 133 134 135 136 137 138 139 140 141
		if (key->source_type < cur->key.source_type)
			break;
		if (key->source_type == cur->key.source_type &&
		    key->target_type < cur->key.target_type)
			break;
		if (key->source_type == cur->key.source_type &&
		    key->target_type == cur->key.target_type &&
		    key->target_class < cur->key.target_class)
			break;
	}

	newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
142
	if (!newnode)
L
Linus Torvalds 已提交
143 144 145 146 147 148 149 150 151 152
		return -ENOMEM;

	return 0;
}

/* Unlike avtab_insert(), this function allow multiple insertions of the same
 * key/specified mask into the table, as needed by the conditional avtab.
 * It also returns a pointer to the node inserted.
 */
struct avtab_node *
153
avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
L
Linus Torvalds 已提交
154 155
{
	int hvalue;
156
	struct avtab_node *prev, *cur;
157
	u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
L
Linus Torvalds 已提交
158

159
	if (!h || !h->htable)
L
Linus Torvalds 已提交
160
		return NULL;
161
	hvalue = avtab_hash(key, h->mask);
162
	for (prev = NULL, cur = flex_array_get_ptr(h->htable, hvalue);
L
Linus Torvalds 已提交
163 164 165 166 167
	     cur;
	     prev = cur, cur = cur->next) {
		if (key->source_type == cur->key.source_type &&
		    key->target_type == cur->key.target_type &&
		    key->target_class == cur->key.target_class &&
168
		    (specified & cur->key.specified))
L
Linus Torvalds 已提交
169 170 171 172 173 174 175 176 177 178 179
			break;
		if (key->source_type < cur->key.source_type)
			break;
		if (key->source_type == cur->key.source_type &&
		    key->target_type < cur->key.target_type)
			break;
		if (key->source_type == cur->key.source_type &&
		    key->target_type == cur->key.target_type &&
		    key->target_class < cur->key.target_class)
			break;
	}
180
	return avtab_insert_node(h, hvalue, prev, cur, key, datum);
L
Linus Torvalds 已提交
181 182
}

183
struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key)
L
Linus Torvalds 已提交
184 185 186
{
	int hvalue;
	struct avtab_node *cur;
187
	u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
L
Linus Torvalds 已提交
188

189
	if (!h || !h->htable)
L
Linus Torvalds 已提交
190 191
		return NULL;

192
	hvalue = avtab_hash(key, h->mask);
193 194
	for (cur = flex_array_get_ptr(h->htable, hvalue); cur;
	     cur = cur->next) {
L
Linus Torvalds 已提交
195 196 197
		if (key->source_type == cur->key.source_type &&
		    key->target_type == cur->key.target_type &&
		    key->target_class == cur->key.target_class &&
198
		    (specified & cur->key.specified))
L
Linus Torvalds 已提交
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
			return &cur->datum;

		if (key->source_type < cur->key.source_type)
			break;
		if (key->source_type == cur->key.source_type &&
		    key->target_type < cur->key.target_type)
			break;
		if (key->source_type == cur->key.source_type &&
		    key->target_type == cur->key.target_type &&
		    key->target_class < cur->key.target_class)
			break;
	}

	return NULL;
}

/* This search function returns a node pointer, and can be used in
 * conjunction with avtab_search_next_node()
 */
struct avtab_node*
219
avtab_search_node(struct avtab *h, struct avtab_key *key)
L
Linus Torvalds 已提交
220 221 222
{
	int hvalue;
	struct avtab_node *cur;
223
	u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
L
Linus Torvalds 已提交
224

225
	if (!h || !h->htable)
L
Linus Torvalds 已提交
226 227
		return NULL;

228
	hvalue = avtab_hash(key, h->mask);
229 230
	for (cur = flex_array_get_ptr(h->htable, hvalue); cur;
	     cur = cur->next) {
L
Linus Torvalds 已提交
231 232 233
		if (key->source_type == cur->key.source_type &&
		    key->target_type == cur->key.target_type &&
		    key->target_class == cur->key.target_class &&
234
		    (specified & cur->key.specified))
L
Linus Torvalds 已提交
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
			return cur;

		if (key->source_type < cur->key.source_type)
			break;
		if (key->source_type == cur->key.source_type &&
		    key->target_type < cur->key.target_type)
			break;
		if (key->source_type == cur->key.source_type &&
		    key->target_type == cur->key.target_type &&
		    key->target_class < cur->key.target_class)
			break;
	}
	return NULL;
}

struct avtab_node*
avtab_search_node_next(struct avtab_node *node, int specified)
{
	struct avtab_node *cur;

	if (!node)
		return NULL;

258
	specified &= ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
L
Linus Torvalds 已提交
259 260 261 262
	for (cur = node->next; cur; cur = cur->next) {
		if (node->key.source_type == cur->key.source_type &&
		    node->key.target_type == cur->key.target_type &&
		    node->key.target_class == cur->key.target_class &&
263
		    (specified & cur->key.specified))
L
Linus Torvalds 已提交
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
			return cur;

		if (node->key.source_type < cur->key.source_type)
			break;
		if (node->key.source_type == cur->key.source_type &&
		    node->key.target_type < cur->key.target_type)
			break;
		if (node->key.source_type == cur->key.source_type &&
		    node->key.target_type == cur->key.target_type &&
		    node->key.target_class < cur->key.target_class)
			break;
	}
	return NULL;
}

void avtab_destroy(struct avtab *h)
{
	int i;
	struct avtab_node *cur, *temp;

	if (!h || !h->htable)
		return;

287
	for (i = 0; i < h->nslot; i++) {
288
		cur = flex_array_get_ptr(h->htable, i);
289
		while (cur) {
L
Linus Torvalds 已提交
290 291
			temp = cur;
			cur = cur->next;
292 293 294
			if (temp->key.specified & AVTAB_XPERMS)
				kmem_cache_free(avtab_xperms_cachep,
						temp->datum.u.xperms);
L
Linus Torvalds 已提交
295 296 297
			kmem_cache_free(avtab_node_cachep, temp);
		}
	}
298
	flex_array_free(h->htable);
L
Linus Torvalds 已提交
299
	h->htable = NULL;
300 301
	h->nslot = 0;
	h->mask = 0;
L
Linus Torvalds 已提交
302 303 304 305
}

int avtab_init(struct avtab *h)
{
306 307 308 309 310 311 312
	h->htable = NULL;
	h->nel = 0;
	return 0;
}

int avtab_alloc(struct avtab *h, u32 nrules)
{
313
	u32 mask = 0;
314 315 316 317 318 319
	u32 shift = 0;
	u32 work = nrules;
	u32 nslot = 0;

	if (nrules == 0)
		goto avtab_alloc_out;
L
Linus Torvalds 已提交
320

321 322 323 324 325 326 327
	while (work) {
		work  = work >> 1;
		shift++;
	}
	if (shift > 2)
		shift = shift - 2;
	nslot = 1 << shift;
328 329
	if (nslot > MAX_AVTAB_HASH_BUCKETS)
		nslot = MAX_AVTAB_HASH_BUCKETS;
330 331
	mask = nslot - 1;

332 333
	h->htable = flex_array_alloc(sizeof(struct avtab_node *), nslot,
				     GFP_KERNEL | __GFP_ZERO);
L
Linus Torvalds 已提交
334 335
	if (!h->htable)
		return -ENOMEM;
336 337

 avtab_alloc_out:
L
Linus Torvalds 已提交
338
	h->nel = 0;
339 340
	h->nslot = nslot;
	h->mask = mask;
J
James Morris 已提交
341 342
	printk(KERN_DEBUG "SELinux: %d avtab hash slots, %d rules.\n",
	       h->nslot, nrules);
L
Linus Torvalds 已提交
343 344 345 346 347 348
	return 0;
}

void avtab_hash_eval(struct avtab *h, char *tag)
{
	int i, chain_len, slots_used, max_chain_len;
349
	unsigned long long chain2_len_sum;
L
Linus Torvalds 已提交
350 351 352 353
	struct avtab_node *cur;

	slots_used = 0;
	max_chain_len = 0;
354 355
	chain2_len_sum = 0;
	for (i = 0; i < h->nslot; i++) {
356
		cur = flex_array_get_ptr(h->htable, i);
L
Linus Torvalds 已提交
357 358 359 360 361 362 363 364 365 366
		if (cur) {
			slots_used++;
			chain_len = 0;
			while (cur) {
				chain_len++;
				cur = cur->next;
			}

			if (chain_len > max_chain_len)
				max_chain_len = chain_len;
367
			chain2_len_sum += chain_len * chain_len;
L
Linus Torvalds 已提交
368 369 370
		}
	}

E
Eric Paris 已提交
371
	printk(KERN_DEBUG "SELinux: %s:  %d entries and %d/%d buckets used, "
372
	       "longest chain length %d sum of chain length^2 %llu\n",
373 374
	       tag, h->nel, slots_used, h->nslot, max_chain_len,
	       chain2_len_sum);
L
Linus Torvalds 已提交
375 376
}

377 378 379 380 381 382
static uint16_t spec_order[] = {
	AVTAB_ALLOWED,
	AVTAB_AUDITDENY,
	AVTAB_AUDITALLOW,
	AVTAB_TRANSITION,
	AVTAB_CHANGE,
383 384 385 386
	AVTAB_MEMBER,
	AVTAB_XPERMS_ALLOWED,
	AVTAB_XPERMS_AUDITALLOW,
	AVTAB_XPERMS_DONTAUDIT
387 388
};

389
int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
390
		    int (*insertf)(struct avtab *a, struct avtab_key *k,
391 392
				   struct avtab_datum *d, void *p),
		    void *p)
L
Linus Torvalds 已提交
393
{
394 395
	__le16 buf16[4];
	u16 enabled;
396
	u32 items, items2, val, vers = pol->policyvers;
397 398
	struct avtab_key key;
	struct avtab_datum datum;
399 400
	struct avtab_extended_perms xperms;
	__le32 buf32[ARRAY_SIZE(xperms.perms.p)];
401
	int i, rc;
402
	unsigned set;
403 404 405 406 407 408

	memset(&key, 0, sizeof(struct avtab_key));
	memset(&datum, 0, sizeof(struct avtab_datum));

	if (vers < POLICYDB_VERSION_AVTAB) {
		rc = next_entry(buf32, fp, sizeof(u32));
409
		if (rc) {
J
James Morris 已提交
410
			printk(KERN_ERR "SELinux: avtab: truncated entry\n");
411
			return rc;
412 413 414
		}
		items2 = le32_to_cpu(buf32[0]);
		if (items2 > ARRAY_SIZE(buf32)) {
J
James Morris 已提交
415
			printk(KERN_ERR "SELinux: avtab: entry overflow\n");
416
			return -EINVAL;
L
Linus Torvalds 已提交
417

418 419
		}
		rc = next_entry(buf32, fp, sizeof(u32)*items2);
420
		if (rc) {
J
James Morris 已提交
421
			printk(KERN_ERR "SELinux: avtab: truncated entry\n");
422
			return rc;
423 424
		}
		items = 0;
L
Linus Torvalds 已提交
425

426 427 428
		val = le32_to_cpu(buf32[items++]);
		key.source_type = (u16)val;
		if (key.source_type != val) {
E
Eric Paris 已提交
429
			printk(KERN_ERR "SELinux: avtab: truncated source type\n");
430
			return -EINVAL;
431 432 433 434
		}
		val = le32_to_cpu(buf32[items++]);
		key.target_type = (u16)val;
		if (key.target_type != val) {
E
Eric Paris 已提交
435
			printk(KERN_ERR "SELinux: avtab: truncated target type\n");
436
			return -EINVAL;
437 438 439 440
		}
		val = le32_to_cpu(buf32[items++]);
		key.target_class = (u16)val;
		if (key.target_class != val) {
E
Eric Paris 已提交
441
			printk(KERN_ERR "SELinux: avtab: truncated target class\n");
442
			return -EINVAL;
443 444 445 446 447 448
		}

		val = le32_to_cpu(buf32[items++]);
		enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0;

		if (!(val & (AVTAB_AV | AVTAB_TYPE))) {
E
Eric Paris 已提交
449
			printk(KERN_ERR "SELinux: avtab: null entry\n");
450
			return -EINVAL;
451 452 453
		}
		if ((val & AVTAB_AV) &&
		    (val & AVTAB_TYPE)) {
E
Eric Paris 已提交
454
			printk(KERN_ERR "SELinux: avtab: entry has both access vectors and types\n");
455
			return -EINVAL;
456
		}
457 458 459 460
		if (val & AVTAB_XPERMS) {
			printk(KERN_ERR "SELinux: avtab: entry has extended permissions\n");
			return -EINVAL;
		}
461

462
		for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
463 464
			if (val & spec_order[i]) {
				key.specified = spec_order[i] | enabled;
465
				datum.u.data = le32_to_cpu(buf32[items++]);
466
				rc = insertf(a, &key, &datum, p);
467 468
				if (rc)
					return rc;
469 470 471 472
			}
		}

		if (items != items2) {
E
Eric Paris 已提交
473
			printk(KERN_ERR "SELinux: avtab: entry only had %d items, expected %d\n", items2, items);
474
			return -EINVAL;
475 476
		}
		return 0;
L
Linus Torvalds 已提交
477
	}
478 479

	rc = next_entry(buf16, fp, sizeof(u16)*4);
480
	if (rc) {
E
Eric Paris 已提交
481
		printk(KERN_ERR "SELinux: avtab: truncated entry\n");
482
		return rc;
L
Linus Torvalds 已提交
483
	}
484

L
Linus Torvalds 已提交
485
	items = 0;
486 487 488 489 490
	key.source_type = le16_to_cpu(buf16[items++]);
	key.target_type = le16_to_cpu(buf16[items++]);
	key.target_class = le16_to_cpu(buf16[items++]);
	key.specified = le16_to_cpu(buf16[items++]);

491 492 493
	if (!policydb_type_isvalid(pol, key.source_type) ||
	    !policydb_type_isvalid(pol, key.target_type) ||
	    !policydb_class_isvalid(pol, key.target_class)) {
E
Eric Paris 已提交
494
		printk(KERN_ERR "SELinux: avtab: invalid type or class\n");
495
		return -EINVAL;
496 497 498 499 500 501 502 503
	}

	set = 0;
	for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
		if (key.specified & spec_order[i])
			set++;
	}
	if (!set || set > 1) {
E
Eric Paris 已提交
504
		printk(KERN_ERR "SELinux:  avtab:  more than one specifier\n");
505
		return -EINVAL;
506 507
	}

508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
	if ((vers < POLICYDB_VERSION_XPERMS_IOCTL) &&
			(key.specified & AVTAB_XPERMS)) {
		printk(KERN_ERR "SELinux:  avtab:  policy version %u does not "
				"support extended permissions rules and one "
				"was specified\n", vers);
		return -EINVAL;
	} else if (key.specified & AVTAB_XPERMS) {
		memset(&xperms, 0, sizeof(struct avtab_extended_perms));
		rc = next_entry(&xperms.specified, fp, sizeof(u8));
		if (rc) {
			printk(KERN_ERR "SELinux: avtab: truncated entry\n");
			return rc;
		}
		rc = next_entry(&xperms.driver, fp, sizeof(u8));
		if (rc) {
			printk(KERN_ERR "SELinux: avtab: truncated entry\n");
			return rc;
		}
		rc = next_entry(buf32, fp, sizeof(u32)*ARRAY_SIZE(xperms.perms.p));
		if (rc) {
			printk(KERN_ERR "SELinux: avtab: truncated entry\n");
			return rc;
		}
		for (i = 0; i < ARRAY_SIZE(xperms.perms.p); i++)
			xperms.perms.p[i] = le32_to_cpu(buf32[i]);
		datum.u.xperms = &xperms;
	} else {
		rc = next_entry(buf32, fp, sizeof(u32));
		if (rc) {
			printk(KERN_ERR "SELinux: avtab: truncated entry\n");
			return rc;
		}
		datum.u.data = le32_to_cpu(*buf32);
L
Linus Torvalds 已提交
541
	}
542
	if ((key.specified & AVTAB_TYPE) &&
543
	    !policydb_type_isvalid(pol, datum.u.data)) {
E
Eric Paris 已提交
544
		printk(KERN_ERR "SELinux: avtab: invalid type\n");
545
		return -EINVAL;
546
	}
547 548
	return insertf(a, &key, &datum, p);
}
L
Linus Torvalds 已提交
549

550 551 552 553
static int avtab_insertf(struct avtab *a, struct avtab_key *k,
			 struct avtab_datum *d, void *p)
{
	return avtab_insert(a, k, d);
L
Linus Torvalds 已提交
554 555
}

556
int avtab_read(struct avtab *a, void *fp, struct policydb *pol)
L
Linus Torvalds 已提交
557 558
{
	int rc;
559
	__le32 buf[1];
L
Linus Torvalds 已提交
560 561 562 563 564
	u32 nel, i;


	rc = next_entry(buf, fp, sizeof(u32));
	if (rc < 0) {
J
James Morris 已提交
565
		printk(KERN_ERR "SELinux: avtab: truncated table\n");
L
Linus Torvalds 已提交
566 567 568 569
		goto bad;
	}
	nel = le32_to_cpu(buf[0]);
	if (!nel) {
J
James Morris 已提交
570
		printk(KERN_ERR "SELinux: avtab: table is empty\n");
L
Linus Torvalds 已提交
571 572 573
		rc = -EINVAL;
		goto bad;
	}
574 575 576 577 578

	rc = avtab_alloc(a, nel);
	if (rc)
		goto bad;

L
Linus Torvalds 已提交
579
	for (i = 0; i < nel; i++) {
580
		rc = avtab_read_item(a, fp, pol, avtab_insertf, NULL);
L
Linus Torvalds 已提交
581 582
		if (rc) {
			if (rc == -ENOMEM)
J
James Morris 已提交
583
				printk(KERN_ERR "SELinux: avtab: out of memory\n");
584
			else if (rc == -EEXIST)
J
James Morris 已提交
585
				printk(KERN_ERR "SELinux: avtab: duplicate entry\n");
586

L
Linus Torvalds 已提交
587 588 589 590 591 592 593 594 595 596 597 598 599
			goto bad;
		}
	}

	rc = 0;
out:
	return rc;

bad:
	avtab_destroy(a);
	goto out;
}

600 601 602
int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp)
{
	__le16 buf16[4];
603
	__le32 buf32[ARRAY_SIZE(cur->datum.u.xperms->perms.p)];
604
	int rc;
605
	unsigned int i;
606 607 608 609 610 611 612 613

	buf16[0] = cpu_to_le16(cur->key.source_type);
	buf16[1] = cpu_to_le16(cur->key.target_type);
	buf16[2] = cpu_to_le16(cur->key.target_class);
	buf16[3] = cpu_to_le16(cur->key.specified);
	rc = put_entry(buf16, sizeof(u16), 4, fp);
	if (rc)
		return rc;
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629

	if (cur->key.specified & AVTAB_XPERMS) {
		rc = put_entry(&cur->datum.u.xperms->specified, sizeof(u8), 1, fp);
		if (rc)
			return rc;
		rc = put_entry(&cur->datum.u.xperms->driver, sizeof(u8), 1, fp);
		if (rc)
			return rc;
		for (i = 0; i < ARRAY_SIZE(cur->datum.u.xperms->perms.p); i++)
			buf32[i] = cpu_to_le32(cur->datum.u.xperms->perms.p[i]);
		rc = put_entry(buf32, sizeof(u32),
				ARRAY_SIZE(cur->datum.u.xperms->perms.p), fp);
	} else {
		buf32[0] = cpu_to_le32(cur->datum.u.data);
		rc = put_entry(buf32, sizeof(u32), 1, fp);
	}
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647
	if (rc)
		return rc;
	return 0;
}

int avtab_write(struct policydb *p, struct avtab *a, void *fp)
{
	unsigned int i;
	int rc = 0;
	struct avtab_node *cur;
	__le32 buf[1];

	buf[0] = cpu_to_le32(a->nel);
	rc = put_entry(buf, sizeof(u32), 1, fp);
	if (rc)
		return rc;

	for (i = 0; i < a->nslot; i++) {
648 649
		for (cur = flex_array_get_ptr(a->htable, i); cur;
		     cur = cur->next) {
650 651 652 653 654 655 656 657
			rc = avtab_write_item(p, cur, fp);
			if (rc)
				return rc;
		}
	}

	return rc;
}
L
Linus Torvalds 已提交
658 659 660 661
void avtab_cache_init(void)
{
	avtab_node_cachep = kmem_cache_create("avtab_node",
					      sizeof(struct avtab_node),
662
					      0, SLAB_PANIC, NULL);
663 664 665
	avtab_xperms_cachep = kmem_cache_create("avtab_extended_perms",
						sizeof(struct avtab_extended_perms),
						0, SLAB_PANIC, NULL);
L
Linus Torvalds 已提交
666 667 668 669
}

void avtab_cache_destroy(void)
{
670
	kmem_cache_destroy(avtab_node_cachep);
671
	kmem_cache_destroy(avtab_xperms_cachep);
L
Linus Torvalds 已提交
672
}