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