/src/selinux/libsepol/src/avtab.c
Line | Count | Source |
1 | | |
2 | | /* Author : Stephen Smalley, <stephen.smalley.work@gmail.com> */ |
3 | | |
4 | | /* |
5 | | * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp> |
6 | | * Tuned number of hash slots for avtab to reduce memory usage |
7 | | */ |
8 | | |
9 | | /* Updated: Frank Mayer <mayerf@tresys.com> |
10 | | * and Karl MacMillan <kmacmillan@mentalrootkit.com> |
11 | | * |
12 | | * Added conditional policy language extensions |
13 | | * |
14 | | * Updated: Red Hat, Inc. James Morris <jmorris@redhat.com> |
15 | | * |
16 | | * Code cleanup |
17 | | * |
18 | | * Updated: Karl MacMillan <kmacmillan@mentalrootkit.com> |
19 | | * |
20 | | * Copyright (C) 2003 Tresys Technology, LLC |
21 | | * Copyright (C) 2003,2007 Red Hat, Inc. |
22 | | * |
23 | | * This library is free software; you can redistribute it and/or |
24 | | * modify it under the terms of the GNU Lesser General Public |
25 | | * License as published by the Free Software Foundation; either |
26 | | * version 2.1 of the License, or (at your option) any later version. |
27 | | * |
28 | | * This library is distributed in the hope that it will be useful, |
29 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
30 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
31 | | * Lesser General Public License for more details. |
32 | | * |
33 | | * You should have received a copy of the GNU Lesser General Public |
34 | | * License along with this library; if not, write to the Free Software |
35 | | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
36 | | */ |
37 | | |
38 | | /* FLASK */ |
39 | | |
40 | | /* |
41 | | * Implementation of the access vector table type. |
42 | | */ |
43 | | |
44 | | #include <stdlib.h> |
45 | | #include <sepol/policydb/avtab.h> |
46 | | #include <sepol/policydb/policydb.h> |
47 | | #include <sepol/errcodes.h> |
48 | | |
49 | | #include "debug.h" |
50 | | #include "private.h" |
51 | | |
52 | | /* Based on MurmurHash3, written by Austin Appleby and placed in the |
53 | | * public domain. |
54 | | */ |
55 | | ignore_unsigned_overflow_ |
56 | | static inline int avtab_hash(struct avtab_key *keyp, uint32_t mask) |
57 | 31.1k | { |
58 | 31.1k | static const uint32_t c1 = 0xcc9e2d51; |
59 | 31.1k | static const uint32_t c2 = 0x1b873593; |
60 | 31.1k | static const uint32_t r1 = 15; |
61 | 31.1k | static const uint32_t r2 = 13; |
62 | 31.1k | static const uint32_t m = 5; |
63 | 31.1k | static const uint32_t n = 0xe6546b64; |
64 | | |
65 | 31.1k | uint32_t hash = 0; |
66 | | |
67 | 93.4k | #define mix(input) do { \ |
68 | 93.4k | uint32_t v = input; \ |
69 | 93.4k | v *= c1; \ |
70 | 93.4k | v = (v << r1) | (v >> (32 - r1)); \ |
71 | 93.4k | v *= c2; \ |
72 | 93.4k | hash ^= v; \ |
73 | 93.4k | hash = (hash << r2) | (hash >> (32 - r2)); \ |
74 | 93.4k | hash = hash * m + n; \ |
75 | 93.4k | } while (0) |
76 | | |
77 | 31.1k | mix(keyp->target_class); |
78 | 31.1k | mix(keyp->target_type); |
79 | 31.1k | mix(keyp->source_type); |
80 | | |
81 | 31.1k | #undef mix |
82 | | |
83 | 31.1k | hash ^= hash >> 16; |
84 | 31.1k | hash *= 0x85ebca6b; |
85 | 31.1k | hash ^= hash >> 13; |
86 | 31.1k | hash *= 0xc2b2ae35; |
87 | 31.1k | hash ^= hash >> 16; |
88 | | |
89 | 31.1k | return hash & mask; |
90 | 31.1k | } |
91 | | |
92 | | static avtab_ptr_t |
93 | | avtab_insert_node(avtab_t * h, int hvalue, avtab_ptr_t prev, avtab_key_t * key, |
94 | | avtab_datum_t * datum) |
95 | 20.6k | { |
96 | 20.6k | avtab_ptr_t newnode; |
97 | 20.6k | avtab_extended_perms_t *xperms; |
98 | | |
99 | 20.6k | newnode = (avtab_ptr_t) malloc(sizeof(struct avtab_node)); |
100 | 20.6k | if (newnode == NULL) |
101 | 0 | return NULL; |
102 | 20.6k | memset(newnode, 0, sizeof(struct avtab_node)); |
103 | 20.6k | newnode->key = *key; |
104 | | |
105 | 20.6k | if (key->specified & AVTAB_XPERMS) { |
106 | 7.09k | xperms = calloc(1, sizeof(avtab_extended_perms_t)); |
107 | 7.09k | if (xperms == NULL) { |
108 | 0 | free(newnode); |
109 | 0 | return NULL; |
110 | 0 | } |
111 | 7.09k | if (datum->xperms) /* else caller populates xperms */ |
112 | 4.06k | *xperms = *(datum->xperms); |
113 | | |
114 | 7.09k | newnode->datum.xperms = xperms; |
115 | | /* data is usually ignored with xperms, except in the case of |
116 | | * neverallow checking, which requires permission bits to be set. |
117 | | * So copy data so it is set in the avtab |
118 | | */ |
119 | 7.09k | newnode->datum.data = datum->data; |
120 | 13.5k | } else { |
121 | 13.5k | newnode->datum = *datum; |
122 | 13.5k | } |
123 | | |
124 | 20.6k | if (prev) { |
125 | 8.79k | newnode->next = prev->next; |
126 | 8.79k | prev->next = newnode; |
127 | 11.8k | } else { |
128 | 11.8k | newnode->next = h->htable[hvalue]; |
129 | 11.8k | h->htable[hvalue] = newnode; |
130 | 11.8k | } |
131 | | |
132 | 20.6k | h->nel++; |
133 | 20.6k | return newnode; |
134 | 20.6k | } |
135 | | |
136 | | int avtab_insert(avtab_t * h, avtab_key_t * key, avtab_datum_t * datum) |
137 | 10.0k | { |
138 | 10.0k | int hvalue; |
139 | 10.0k | avtab_ptr_t prev, cur, newnode; |
140 | 10.0k | uint16_t specified = |
141 | 10.0k | key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD); |
142 | | |
143 | 10.0k | if (!h || !h->htable) |
144 | 0 | return SEPOL_ENOMEM; |
145 | | |
146 | 10.0k | hvalue = avtab_hash(key, h->mask); |
147 | 10.0k | for (prev = NULL, cur = h->htable[hvalue]; |
148 | 15.1k | cur; prev = cur, cur = cur->next) { |
149 | 6.39k | if (key->source_type == cur->key.source_type && |
150 | 5.23k | key->target_type == cur->key.target_type && |
151 | 3.92k | key->target_class == cur->key.target_class && |
152 | 3.42k | (specified & cur->key.specified)) { |
153 | | /* Extended permissions are not necessarily unique */ |
154 | 862 | if (specified & AVTAB_XPERMS) |
155 | 860 | break; |
156 | 2 | return SEPOL_EEXIST; |
157 | 862 | } |
158 | 5.53k | if (key->source_type < cur->key.source_type) |
159 | 214 | break; |
160 | 5.31k | if (key->source_type == cur->key.source_type && |
161 | 4.36k | key->target_type < cur->key.target_type) |
162 | 190 | break; |
163 | 5.12k | if (key->source_type == cur->key.source_type && |
164 | 4.17k | key->target_type == cur->key.target_type && |
165 | 3.06k | key->target_class < cur->key.target_class) |
166 | 64 | break; |
167 | 5.12k | } |
168 | | |
169 | 10.0k | newnode = avtab_insert_node(h, hvalue, prev, key, datum); |
170 | 10.0k | if (!newnode) |
171 | 0 | return SEPOL_ENOMEM; |
172 | | |
173 | 10.0k | return 0; |
174 | 10.0k | } |
175 | | |
176 | | /* Unlike avtab_insert(), this function allow multiple insertions of the same |
177 | | * key/specified mask into the table, as needed by the conditional avtab. |
178 | | * It also returns a pointer to the node inserted. |
179 | | */ |
180 | | avtab_ptr_t |
181 | | avtab_insert_nonunique(avtab_t * h, avtab_key_t * key, avtab_datum_t * datum) |
182 | 10.5k | { |
183 | 10.5k | int hvalue; |
184 | 10.5k | avtab_ptr_t prev, cur, newnode; |
185 | 10.5k | uint16_t specified = |
186 | 10.5k | key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD); |
187 | | |
188 | 10.5k | if (!h || !h->htable) |
189 | 0 | return NULL; |
190 | 10.5k | hvalue = avtab_hash(key, h->mask); |
191 | 10.5k | for (prev = NULL, cur = h->htable[hvalue]; |
192 | 462k | cur; prev = cur, cur = cur->next) { |
193 | 459k | if (key->source_type == cur->key.source_type && |
194 | 440k | key->target_type == cur->key.target_type && |
195 | 254k | key->target_class == cur->key.target_class && |
196 | 214k | (specified & cur->key.specified)) |
197 | 5.97k | break; |
198 | 453k | if (key->source_type < cur->key.source_type) |
199 | 756 | break; |
200 | 452k | if (key->source_type == cur->key.source_type && |
201 | 434k | key->target_type < cur->key.target_type) |
202 | 531 | break; |
203 | 452k | if (key->source_type == cur->key.source_type && |
204 | 433k | key->target_type == cur->key.target_type && |
205 | 248k | key->target_class < cur->key.target_class) |
206 | 479 | break; |
207 | 452k | } |
208 | 10.5k | newnode = avtab_insert_node(h, hvalue, prev, key, datum); |
209 | | |
210 | 10.5k | return newnode; |
211 | 10.5k | } |
212 | | |
213 | | avtab_datum_t *avtab_search(avtab_t * h, avtab_key_t * key) |
214 | 9.42k | { |
215 | 9.42k | int hvalue; |
216 | 9.42k | avtab_ptr_t cur; |
217 | 9.42k | uint16_t specified = |
218 | 9.42k | key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD); |
219 | | |
220 | 9.42k | if (!h || !h->htable) |
221 | 99 | return NULL; |
222 | | |
223 | 9.32k | hvalue = avtab_hash(key, h->mask); |
224 | 19.1k | for (cur = h->htable[hvalue]; cur; cur = cur->next) { |
225 | 14.9k | if (key->source_type == cur->key.source_type && |
226 | 11.3k | key->target_type == cur->key.target_type && |
227 | 7.41k | key->target_class == cur->key.target_class && |
228 | 5.74k | (specified & cur->key.specified)) |
229 | 3.35k | return &cur->datum; |
230 | | |
231 | 11.5k | if (key->source_type < cur->key.source_type) |
232 | 1.14k | break; |
233 | 10.4k | if (key->source_type == cur->key.source_type && |
234 | 7.96k | key->target_type < cur->key.target_type) |
235 | 427 | break; |
236 | 9.98k | if (key->source_type == cur->key.source_type && |
237 | 7.54k | key->target_type == cur->key.target_type && |
238 | 4.06k | key->target_class < cur->key.target_class) |
239 | 175 | break; |
240 | 9.98k | } |
241 | | |
242 | 5.97k | return NULL; |
243 | 9.32k | } |
244 | | |
245 | | /* This search function returns a node pointer, and can be used in |
246 | | * conjunction with avtab_search_next_node() |
247 | | */ |
248 | | avtab_ptr_t avtab_search_node(avtab_t * h, avtab_key_t * key) |
249 | 1.21k | { |
250 | 1.21k | int hvalue; |
251 | 1.21k | avtab_ptr_t cur; |
252 | 1.21k | uint16_t specified = |
253 | 1.21k | key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD); |
254 | | |
255 | 1.21k | if (!h || !h->htable) |
256 | 0 | return NULL; |
257 | | |
258 | 1.21k | hvalue = avtab_hash(key, h->mask); |
259 | 8.08k | for (cur = h->htable[hvalue]; cur; cur = cur->next) { |
260 | 7.60k | if (key->source_type == cur->key.source_type && |
261 | 4.50k | key->target_type == cur->key.target_type && |
262 | 2.75k | key->target_class == cur->key.target_class && |
263 | 1.97k | (specified & cur->key.specified)) |
264 | 382 | return cur; |
265 | | |
266 | 7.22k | if (key->source_type < cur->key.source_type) |
267 | 144 | break; |
268 | 7.08k | if (key->source_type == cur->key.source_type && |
269 | 4.11k | key->target_type < cur->key.target_type) |
270 | 123 | break; |
271 | 6.95k | if (key->source_type == cur->key.source_type && |
272 | 3.99k | key->target_type == cur->key.target_type && |
273 | 2.37k | key->target_class < cur->key.target_class) |
274 | 90 | break; |
275 | 6.95k | } |
276 | 833 | return NULL; |
277 | 1.21k | } |
278 | | |
279 | | avtab_ptr_t avtab_search_node_next(avtab_ptr_t node, int specified) |
280 | 718 | { |
281 | 718 | avtab_ptr_t cur; |
282 | | |
283 | 718 | if (!node) |
284 | 0 | return NULL; |
285 | | |
286 | 718 | specified &= ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD); |
287 | 1.38k | for (cur = node->next; cur; cur = cur->next) { |
288 | 1.16k | if (node->key.source_type == cur->key.source_type && |
289 | 1.04k | node->key.target_type == cur->key.target_type && |
290 | 938 | node->key.target_class == cur->key.target_class && |
291 | 897 | (specified & cur->key.specified)) |
292 | 226 | return cur; |
293 | | |
294 | 942 | if (node->key.source_type < cur->key.source_type) |
295 | 121 | break; |
296 | 821 | if (node->key.source_type == cur->key.source_type && |
297 | 821 | node->key.target_type < cur->key.target_type) |
298 | 109 | break; |
299 | 712 | if (node->key.source_type == cur->key.source_type && |
300 | 712 | node->key.target_type == cur->key.target_type && |
301 | 712 | node->key.target_class < cur->key.target_class) |
302 | 41 | break; |
303 | 712 | } |
304 | 492 | return NULL; |
305 | 718 | } |
306 | | |
307 | | void avtab_destroy(avtab_t * h) |
308 | 51.8k | { |
309 | 51.8k | unsigned int i; |
310 | 51.8k | avtab_ptr_t cur, temp; |
311 | | |
312 | 51.8k | if (!h || !h->htable) |
313 | 38.1k | return; |
314 | | |
315 | 428M | for (i = 0; i < h->nslot; i++) { |
316 | 428M | cur = h->htable[i]; |
317 | 428M | while (cur != NULL) { |
318 | 20.3k | if (cur->key.specified & AVTAB_XPERMS) { |
319 | 6.80k | free(cur->datum.xperms); |
320 | 6.80k | } |
321 | 20.3k | temp = cur; |
322 | 20.3k | cur = cur->next; |
323 | 20.3k | free(temp); |
324 | 20.3k | } |
325 | 428M | h->htable[i] = NULL; |
326 | 428M | } |
327 | 13.6k | free(h->htable); |
328 | 13.6k | h->htable = NULL; |
329 | 13.6k | h->nslot = 0; |
330 | 13.6k | h->mask = 0; |
331 | 13.6k | } |
332 | | |
333 | | int avtab_map(const avtab_t * h, |
334 | | int (*apply) (avtab_key_t * k, |
335 | | avtab_datum_t * d, void *args), void *args) |
336 | 25.1k | { |
337 | 25.1k | unsigned int i; |
338 | 25.1k | int ret; |
339 | 25.1k | avtab_ptr_t cur; |
340 | | |
341 | 25.1k | if (!h) |
342 | 0 | return 0; |
343 | | |
344 | 3.30G | for (i = 0; i < h->nslot; i++) { |
345 | 3.30G | cur = h->htable[i]; |
346 | 3.30G | while (cur != NULL) { |
347 | 38.7k | ret = apply(&cur->key, &cur->datum, args); |
348 | 38.7k | if (ret) |
349 | 318 | return ret; |
350 | 38.4k | cur = cur->next; |
351 | 38.4k | } |
352 | 3.30G | } |
353 | 24.8k | return 0; |
354 | 25.1k | } |
355 | | |
356 | | int avtab_init(avtab_t * h) |
357 | 26.6k | { |
358 | 26.6k | h->htable = NULL; |
359 | 26.6k | h->nel = 0; |
360 | 26.6k | return 0; |
361 | 26.6k | } |
362 | | |
363 | | int avtab_alloc(avtab_t *h, uint32_t nrules) |
364 | 19.8k | { |
365 | 19.8k | uint32_t mask = 0; |
366 | 19.8k | uint32_t shift = 0; |
367 | 19.8k | uint32_t work = nrules; |
368 | 19.8k | uint32_t nslot = 0; |
369 | | |
370 | 19.8k | if (nrules == 0) |
371 | 6.25k | goto out; |
372 | | |
373 | 47.2k | while (work) { |
374 | 33.5k | work = work >> 1; |
375 | 33.5k | shift++; |
376 | 33.5k | } |
377 | 13.6k | if (shift > 2) |
378 | 1.68k | shift = shift - 2; |
379 | 13.6k | nslot = UINT32_C(1) << shift; |
380 | 13.6k | if (nslot > MAX_AVTAB_HASH_BUCKETS) |
381 | 0 | nslot = MAX_AVTAB_HASH_BUCKETS; |
382 | 13.6k | mask = nslot - 1; |
383 | | |
384 | 13.6k | h->htable = calloc(nslot, sizeof(avtab_ptr_t)); |
385 | 13.6k | if (!h->htable) |
386 | 0 | return -1; |
387 | 19.8k | out: |
388 | 19.8k | h->nel = 0; |
389 | 19.8k | h->nslot = nslot; |
390 | 19.8k | h->mask = mask; |
391 | 19.8k | return 0; |
392 | 13.6k | } |
393 | | |
394 | | void avtab_hash_eval(avtab_t * h, char *tag) |
395 | 0 | { |
396 | 0 | unsigned int i, chain_len, slots_used, max_chain_len; |
397 | 0 | avtab_ptr_t cur; |
398 | |
|
399 | 0 | slots_used = 0; |
400 | 0 | max_chain_len = 0; |
401 | 0 | for (i = 0; i < h->nslot; i++) { |
402 | 0 | cur = h->htable[i]; |
403 | 0 | if (cur) { |
404 | 0 | slots_used++; |
405 | 0 | chain_len = 0; |
406 | 0 | while (cur) { |
407 | 0 | chain_len++; |
408 | 0 | cur = cur->next; |
409 | 0 | } |
410 | |
|
411 | 0 | if (chain_len > max_chain_len) |
412 | 0 | max_chain_len = chain_len; |
413 | 0 | } |
414 | 0 | } |
415 | |
|
416 | 0 | printf |
417 | 0 | ("%s: %d entries and %d/%d buckets used, longest chain length %d\n", |
418 | 0 | tag, h->nel, slots_used, h->nslot, max_chain_len); |
419 | 0 | } |
420 | | |
421 | | /* Ordering of datums in the original avtab format in the policy file. */ |
422 | | static const uint16_t spec_order[] = { |
423 | | AVTAB_ALLOWED, |
424 | | AVTAB_AUDITDENY, |
425 | | AVTAB_AUDITALLOW, |
426 | | AVTAB_TRANSITION, |
427 | | AVTAB_CHANGE, |
428 | | AVTAB_MEMBER, |
429 | | AVTAB_XPERMS_ALLOWED, |
430 | | AVTAB_XPERMS_AUDITALLOW, |
431 | | AVTAB_XPERMS_DONTAUDIT |
432 | | }; |
433 | | |
434 | | int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a, |
435 | | int (*insertf) (avtab_t * a, avtab_key_t * k, |
436 | | avtab_datum_t * d, void *p), void *p) |
437 | 15.0k | { |
438 | 15.0k | uint8_t buf8; |
439 | 15.0k | uint16_t buf16[4], enabled; |
440 | 15.0k | uint32_t buf32[8], items, items2, val; |
441 | 15.0k | avtab_key_t key; |
442 | 15.0k | avtab_datum_t datum; |
443 | 15.0k | avtab_extended_perms_t xperms; |
444 | 15.0k | unsigned int i; |
445 | 15.0k | int rc; |
446 | | |
447 | 15.0k | memset(&key, 0, sizeof(avtab_key_t)); |
448 | 15.0k | memset(&datum, 0, sizeof(avtab_datum_t)); |
449 | 15.0k | memset(&xperms, 0, sizeof(avtab_extended_perms_t)); |
450 | | |
451 | 15.0k | if (vers < POLICYDB_VERSION_AVTAB) { |
452 | 4.96k | rc = next_entry(buf32, fp, sizeof(uint32_t)); |
453 | 4.96k | if (rc < 0) { |
454 | 245 | ERR(fp->handle, "truncated entry"); |
455 | 245 | return -1; |
456 | 245 | } |
457 | 4.71k | items2 = le32_to_cpu(buf32[0]); |
458 | | |
459 | 4.71k | if (items2 < 5 || items2 > ARRAY_SIZE(buf32)) { |
460 | 82 | ERR(fp->handle, "invalid item count"); |
461 | 82 | return -1; |
462 | 82 | } |
463 | | |
464 | 4.63k | rc = next_entry(buf32, fp, sizeof(uint32_t) * items2); |
465 | 4.63k | if (rc < 0) { |
466 | 4 | ERR(fp->handle, "truncated entry"); |
467 | 4 | return -1; |
468 | 4 | } |
469 | | |
470 | 4.63k | items = 0; |
471 | 4.63k | val = le32_to_cpu(buf32[items++]); |
472 | 4.63k | key.source_type = (uint16_t) val; |
473 | 4.63k | if (key.source_type != val) { |
474 | 23 | ERR(fp->handle, "truncated source type"); |
475 | 23 | return -1; |
476 | 23 | } |
477 | 4.60k | val = le32_to_cpu(buf32[items++]); |
478 | 4.60k | key.target_type = (uint16_t) val; |
479 | 4.60k | if (key.target_type != val) { |
480 | 27 | ERR(fp->handle, "truncated target type"); |
481 | 27 | return -1; |
482 | 27 | } |
483 | 4.58k | val = le32_to_cpu(buf32[items++]); |
484 | 4.58k | key.target_class = (uint16_t) val; |
485 | 4.58k | if (key.target_class != val) { |
486 | 27 | ERR(fp->handle, "truncated target class"); |
487 | 27 | return -1; |
488 | 27 | } |
489 | | |
490 | 4.55k | val = le32_to_cpu(buf32[items++]); |
491 | 4.55k | enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0; |
492 | | |
493 | 4.55k | if (!(val & (AVTAB_AV | AVTAB_TYPE))) { |
494 | 11 | ERR(fp->handle, "null entry"); |
495 | 11 | return -1; |
496 | 11 | } |
497 | 4.54k | if ((val & AVTAB_AV) && (val & AVTAB_TYPE)) { |
498 | 4 | ERR(fp->handle, "entry has both access " |
499 | 4 | "vectors and types"); |
500 | 4 | return -1; |
501 | 4 | } |
502 | | |
503 | 45.1k | for (i = 0; i < ARRAY_SIZE(spec_order); i++) { |
504 | 40.7k | if (val & spec_order[i]) { |
505 | 10.3k | if (items >= items2) { /* items is index, items2 is total number */ |
506 | 76 | ERR(fp->handle, "entry has too many items (%d/%d)", |
507 | 76 | items + 1, items2); |
508 | 76 | return -1; |
509 | 76 | } |
510 | 10.2k | key.specified = spec_order[i] | enabled; |
511 | 10.2k | datum.data = le32_to_cpu(buf32[items++]); |
512 | 10.2k | rc = insertf(a, &key, &datum, p); |
513 | 10.2k | if (rc) |
514 | 2 | return rc; |
515 | 10.2k | } |
516 | 40.7k | } |
517 | | |
518 | 4.46k | if (items != items2) { |
519 | 10 | ERR(fp->handle, "entry only had %d items, " |
520 | 10 | "expected %d", items2, items); |
521 | 10 | return -1; |
522 | 10 | } |
523 | 4.45k | return 0; |
524 | 4.46k | } |
525 | | |
526 | 10.1k | rc = next_entry(buf16, fp, sizeof(uint16_t) * 4); |
527 | 10.1k | if (rc < 0) { |
528 | 312 | ERR(fp->handle, "truncated entry"); |
529 | 312 | return -1; |
530 | 312 | } |
531 | 9.80k | items = 0; |
532 | 9.80k | key.source_type = le16_to_cpu(buf16[items++]); |
533 | 9.80k | key.target_type = le16_to_cpu(buf16[items++]); |
534 | 9.80k | key.target_class = le16_to_cpu(buf16[items++]); |
535 | 9.80k | key.specified = le16_to_cpu(buf16[items++]); |
536 | | |
537 | 9.80k | if (key.specified & ~(AVTAB_AV | AVTAB_TYPE | AVTAB_XPERMS | AVTAB_ENABLED)) { |
538 | 14 | ERR(fp->handle, "invalid specifier"); |
539 | 14 | return -1; |
540 | 14 | } |
541 | | |
542 | 9.79k | if (__builtin_popcount(key.specified & ~AVTAB_ENABLED) != 1) { |
543 | 11 | ERR(fp->handle, "not exactly one specifier"); |
544 | 11 | return -1; |
545 | 11 | } |
546 | | |
547 | 9.78k | if ((vers < POLICYDB_VERSION_XPERMS_IOCTL) && |
548 | 2.59k | (key.specified & AVTAB_XPERMS)) { |
549 | 4 | ERR(fp->handle, "policy version %u does not support extended " |
550 | 4 | "permissions rules and one was specified", vers); |
551 | 4 | return -1; |
552 | 9.78k | } else if (key.specified & AVTAB_XPERMS) { |
553 | 4.06k | rc = next_entry(&buf8, fp, sizeof(uint8_t)); |
554 | 4.06k | if (rc < 0) { |
555 | 1 | ERR(fp->handle, "truncated entry"); |
556 | 1 | return -1; |
557 | 1 | } |
558 | 4.06k | xperms.specified = buf8; |
559 | 4.06k | rc = next_entry(&buf8, fp, sizeof(uint8_t)); |
560 | 4.06k | if (rc < 0) { |
561 | 1 | ERR(fp->handle, "truncated entry"); |
562 | 1 | return -1; |
563 | 1 | } |
564 | 4.06k | xperms.driver = buf8; |
565 | 4.06k | rc = next_entry(buf32, fp, sizeof(uint32_t)*8); |
566 | 4.06k | if (rc < 0) { |
567 | 2 | ERR(fp->handle, "truncated entry"); |
568 | 2 | return -1; |
569 | 2 | } |
570 | 36.5k | for (i = 0; i < ARRAY_SIZE(xperms.perms); i++) |
571 | 32.4k | xperms.perms[i] = le32_to_cpu(buf32[i]); |
572 | 4.06k | datum.xperms = &xperms; |
573 | 5.71k | } else { |
574 | 5.71k | rc = next_entry(buf32, fp, sizeof(uint32_t)); |
575 | 5.71k | if (rc < 0) { |
576 | 3 | ERR(fp->handle, "truncated entry"); |
577 | 3 | return -1; |
578 | 3 | } |
579 | 5.71k | datum.data = le32_to_cpu(*buf32); |
580 | 5.71k | } |
581 | 9.77k | return insertf(a, &key, &datum, p); |
582 | 9.78k | } |
583 | | |
584 | | static int avtab_insertf(avtab_t * a, avtab_key_t * k, avtab_datum_t * d, |
585 | | void *p __attribute__ ((unused))) |
586 | 9.57k | { |
587 | 9.57k | return avtab_insert(a, k, d); |
588 | 9.57k | } |
589 | | |
590 | | int avtab_read(avtab_t * a, struct policy_file *fp, uint32_t vers) |
591 | 6.97k | { |
592 | 6.97k | unsigned int i; |
593 | 6.97k | int rc; |
594 | 6.97k | uint32_t buf[1]; |
595 | 6.97k | uint32_t nel; |
596 | | |
597 | 6.97k | rc = next_entry(buf, fp, sizeof(uint32_t)); |
598 | 6.97k | if (rc < 0) { |
599 | 7 | ERR(fp->handle, "truncated table"); |
600 | 7 | goto bad; |
601 | 7 | } |
602 | 6.97k | nel = le32_to_cpu(buf[0]); |
603 | 6.97k | if (zero_or_saturated(nel) || exceeds_available_bytes(fp, nel, sizeof(uint32_t) * 3)) { |
604 | 83 | ERR(fp->handle, "table is empty"); |
605 | 83 | goto bad; |
606 | 83 | } |
607 | | |
608 | 6.88k | rc = avtab_alloc(a, nel); |
609 | 6.88k | if (rc) { |
610 | 0 | ERR(fp->handle, "out of memory"); |
611 | 0 | goto bad; |
612 | 0 | } |
613 | | |
614 | 15.1k | for (i = 0; i < nel; i++) { |
615 | 8.60k | rc = avtab_read_item(fp, vers, a, avtab_insertf, NULL); |
616 | 8.60k | if (rc) { |
617 | 299 | if (rc == SEPOL_ENOMEM) |
618 | 299 | ERR(fp->handle, "out of memory"); |
619 | 299 | if (rc == SEPOL_EEXIST) |
620 | 299 | ERR(fp->handle, "duplicate entry"); |
621 | 299 | ERR(fp->handle, "failed on entry %d of %u", i, nel); |
622 | 299 | goto bad; |
623 | 299 | } |
624 | 8.60k | } |
625 | | |
626 | 6.58k | return 0; |
627 | | |
628 | 389 | bad: |
629 | 389 | avtab_destroy(a); |
630 | 389 | return -1; |
631 | 6.88k | } |