/src/selinux/checkpolicy/module_compiler.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Author : Joshua Brindle <jbrindle@tresys.com> |
2 | | * Karl MacMillan <kmacmillan@tresys.com> |
3 | | * Jason Tang <jtang@tresys.com> |
4 | | * Added support for binary policy modules |
5 | | * |
6 | | * Copyright (C) 2004 - 2005 Tresys Technology, LLC |
7 | | * This program is free software; you can redistribute it and/or modify |
8 | | * it under the terms of the GNU General Public License as published by |
9 | | * the Free Software Foundation, version 2. |
10 | | */ |
11 | | |
12 | | #include <assert.h> |
13 | | #include <stdarg.h> |
14 | | #include <stdlib.h> |
15 | | #include <string.h> |
16 | | |
17 | | #include <sepol/policydb/policydb.h> |
18 | | #include <sepol/policydb/avrule_block.h> |
19 | | #include <sepol/policydb/conditional.h> |
20 | | |
21 | | #include "queue.h" |
22 | | #include "module_compiler.h" |
23 | | |
24 | | typedef struct scope_stack { |
25 | | int type; /* 1 = avrule block, 2 = conditional */ |
26 | | avrule_decl_t *decl; /* if in an avrule block, which |
27 | | * declaration is current */ |
28 | | avrule_t *last_avrule; |
29 | | int in_else; /* if in an avrule block, within ELSE branch */ |
30 | | int require_given; /* 1 if this block had at least one require */ |
31 | | struct scope_stack *parent; |
32 | | } scope_stack_t; |
33 | | |
34 | | extern policydb_t *policydbp; |
35 | | extern queue_t id_queue; |
36 | | extern int yyerror(const char *msg); |
37 | | __attribute__ ((format(printf, 1, 2))) |
38 | | extern void yyerror2(const char *fmt, ...); |
39 | | |
40 | | static int push_stack(int stack_type, ...); |
41 | | static void pop_stack(void); |
42 | | |
43 | | /* keep track of the last item added to the stack */ |
44 | | static scope_stack_t *stack_top = NULL; |
45 | | static avrule_block_t *last_block; |
46 | | static uint32_t next_decl_id = 1; |
47 | | |
48 | | static const char * const flavor_str[SYM_NUM] = { |
49 | | [SYM_COMMONS] = "common", |
50 | | [SYM_CLASSES] = "class", |
51 | | [SYM_ROLES] = "role", |
52 | | [SYM_TYPES] = "type", |
53 | | [SYM_USERS] = "user", |
54 | | [SYM_BOOLS] = "bool", |
55 | | [SYM_LEVELS] = "level", |
56 | | [SYM_CATS] = "cat" |
57 | | }; |
58 | | |
59 | | static void print_error_msg(int ret, uint32_t symbol_type) |
60 | 16 | { |
61 | 16 | switch (ret) { |
62 | 0 | case -3: |
63 | 0 | yyerror("Out of memory!"); |
64 | 0 | break; |
65 | 6 | case -2: |
66 | 6 | yyerror2("Duplicate declaration of %s", flavor_str[symbol_type]); |
67 | 6 | break; |
68 | 10 | case -1: |
69 | 10 | yyerror2("Could not declare %s here", flavor_str[symbol_type]); |
70 | 10 | break; |
71 | 0 | default: |
72 | 0 | yyerror2("Unknown error %d", ret); |
73 | 16 | } |
74 | 16 | } |
75 | | |
76 | | int define_policy(int pass, int module_header_given) |
77 | 12.2k | { |
78 | 12.2k | char *id; |
79 | | |
80 | 12.2k | if (module_header_given) { |
81 | 1 | if (policydbp->policy_type != POLICY_MOD) { |
82 | 1 | yyerror |
83 | 1 | ("Module specification found while not building a policy module."); |
84 | 1 | return -1; |
85 | 1 | } |
86 | | |
87 | 0 | if (pass == 2) { |
88 | 0 | while ((id = queue_remove(id_queue)) != NULL) |
89 | 0 | free(id); |
90 | 0 | } else { |
91 | 0 | id = (char *)queue_remove(id_queue); |
92 | 0 | if (!id) { |
93 | 0 | yyerror("no module name"); |
94 | 0 | return -1; |
95 | 0 | } |
96 | 0 | free(policydbp->name); |
97 | 0 | policydbp->name = id; |
98 | 0 | if ((policydbp->version = |
99 | 0 | queue_remove(id_queue)) == NULL) { |
100 | 0 | yyerror |
101 | 0 | ("Expected a module version but none was found."); |
102 | 0 | return -1; |
103 | 0 | } |
104 | 0 | } |
105 | 12.2k | } else { |
106 | 12.2k | if (policydbp->policy_type == POLICY_MOD) { |
107 | 0 | yyerror |
108 | 0 | ("Building a policy module, but no module specification found."); |
109 | 0 | return -1; |
110 | 0 | } |
111 | 12.2k | } |
112 | | /* the first declaration within the global avrule |
113 | | block will always have an id of 1 */ |
114 | 12.2k | next_decl_id = 2; |
115 | | |
116 | | /* reset the scoping stack */ |
117 | 16.4k | while (stack_top != NULL) { |
118 | 4.20k | pop_stack(); |
119 | 4.20k | } |
120 | 12.2k | if (push_stack(1, policydbp->global, policydbp->global->branch_list) == |
121 | 12.2k | -1) { |
122 | 0 | return -1; |
123 | 0 | } |
124 | 12.2k | last_block = policydbp->global; |
125 | 12.2k | return 0; |
126 | 12.2k | } |
127 | | |
128 | | /* Given the current parse stack, returns 1 if a declaration or require would |
129 | | * be allowed here or 0 if not. For example, declarations and requirements are |
130 | | * not allowed in conditionals, so if there are any conditionals in the |
131 | | * current scope stack then this would return a 0. |
132 | | */ |
133 | | static int is_creation_allowed(void) |
134 | 707k | { |
135 | 707k | if (stack_top->type != 1 || stack_top->in_else) { |
136 | 12 | return 0; |
137 | 12 | } |
138 | 707k | return 1; |
139 | 707k | } |
140 | | |
141 | | /* Attempt to declare or require a symbol within the current scope. |
142 | | * Returns: |
143 | | * 0: Success - Symbol had not been previously created. |
144 | | * 1: Success - Symbol had already been created and caller must free datum. |
145 | | * -1: Failure - Symbol cannot be created here |
146 | | * -2: Failure - Duplicate declaration or type/attribute mismatch |
147 | | * -3: Failure - Out of memory or some other error |
148 | | */ |
149 | | static int create_symbol(uint32_t symbol_type, hashtab_key_t key, hashtab_datum_t datum, |
150 | | uint32_t * dest_value, uint32_t scope) |
151 | 707k | { |
152 | 707k | avrule_decl_t *decl = stack_top->decl; |
153 | 707k | int ret; |
154 | | |
155 | 707k | if (!is_creation_allowed()) { |
156 | 12 | return -1; |
157 | 12 | } |
158 | | |
159 | 707k | ret = symtab_insert(policydbp, symbol_type, key, datum, scope, |
160 | 707k | decl->decl_id, dest_value); |
161 | | |
162 | 707k | if (ret == 1 && dest_value) { |
163 | 626k | hashtab_datum_t s = |
164 | 626k | hashtab_search(policydbp->symtab[symbol_type].table, |
165 | 626k | key); |
166 | 626k | assert(s != NULL); |
167 | | |
168 | 626k | if (symbol_type == SYM_LEVELS) { |
169 | 30.0k | *dest_value = ((level_datum_t *)s)->level->sens; |
170 | 596k | } else { |
171 | 596k | *dest_value = ((symtab_datum_t *)s)->value; |
172 | 596k | } |
173 | 626k | } else if (ret == -2) { |
174 | 27 | return -2; |
175 | 81.2k | } else if (ret < 0) { |
176 | 0 | return -3; |
177 | 0 | } |
178 | | |
179 | 707k | return ret; |
180 | 707k | } |
181 | | |
182 | | /* Attempt to declare a symbol within the current declaration. If |
183 | | * currently within a non-conditional and in a non-else branch then |
184 | | * insert the symbol, return 0 on success if symbol was undeclared. |
185 | | * For roles and users, it is legal to have multiple declarations; as |
186 | | * such return 1 to indicate that caller must free() the datum because |
187 | | * it was not added. If symbols may not be declared here return -1. |
188 | | * For duplicate declarations return -2. For all else, including out |
189 | | * of memory, return -3. Note that dest_value and datum_value might |
190 | | * not be restricted pointers. */ |
191 | | int declare_symbol(uint32_t symbol_type, |
192 | | hashtab_key_t key, hashtab_datum_t datum, |
193 | | uint32_t * dest_value, const uint32_t * datum_value) |
194 | 257k | { |
195 | 257k | avrule_decl_t *decl = stack_top->decl; |
196 | 257k | int ret = create_symbol(symbol_type, key, datum, dest_value, SCOPE_DECL); |
197 | | |
198 | 257k | if (ret < 0) { |
199 | 32 | return ret; |
200 | 32 | } |
201 | | |
202 | 257k | if (ebitmap_set_bit(decl->declared.scope + symbol_type, |
203 | 257k | *datum_value - 1, 1)) { |
204 | 0 | return -3; |
205 | 0 | } |
206 | | |
207 | 257k | return ret; |
208 | 257k | } |
209 | | |
210 | | static int role_implicit_bounds(hashtab_t roles_tab, |
211 | | char *role_id, role_datum_t *role) |
212 | 194k | { |
213 | 194k | role_datum_t *bounds; |
214 | 194k | char *bounds_id, *delim; |
215 | | |
216 | 194k | delim = strrchr(role_id, '.'); |
217 | 194k | if (!delim) |
218 | 194k | return 0; /* no implicit boundary */ |
219 | | |
220 | 231 | bounds_id = strdup(role_id); |
221 | 231 | if (!bounds_id) { |
222 | 0 | yyerror("out of memory"); |
223 | 0 | return -1; |
224 | 0 | } |
225 | 231 | bounds_id[(size_t)(delim - role_id)] = '\0'; |
226 | | |
227 | 231 | bounds = hashtab_search(roles_tab, bounds_id); |
228 | 231 | if (!bounds) { |
229 | 3 | yyerror2("role %s doesn't exist, is implicit bounds of %s", |
230 | 3 | bounds_id, role_id); |
231 | 3 | free(bounds_id); |
232 | 3 | return -1; |
233 | 3 | } |
234 | | |
235 | 228 | if (!role->bounds) |
236 | 228 | role->bounds = bounds->s.value; |
237 | 0 | else if (role->bounds != bounds->s.value) { |
238 | 0 | yyerror2("role %s has inconsistent bounds %s/%s", |
239 | 0 | role_id, bounds_id, |
240 | 0 | policydbp->p_role_val_to_name[role->bounds - 1]); |
241 | 0 | free(bounds_id); |
242 | 0 | return -1; |
243 | 0 | } |
244 | 228 | free(bounds_id); |
245 | | |
246 | 228 | return 0; |
247 | 228 | } |
248 | | |
249 | | static int create_role(uint32_t scope, unsigned char isattr, role_datum_t **role, char **key) |
250 | 432k | { |
251 | 432k | char *id = queue_remove(id_queue); |
252 | 432k | role_datum_t *datum = NULL; |
253 | 432k | int ret; |
254 | 432k | uint32_t value; |
255 | | |
256 | 432k | *role = NULL; |
257 | 432k | *key = NULL; |
258 | 432k | isattr = isattr ? ROLE_ATTRIB : ROLE_ROLE; |
259 | | |
260 | 432k | if (id == NULL) { |
261 | 1 | yyerror("no role name"); |
262 | 1 | return -1; |
263 | 1 | } |
264 | | |
265 | 432k | datum = malloc(sizeof(*datum)); |
266 | 432k | if (datum == NULL) { |
267 | 0 | yyerror("Out of memory!"); |
268 | 0 | free(id); |
269 | 0 | return -1; |
270 | 0 | } |
271 | | |
272 | 432k | role_datum_init(datum); |
273 | 432k | datum->flavor = isattr; |
274 | | |
275 | 432k | if (scope == SCOPE_DECL) { |
276 | 233k | ret = declare_symbol(SYM_ROLES, id, datum, &value, &value); |
277 | 233k | } else { |
278 | 199k | ret = require_symbol(SYM_ROLES, id, datum, &value, &value); |
279 | 199k | } |
280 | | |
281 | 432k | if (ret == 0) { |
282 | 26.2k | datum->s.value = value; |
283 | 26.2k | *role = datum; |
284 | 26.2k | *key = strdup(id); |
285 | 26.2k | if (*key == NULL) { |
286 | 0 | yyerror("Out of memory!"); |
287 | 0 | return -1; |
288 | 0 | } |
289 | 406k | } else if (ret == 1) { |
290 | 406k | *role = hashtab_search(policydbp->symtab[SYM_ROLES].table, id); |
291 | 406k | if (*role && (isattr != (*role)->flavor)) { |
292 | 2 | yyerror2("Identifier %s used as both an attribute and a role", |
293 | 2 | id); |
294 | 2 | *role = NULL; |
295 | 2 | free(id); |
296 | 2 | role_datum_destroy(datum); |
297 | 2 | free(datum); |
298 | 2 | return -1; |
299 | 2 | } |
300 | 406k | datum->s.value = value; |
301 | 406k | *role = datum; |
302 | 406k | *key = id; |
303 | 406k | } else { |
304 | 4 | print_error_msg(ret, SYM_ROLES); |
305 | 4 | free(id); |
306 | 4 | role_datum_destroy(datum); |
307 | 4 | free(datum); |
308 | 4 | } |
309 | | |
310 | 432k | return ret; |
311 | 432k | } |
312 | | |
313 | | role_datum_t *declare_role(unsigned char isattr) |
314 | 233k | { |
315 | 233k | char *key = NULL; |
316 | 233k | role_datum_t *role = NULL; |
317 | 233k | role_datum_t *dest_role = NULL; |
318 | 233k | hashtab_t roles_tab; |
319 | 233k | int ret, ret2; |
320 | | |
321 | 233k | ret = create_role(SCOPE_DECL, isattr, &role, &key); |
322 | 233k | if (ret < 0) { |
323 | 4 | return NULL; |
324 | 4 | } |
325 | | |
326 | | /* create a new role_datum_t for this decl, if necessary */ |
327 | 233k | assert(stack_top->type == 1); |
328 | | |
329 | 233k | if (stack_top->parent == NULL) { |
330 | | /* in parent, so use global symbol table */ |
331 | 17.3k | roles_tab = policydbp->p_roles.table; |
332 | 215k | } else { |
333 | 215k | roles_tab = stack_top->decl->p_roles.table; |
334 | 215k | } |
335 | | |
336 | 233k | dest_role = hashtab_search(roles_tab, key); |
337 | 233k | if (dest_role == NULL) { |
338 | 194k | if (ret == 0) { |
339 | 6.13k | dest_role = malloc(sizeof(*dest_role)); |
340 | 6.13k | if (dest_role == NULL) { |
341 | 0 | yyerror("Out of memory!"); |
342 | 0 | free(key); |
343 | 0 | return NULL; |
344 | 0 | } |
345 | 6.13k | role_datum_init(dest_role); |
346 | 6.13k | dest_role->s.value = role->s.value; |
347 | 6.13k | dest_role->flavor = role->flavor; |
348 | 188k | } else { |
349 | 188k | dest_role = role; |
350 | 188k | } |
351 | 194k | ret2 = role_implicit_bounds(roles_tab, key, dest_role); |
352 | 194k | if (ret2 != 0) { |
353 | 3 | free(key); |
354 | 3 | role_datum_destroy(dest_role); |
355 | 3 | free(dest_role); |
356 | 3 | return NULL; |
357 | 3 | } |
358 | 194k | ret2 = hashtab_insert(roles_tab, key, dest_role); |
359 | 194k | if (ret2 != 0) { |
360 | 0 | yyerror("Out of memory!"); |
361 | 0 | free(key); |
362 | 0 | role_datum_destroy(dest_role); |
363 | 0 | free(dest_role); |
364 | 0 | return NULL; |
365 | 0 | } |
366 | 194k | } else { |
367 | 38.7k | free(key); |
368 | 38.7k | if (ret == 1) { |
369 | 27.3k | role_datum_destroy(role); |
370 | 27.3k | free(role); |
371 | 27.3k | } |
372 | 38.7k | } |
373 | | |
374 | 233k | if (ret == 0) { |
375 | 17.4k | ret2 = ebitmap_set_bit(&dest_role->dominates, dest_role->s.value - 1, 1); |
376 | 17.4k | if (ret2 != 0) { |
377 | 0 | yyerror("out of memory"); |
378 | 0 | return NULL; |
379 | 0 | } |
380 | 17.4k | } |
381 | | |
382 | 233k | return dest_role; |
383 | 233k | } |
384 | | |
385 | | static int create_type(uint32_t scope, unsigned char isattr, type_datum_t **type) |
386 | 67.4k | { |
387 | 67.4k | char *id; |
388 | 67.4k | type_datum_t *datum; |
389 | 67.4k | int ret; |
390 | 67.4k | uint32_t value = 0; |
391 | | |
392 | 67.4k | *type = NULL; |
393 | 67.4k | isattr = isattr ? TYPE_ATTRIB : TYPE_TYPE; |
394 | | |
395 | 67.4k | id = (char *)queue_remove(id_queue); |
396 | 67.4k | if (!id) { |
397 | 1 | yyerror("no type/attribute name?"); |
398 | 1 | return -1; |
399 | 1 | } |
400 | 67.4k | if (strcmp(id, "self") == 0) { |
401 | 5 | yyerror("\"self\" is a reserved type name."); |
402 | 5 | free(id); |
403 | 5 | return -1; |
404 | 5 | } |
405 | | |
406 | 67.4k | datum = malloc(sizeof(*datum)); |
407 | 67.4k | if (!datum) { |
408 | 0 | yyerror("Out of memory!"); |
409 | 0 | free(id); |
410 | 0 | return -1; |
411 | 0 | } |
412 | 67.4k | type_datum_init(datum); |
413 | 67.4k | datum->primary = 1; |
414 | 67.4k | datum->flavor = isattr; |
415 | | |
416 | 67.4k | if (scope == SCOPE_DECL) { |
417 | 1.47k | ret = declare_symbol(SYM_TYPES, id, datum, &value, &value); |
418 | 65.9k | } else { |
419 | 65.9k | ret = require_symbol(SYM_TYPES, id, datum, &value, &value); |
420 | 65.9k | } |
421 | | |
422 | 67.4k | if (ret == 0) { |
423 | 19.2k | datum->s.value = value; |
424 | 19.2k | *type = datum; |
425 | 48.2k | } else if (ret == 1) { |
426 | 48.2k | type_datum_destroy(datum); |
427 | 48.2k | free(datum); |
428 | 48.2k | *type = hashtab_search(policydbp->symtab[SYM_TYPES].table, id); |
429 | 48.2k | if (*type && (isattr != (*type)->flavor)) { |
430 | 4 | yyerror2("Identifier %s used as both an attribute and a type", |
431 | 4 | id); |
432 | 4 | *type = NULL; |
433 | 4 | free(id); |
434 | 4 | return -1; |
435 | 4 | } |
436 | 48.1k | free(id); |
437 | 48.1k | } else { |
438 | 6 | print_error_msg(ret, SYM_TYPES); |
439 | 6 | free(id); |
440 | 6 | type_datum_destroy(datum); |
441 | 6 | free(datum); |
442 | 6 | } |
443 | | |
444 | 67.4k | return ret; |
445 | 67.4k | } |
446 | | |
447 | | type_datum_t *declare_type(unsigned char primary, unsigned char isattr) |
448 | 1.47k | { |
449 | 1.47k | type_datum_t *type = NULL; |
450 | 1.47k | int ret = create_type(SCOPE_DECL, isattr, &type); |
451 | | |
452 | 1.47k | if (ret == 0) { |
453 | 1.43k | type->primary = primary; |
454 | 1.43k | } |
455 | | |
456 | 1.47k | return type; |
457 | 1.47k | } |
458 | | |
459 | | static int user_implicit_bounds(hashtab_t users_tab, |
460 | | char *user_id, user_datum_t *user) |
461 | 2.66k | { |
462 | 2.66k | user_datum_t *bounds; |
463 | 2.66k | char *bounds_id, *delim; |
464 | | |
465 | 2.66k | delim = strrchr(user_id, '.'); |
466 | 2.66k | if (!delim) |
467 | 2.45k | return 0; /* no implicit boundary */ |
468 | | |
469 | 209 | bounds_id = strdup(user_id); |
470 | 209 | if (!bounds_id) { |
471 | 0 | yyerror("out of memory"); |
472 | 0 | return -1; |
473 | 0 | } |
474 | 209 | bounds_id[(size_t)(delim - user_id)] = '\0'; |
475 | | |
476 | 209 | bounds = hashtab_search(users_tab, bounds_id); |
477 | 209 | if (!bounds) { |
478 | 2 | yyerror2("user %s doesn't exist, is implicit bounds of %s", |
479 | 2 | bounds_id, user_id); |
480 | 2 | free(bounds_id); |
481 | 2 | return -1; |
482 | 2 | } |
483 | | |
484 | 207 | if (!user->bounds) |
485 | 207 | user->bounds = bounds->s.value; |
486 | 0 | else if (user->bounds != bounds->s.value) { |
487 | 0 | yyerror2("user %s has inconsistent bounds %s/%s", |
488 | 0 | user_id, bounds_id, |
489 | 0 | policydbp->p_role_val_to_name[user->bounds - 1]); |
490 | 0 | free(bounds_id); |
491 | 0 | return -1; |
492 | 0 | } |
493 | 207 | free(bounds_id); |
494 | | |
495 | 207 | return 0; |
496 | 207 | } |
497 | | |
498 | | static int create_user(uint32_t scope, user_datum_t **user, char **key) |
499 | 12.9k | { |
500 | 12.9k | char *id = queue_remove(id_queue); |
501 | 12.9k | user_datum_t *datum = NULL; |
502 | 12.9k | int ret; |
503 | 12.9k | uint32_t value; |
504 | | |
505 | 12.9k | *user = NULL; |
506 | 12.9k | *key = NULL; |
507 | | |
508 | 12.9k | if (id == NULL) { |
509 | 1 | yyerror("no user name"); |
510 | 1 | return -1; |
511 | 1 | } |
512 | | |
513 | 12.9k | datum = malloc(sizeof(*datum)); |
514 | 12.9k | if (datum == NULL) { |
515 | 0 | yyerror("Out of memory!"); |
516 | 0 | free(id); |
517 | 0 | return -1; |
518 | 0 | } |
519 | | |
520 | 12.9k | user_datum_init(datum); |
521 | | |
522 | 12.9k | if (scope == SCOPE_DECL) { |
523 | 7.88k | ret = declare_symbol(SYM_USERS, id, datum, &value, &value); |
524 | 7.88k | } else { |
525 | 5.04k | ret = require_symbol(SYM_USERS, id, datum, &value, &value); |
526 | 5.04k | } |
527 | | |
528 | 12.9k | if (ret == 0) { |
529 | 7.58k | datum->s.value = value; |
530 | 7.58k | *user = datum; |
531 | 7.58k | *key = strdup(id); |
532 | 7.58k | if (*key == NULL) { |
533 | 0 | yyerror("Out of memory!"); |
534 | 0 | return -1; |
535 | 0 | } |
536 | 7.58k | } else if (ret == 1) { |
537 | 5.34k | datum->s.value = value; |
538 | 5.34k | *user = datum; |
539 | 5.34k | *key = id; |
540 | 5.34k | } else { |
541 | 2 | print_error_msg(ret, SYM_USERS); |
542 | 2 | free(id); |
543 | 2 | user_datum_destroy(datum); |
544 | 2 | free(datum); |
545 | 2 | } |
546 | | |
547 | 12.9k | return ret; |
548 | 12.9k | } |
549 | | |
550 | | user_datum_t *declare_user(void) |
551 | 7.88k | { |
552 | 7.88k | char *key = NULL; |
553 | 7.88k | user_datum_t *user = NULL; |
554 | 7.88k | user_datum_t *dest_user = NULL; |
555 | 7.88k | hashtab_t users_tab; |
556 | 7.88k | int ret, ret2; |
557 | | |
558 | 7.88k | ret = create_user(SCOPE_DECL, &user, &key); |
559 | 7.88k | if (ret < 0) { |
560 | 1 | return NULL; |
561 | 1 | } |
562 | | |
563 | | /* create a new user_datum_t for this decl, if necessary */ |
564 | 7.87k | assert(stack_top->type == 1); |
565 | | |
566 | 7.87k | if (stack_top->parent == NULL) { |
567 | | /* in parent, so use global symbol table */ |
568 | 4.97k | users_tab = policydbp->p_users.table; |
569 | 4.97k | } else { |
570 | 2.90k | users_tab = stack_top->decl->p_users.table; |
571 | 2.90k | } |
572 | | |
573 | 7.87k | dest_user = hashtab_search(users_tab, key); |
574 | 7.87k | if (dest_user == NULL) { |
575 | 2.66k | if (ret == 0) { |
576 | 441 | dest_user = malloc(sizeof(*dest_user)); |
577 | 441 | if (dest_user == NULL) { |
578 | 0 | yyerror("Out of memory!"); |
579 | 0 | free(key); |
580 | 0 | return NULL; |
581 | 0 | } |
582 | 441 | user_datum_init(dest_user); |
583 | 441 | dest_user->s.value = user->s.value; |
584 | 2.22k | } else { |
585 | 2.22k | dest_user = user; |
586 | 2.22k | } |
587 | 2.66k | ret2 = user_implicit_bounds(users_tab, key, dest_user); |
588 | 2.66k | if (ret2 != 0) { |
589 | 2 | free(key); |
590 | 2 | user_datum_destroy(dest_user); |
591 | 2 | free(dest_user); |
592 | 2 | return NULL; |
593 | 2 | } |
594 | 2.66k | ret2 = hashtab_insert(users_tab, key, dest_user); |
595 | 2.66k | if (ret2 != 0) { |
596 | 0 | yyerror("Out of memory!"); |
597 | 0 | free(key); |
598 | 0 | user_datum_destroy(dest_user); |
599 | 0 | free(dest_user); |
600 | 0 | return NULL; |
601 | 0 | } |
602 | 5.21k | } else { |
603 | 5.21k | free(key); |
604 | 5.21k | if (ret == 1) { |
605 | 1.62k | user_datum_destroy(user); |
606 | 1.62k | free(user); |
607 | 1.62k | } |
608 | 5.21k | } |
609 | | |
610 | 7.87k | return dest_user; |
611 | 7.87k | } |
612 | | |
613 | | /* Return a type_datum_t for the local avrule_decl with the given ID. |
614 | | * If it does not exist, create one with the same value as 'value'. |
615 | | * This function assumes that the ID is within scope. c.f., |
616 | | * is_id_in_scope(). |
617 | | * |
618 | | * NOTE: this function usurps ownership of id afterwards. The caller |
619 | | * shall not reference it nor free() it afterwards. |
620 | | */ |
621 | | type_datum_t *get_local_type(char *id, uint32_t value, unsigned char isattr) |
622 | 1.40k | { |
623 | 1.40k | type_datum_t *dest_typdatum; |
624 | 1.40k | hashtab_t types_tab; |
625 | 1.40k | assert(stack_top->type == 1); |
626 | 1.40k | if (stack_top->parent == NULL) { |
627 | | /* in global, so use global symbol table */ |
628 | 727 | types_tab = policydbp->p_types.table; |
629 | 727 | } else { |
630 | 674 | types_tab = stack_top->decl->p_types.table; |
631 | 674 | } |
632 | 1.40k | dest_typdatum = hashtab_search(types_tab, id); |
633 | 1.40k | if (!dest_typdatum) { |
634 | 242 | dest_typdatum = (type_datum_t *) malloc(sizeof(type_datum_t)); |
635 | 242 | if (dest_typdatum == NULL) { |
636 | 0 | free(id); |
637 | 0 | return NULL; |
638 | 0 | } |
639 | 242 | type_datum_init(dest_typdatum); |
640 | 242 | dest_typdatum->s.value = value; |
641 | 242 | dest_typdatum->flavor = isattr ? TYPE_ATTRIB : TYPE_TYPE; |
642 | 242 | dest_typdatum->primary = 1; |
643 | 242 | if (hashtab_insert(types_tab, id, dest_typdatum)) { |
644 | 0 | free(id); |
645 | 0 | type_datum_destroy(dest_typdatum); |
646 | 0 | free(dest_typdatum); |
647 | 0 | return NULL; |
648 | 0 | } |
649 | | |
650 | 1.15k | } else { |
651 | 1.15k | free(id); |
652 | 1.15k | if (dest_typdatum->flavor != isattr ? TYPE_ATTRIB : TYPE_TYPE) { |
653 | 0 | return NULL; |
654 | 0 | } |
655 | 1.15k | } |
656 | 1.40k | return dest_typdatum; |
657 | 1.40k | } |
658 | | |
659 | | /* Return a role_datum_t for the local avrule_decl with the given ID. |
660 | | * If it does not exist, create one with the same value as 'value'. |
661 | | * This function assumes that the ID is within scope. c.f., |
662 | | * is_id_in_scope(). |
663 | | * |
664 | | * NOTE: this function usurps ownership of id afterwards. The caller |
665 | | * shall not reference it nor free() it afterwards. |
666 | | */ |
667 | | role_datum_t *get_local_role(char *id, uint32_t value, unsigned char isattr) |
668 | 12.8k | { |
669 | 12.8k | role_datum_t *dest_roledatum; |
670 | 12.8k | hashtab_t roles_tab; |
671 | | |
672 | 12.8k | assert(stack_top->type == 1); |
673 | | |
674 | 12.8k | if (stack_top->parent == NULL) { |
675 | | /* in global, so use global symbol table */ |
676 | 1.10k | roles_tab = policydbp->p_roles.table; |
677 | 11.7k | } else { |
678 | 11.7k | roles_tab = stack_top->decl->p_roles.table; |
679 | 11.7k | } |
680 | | |
681 | 12.8k | dest_roledatum = hashtab_search(roles_tab, id); |
682 | 12.8k | if (!dest_roledatum) { |
683 | 8.10k | dest_roledatum = (role_datum_t *)malloc(sizeof(role_datum_t)); |
684 | 8.10k | if (dest_roledatum == NULL) { |
685 | 0 | free(id); |
686 | 0 | return NULL; |
687 | 0 | } |
688 | | |
689 | 8.10k | role_datum_init(dest_roledatum); |
690 | 8.10k | dest_roledatum->s.value = value; |
691 | 8.10k | dest_roledatum->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE; |
692 | | |
693 | 8.10k | if (hashtab_insert(roles_tab, id, dest_roledatum)) { |
694 | 0 | free(id); |
695 | 0 | role_datum_destroy(dest_roledatum); |
696 | 0 | free(dest_roledatum); |
697 | 0 | return NULL; |
698 | 0 | } |
699 | 8.10k | } else { |
700 | 4.75k | free(id); |
701 | 4.75k | if (dest_roledatum->flavor != isattr ? ROLE_ATTRIB : ROLE_ROLE) |
702 | 0 | return NULL; |
703 | 4.75k | } |
704 | | |
705 | 12.8k | return dest_roledatum; |
706 | 12.8k | } |
707 | | |
708 | | /* Attempt to require a symbol within the current scope. If currently |
709 | | * within an optional (and not its else branch), add the symbol to the |
710 | | * required list. Return 0 on success, 1 if caller needs to free() |
711 | | * datum. If symbols may not be declared here return -1. For duplicate |
712 | | * declarations return -2. For all else, including out of memory, |
713 | | * return -3.. Note that dest_value and datum_value might not be |
714 | | * restricted pointers. |
715 | | */ |
716 | | int require_symbol(uint32_t symbol_type, |
717 | | hashtab_key_t key, hashtab_datum_t datum, |
718 | | uint32_t * dest_value, uint32_t * datum_value) |
719 | 450k | { |
720 | 450k | avrule_decl_t *decl = stack_top->decl; |
721 | 450k | int ret = create_symbol(symbol_type, key, datum, dest_value, SCOPE_REQ); |
722 | | |
723 | 450k | if (ret < 0) { |
724 | 7 | return ret; |
725 | 7 | } |
726 | | |
727 | 450k | if (ebitmap_set_bit(decl->required.scope + symbol_type, |
728 | 450k | *datum_value - 1, 1)) { |
729 | 0 | return -3; |
730 | 0 | } |
731 | | |
732 | 450k | stack_top->require_given = 1; |
733 | 450k | return ret; |
734 | 450k | } |
735 | | |
736 | | int add_perm_to_class(uint32_t perm_value, uint32_t class_value) |
737 | 16.0k | { |
738 | 16.0k | avrule_decl_t *decl = stack_top->decl; |
739 | 16.0k | scope_index_t *scope; |
740 | | |
741 | 16.0k | assert(perm_value >= 1); |
742 | 16.0k | assert(class_value >= 1); |
743 | 16.0k | scope = &decl->required; |
744 | 16.0k | if (class_value > scope->class_perms_len) { |
745 | 9.16k | uint32_t i; |
746 | 9.16k | ebitmap_t *new_map = realloc(scope->class_perms_map, |
747 | 9.16k | class_value * sizeof(*new_map)); |
748 | 9.16k | if (new_map == NULL) { |
749 | 0 | return -1; |
750 | 0 | } |
751 | 9.16k | scope->class_perms_map = new_map; |
752 | 19.1k | for (i = scope->class_perms_len; i < class_value; i++) { |
753 | 9.93k | ebitmap_init(scope->class_perms_map + i); |
754 | 9.93k | } |
755 | 9.16k | scope->class_perms_len = class_value; |
756 | 9.16k | } |
757 | 16.0k | if (ebitmap_set_bit(scope->class_perms_map + class_value - 1, |
758 | 16.0k | perm_value - 1, 1)) { |
759 | 0 | return -1; |
760 | 0 | } |
761 | 16.0k | return 0; |
762 | 16.0k | } |
763 | | |
764 | | static int perm_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p |
765 | | __attribute__ ((unused))) |
766 | 0 | { |
767 | 0 | if (key) |
768 | 0 | free(key); |
769 | 0 | free(datum); |
770 | 0 | return 0; |
771 | 0 | } |
772 | | |
773 | | static void class_datum_destroy(class_datum_t * cladatum) |
774 | 3.65k | { |
775 | 3.65k | if (cladatum != NULL) { |
776 | 3.65k | hashtab_map(cladatum->permissions.table, perm_destroy, NULL); |
777 | 3.65k | hashtab_destroy(cladatum->permissions.table); |
778 | 3.65k | free(cladatum); |
779 | 3.65k | } |
780 | 3.65k | } |
781 | | |
782 | | int require_class(int pass) |
783 | 6.82k | { |
784 | 6.82k | char *class_id = queue_remove(id_queue); |
785 | 6.82k | char *perm_id = NULL; |
786 | 6.82k | class_datum_t *datum = NULL; |
787 | 6.82k | perm_datum_t *perm = NULL; |
788 | 6.82k | int ret; |
789 | | |
790 | 6.82k | if (pass == 2) { |
791 | 3.15k | free(class_id); |
792 | 6.49k | while ((perm_id = queue_remove(id_queue)) != NULL) |
793 | 3.34k | free(perm_id); |
794 | 3.15k | return 0; |
795 | 3.15k | } |
796 | | |
797 | | /* first add the class if it is not already there */ |
798 | 3.67k | if (class_id == NULL) { |
799 | 1 | yyerror("no class name for class definition?"); |
800 | 1 | return -1; |
801 | 1 | } |
802 | | |
803 | 3.67k | if ((datum = calloc(1, sizeof(*datum))) == NULL || |
804 | 3.67k | symtab_init(&datum->permissions, PERM_SYMTAB_SIZE)) { |
805 | 0 | yyerror("Out of memory!"); |
806 | 0 | class_datum_destroy(datum); |
807 | 0 | return -1; |
808 | 0 | } |
809 | 3.67k | ret = |
810 | 3.67k | require_symbol(SYM_CLASSES, class_id, datum, &datum->s.value, |
811 | 3.67k | &datum->s.value); |
812 | 3.67k | if (ret < 0) { |
813 | 1 | print_error_msg(ret, SYM_CLASSES); |
814 | 1 | free(class_id); |
815 | 1 | class_datum_destroy(datum); |
816 | 1 | return -1; |
817 | 1 | } |
818 | | |
819 | 3.66k | if (ret == 0) { |
820 | | /* a new class was added; reindex everything */ |
821 | 20 | if (policydb_index_classes(policydbp)) { |
822 | 0 | yyerror("Out of memory!"); |
823 | 0 | return -1; |
824 | 0 | } |
825 | 3.64k | } else { |
826 | 3.64k | class_datum_destroy(datum); |
827 | 3.64k | datum = hashtab_search(policydbp->p_classes.table, class_id); |
828 | 3.64k | assert(datum); /* the class datum should have existed */ |
829 | 3.64k | free(class_id); |
830 | 3.64k | } |
831 | | |
832 | | /* now add each of the permissions to this class's requirements */ |
833 | 7.69k | while ((perm_id = queue_remove(id_queue)) != NULL) { |
834 | 4.04k | int allocated = 0; |
835 | | |
836 | | /* Is the permission already in the table? */ |
837 | 4.04k | perm = hashtab_search(datum->permissions.table, perm_id); |
838 | 4.04k | if (!perm && datum->comdatum) |
839 | 0 | perm = |
840 | 0 | hashtab_search(datum->comdatum->permissions.table, |
841 | 0 | perm_id); |
842 | 4.04k | if (perm) { |
843 | | /* Yes, drop the name. */ |
844 | 4.02k | free(perm_id); |
845 | 4.02k | } else { |
846 | | /* No - allocate and insert an entry for it. */ |
847 | 18 | if (policydbp->policy_type == POLICY_BASE) { |
848 | 18 | yyerror2 |
849 | 18 | ("Base policy - require of permission %s without prior declaration.", |
850 | 18 | perm_id); |
851 | 18 | free(perm_id); |
852 | 18 | return -1; |
853 | 18 | } |
854 | 0 | if (datum->permissions.nprim >= PERM_SYMTAB_SIZE) { |
855 | 0 | yyerror2("Class %s would have too many permissions " |
856 | 0 | "to fit in an access vector with permission %s", |
857 | 0 | policydbp->p_class_val_to_name[datum->s.value - 1], |
858 | 0 | perm_id); |
859 | 0 | free(perm_id); |
860 | 0 | return -1; |
861 | 0 | } |
862 | 0 | allocated = 1; |
863 | 0 | if ((perm = malloc(sizeof(*perm))) == NULL) { |
864 | 0 | yyerror("Out of memory!"); |
865 | 0 | free(perm_id); |
866 | 0 | return -1; |
867 | 0 | } |
868 | 0 | memset(perm, 0, sizeof(*perm)); |
869 | 0 | ret = |
870 | 0 | hashtab_insert(datum->permissions.table, perm_id, |
871 | 0 | perm); |
872 | 0 | if (ret) { |
873 | 0 | yyerror("Out of memory!"); |
874 | 0 | free(perm_id); |
875 | 0 | free(perm); |
876 | 0 | return -1; |
877 | 0 | } |
878 | 0 | perm->s.value = datum->permissions.nprim + 1; |
879 | 0 | } |
880 | | |
881 | 4.02k | if (add_perm_to_class(perm->s.value, datum->s.value) == -1) { |
882 | 0 | yyerror("Out of memory!"); |
883 | 0 | return -1; |
884 | 0 | } |
885 | | |
886 | | /* Update number of primitives if we allocated one. */ |
887 | 4.02k | if (allocated) |
888 | 0 | datum->permissions.nprim++; |
889 | 4.02k | } |
890 | 3.65k | return 0; |
891 | 3.66k | } |
892 | | |
893 | | static int require_role_or_attribute(int pass, unsigned char isattr) |
894 | 389k | { |
895 | 389k | char *key = NULL; |
896 | 389k | role_datum_t *role = NULL; |
897 | 389k | int ret; |
898 | | |
899 | 389k | if (pass == 2) { |
900 | 189k | free(queue_remove(id_queue)); |
901 | 189k | return 0; |
902 | 189k | } |
903 | | |
904 | 199k | ret = create_role(SCOPE_REQ, isattr, &role, &key); |
905 | 199k | if (ret < 0) { |
906 | 3 | return -1; |
907 | 3 | } |
908 | | |
909 | 199k | free(key); |
910 | | |
911 | 199k | if (ret == 0) { |
912 | 8.71k | ret = ebitmap_set_bit(&role->dominates, role->s.value - 1, 1); |
913 | 8.71k | if (ret != 0) { |
914 | 0 | yyerror("Out of memory"); |
915 | 0 | return -1; |
916 | 0 | } |
917 | 190k | } else { |
918 | 190k | role_datum_destroy(role); |
919 | 190k | free(role); |
920 | 190k | } |
921 | | |
922 | 199k | return 0; |
923 | 199k | } |
924 | | |
925 | | int require_role(int pass) |
926 | 300k | { |
927 | 300k | return require_role_or_attribute(pass, 0); |
928 | 300k | } |
929 | | |
930 | | int require_attribute_role(int pass) |
931 | 89.5k | { |
932 | 89.5k | return require_role_or_attribute(pass, 1); |
933 | 89.5k | } |
934 | | |
935 | | static int require_type_or_attribute(int pass, unsigned char isattr) |
936 | 123k | { |
937 | 123k | type_datum_t *type = NULL; |
938 | 123k | int ret; |
939 | | |
940 | 123k | if (pass == 2) { |
941 | 57.1k | free(queue_remove(id_queue)); |
942 | 57.1k | return 0; |
943 | 57.1k | } |
944 | | |
945 | 65.9k | ret = create_type(SCOPE_REQ, isattr, &type); |
946 | | |
947 | 65.9k | if (ret < 0) { |
948 | 6 | return -1; |
949 | 6 | } |
950 | | |
951 | 65.9k | return 0; |
952 | 65.9k | } |
953 | | |
954 | | int require_type(int pass) |
955 | 78.4k | { |
956 | 78.4k | return require_type_or_attribute(pass, 0); |
957 | 78.4k | } |
958 | | |
959 | | int require_attribute(int pass) |
960 | 44.6k | { |
961 | 44.6k | return require_type_or_attribute(pass, 1); |
962 | 44.6k | } |
963 | | |
964 | | int require_user(int pass) |
965 | 10.8k | { |
966 | 10.8k | char *key = NULL; |
967 | 10.8k | user_datum_t *user = NULL; |
968 | 10.8k | int ret; |
969 | | |
970 | 10.8k | if (pass == 1) { |
971 | 5.85k | free(queue_remove(id_queue)); |
972 | 5.85k | return 0; |
973 | 5.85k | } |
974 | | |
975 | 5.04k | ret = create_user(SCOPE_REQ, &user, &key); |
976 | 5.04k | if (ret < 0) { |
977 | 2 | return -1; |
978 | 2 | } |
979 | | |
980 | 5.04k | free(key); |
981 | | |
982 | 5.04k | if (ret == 1) { |
983 | 1.49k | user_datum_destroy(user); |
984 | 1.49k | free(user); |
985 | 1.49k | } |
986 | | |
987 | 5.04k | return 0; |
988 | 5.04k | } |
989 | | |
990 | | static int require_bool_tunable(int pass, int is_tunable) |
991 | 280k | { |
992 | 280k | char *id = queue_remove(id_queue); |
993 | 280k | cond_bool_datum_t *booldatum = NULL; |
994 | 280k | int retval; |
995 | 280k | if (pass == 2) { |
996 | 138k | free(id); |
997 | 138k | return 0; |
998 | 138k | } |
999 | 141k | if (id == NULL) { |
1000 | 1 | yyerror("no boolean name"); |
1001 | 1 | return -1; |
1002 | 1 | } |
1003 | 141k | if ((booldatum = calloc(1, sizeof(*booldatum))) == NULL) { |
1004 | 0 | cond_destroy_bool(id, booldatum, NULL); |
1005 | 0 | yyerror("Out of memory!"); |
1006 | 0 | return -1; |
1007 | 0 | } |
1008 | 141k | if (is_tunable) |
1009 | 659 | booldatum->flags |= COND_BOOL_FLAGS_TUNABLE; |
1010 | 141k | retval = |
1011 | 141k | require_symbol(SYM_BOOLS, id, booldatum, |
1012 | 141k | &booldatum->s.value, &booldatum->s.value); |
1013 | 141k | if (retval != 0) { |
1014 | 131k | cond_destroy_bool(id, booldatum, NULL); |
1015 | 131k | if (retval < 0) { |
1016 | 1 | print_error_msg(retval, SYM_BOOLS); |
1017 | 1 | return -1; |
1018 | 1 | } |
1019 | 131k | } |
1020 | | |
1021 | 141k | return 0; |
1022 | 141k | } |
1023 | | |
1024 | | int require_bool(int pass) |
1025 | 279k | { |
1026 | 279k | return require_bool_tunable(pass, 0); |
1027 | 279k | } |
1028 | | |
1029 | | int require_tunable(int pass) |
1030 | 907 | { |
1031 | 907 | return require_bool_tunable(pass, 1); |
1032 | 907 | } |
1033 | | |
1034 | | int require_sens(int pass) |
1035 | 62.0k | { |
1036 | 62.0k | char *id = queue_remove(id_queue); |
1037 | 62.0k | level_datum_t *level = NULL; |
1038 | 62.0k | int retval; |
1039 | 62.0k | if (pass == 2) { |
1040 | 30.2k | free(id); |
1041 | 30.2k | return 0; |
1042 | 30.2k | } |
1043 | 31.7k | if (!id) { |
1044 | 1 | yyerror("no sensitivity name"); |
1045 | 1 | return -1; |
1046 | 1 | } |
1047 | 31.7k | level = malloc(sizeof(level_datum_t)); |
1048 | 31.7k | if (!level) { |
1049 | 0 | free(id); |
1050 | 0 | yyerror("Out of memory!"); |
1051 | 0 | return -1; |
1052 | 0 | } |
1053 | 31.7k | level_datum_init(level); |
1054 | 31.7k | level->level = malloc(sizeof(mls_level_t)); |
1055 | 31.7k | if (!level->level) { |
1056 | 0 | free(id); |
1057 | 0 | level_datum_destroy(level); |
1058 | 0 | free(level); |
1059 | 0 | yyerror("Out of memory!"); |
1060 | 0 | return -1; |
1061 | 0 | } |
1062 | 31.7k | mls_level_init(level->level); |
1063 | 31.7k | retval = require_symbol(SYM_LEVELS, id, level, |
1064 | 31.7k | &level->level->sens, &level->level->sens); |
1065 | 31.7k | if (retval != 0) { |
1066 | 30.0k | free(id); |
1067 | 30.0k | mls_level_destroy(level->level); |
1068 | 30.0k | free(level->level); |
1069 | 30.0k | level_datum_destroy(level); |
1070 | 30.0k | free(level); |
1071 | 30.0k | if (retval < 0) { |
1072 | 1 | print_error_msg(retval, SYM_LEVELS); |
1073 | 1 | return -1; |
1074 | 1 | } |
1075 | 30.0k | } |
1076 | | |
1077 | 31.7k | return 0; |
1078 | 31.7k | } |
1079 | | |
1080 | | int require_cat(int pass) |
1081 | 3.91k | { |
1082 | 3.91k | char *id = queue_remove(id_queue); |
1083 | 3.91k | cat_datum_t *cat = NULL; |
1084 | 3.91k | int retval; |
1085 | 3.91k | if (pass == 2) { |
1086 | 1.47k | free(id); |
1087 | 1.47k | return 0; |
1088 | 1.47k | } |
1089 | 2.44k | if (!id) { |
1090 | 1 | yyerror("no category name"); |
1091 | 1 | return -1; |
1092 | 1 | } |
1093 | 2.44k | cat = malloc(sizeof(cat_datum_t)); |
1094 | 2.44k | if (!cat) { |
1095 | 0 | free(id); |
1096 | 0 | yyerror("Out of memory!"); |
1097 | 0 | return -1; |
1098 | 0 | } |
1099 | 2.44k | cat_datum_init(cat); |
1100 | | |
1101 | 2.44k | retval = require_symbol(SYM_CATS, id, cat, |
1102 | 2.44k | &cat->s.value, &cat->s.value); |
1103 | 2.44k | if (retval != 0) { |
1104 | 1.33k | free(id); |
1105 | 1.33k | cat_datum_destroy(cat); |
1106 | 1.33k | free(cat); |
1107 | 1.33k | if (retval < 0) { |
1108 | 1 | print_error_msg(retval, SYM_CATS); |
1109 | 1 | return -1; |
1110 | 1 | } |
1111 | 1.33k | } |
1112 | | |
1113 | 2.44k | return 0; |
1114 | 2.44k | } |
1115 | | |
1116 | | static int is_scope_in_stack(const scope_datum_t * scope, const scope_stack_t * stack) |
1117 | 930k | { |
1118 | 930k | uint32_t i; |
1119 | 930k | if (stack == NULL) { |
1120 | 295 | return 0; /* no matching scope found */ |
1121 | 295 | } |
1122 | 930k | if (stack->type == 1) { |
1123 | 930k | const avrule_decl_t *decl = stack->decl; |
1124 | 6.30M | for (i = 0; i < scope->decl_ids_len; i++) { |
1125 | 5.72M | if (scope->decl_ids[i] == decl->decl_id) { |
1126 | 345k | return 1; |
1127 | 345k | } |
1128 | 5.72M | } |
1129 | 930k | } else { |
1130 | | /* note that conditionals can't declare or require |
1131 | | * symbols, so skip this level */ |
1132 | 0 | } |
1133 | | |
1134 | | /* not within scope of this stack, so try its parent */ |
1135 | 584k | return is_scope_in_stack(scope, stack->parent); |
1136 | 930k | } |
1137 | | |
1138 | | int is_id_in_scope(uint32_t symbol_type, const_hashtab_key_t id) |
1139 | 349k | { |
1140 | 349k | const scope_datum_t *scope = |
1141 | 349k | (scope_datum_t *) hashtab_search(policydbp->scope[symbol_type]. |
1142 | 349k | table, id); |
1143 | 349k | if (scope == NULL) { |
1144 | 3.05k | return 1; /* id is not known, so return success */ |
1145 | 3.05k | } |
1146 | 346k | return is_scope_in_stack(scope, stack_top); |
1147 | 349k | } |
1148 | | |
1149 | | static int is_perm_in_scope_index(uint32_t perm_value, uint32_t class_value, |
1150 | | const scope_index_t * scope) |
1151 | 3.75k | { |
1152 | 3.75k | if (class_value > scope->class_perms_len) { |
1153 | 3.10k | return 1; |
1154 | 3.10k | } |
1155 | 649 | if (ebitmap_get_bit(scope->class_perms_map + class_value - 1, |
1156 | 649 | perm_value - 1)) { |
1157 | 583 | return 1; |
1158 | 583 | } |
1159 | 66 | return 0; |
1160 | 649 | } |
1161 | | |
1162 | | static int is_perm_in_stack(uint32_t perm_value, uint32_t class_value, |
1163 | | const scope_stack_t * stack) |
1164 | 3.68k | { |
1165 | 3.68k | if (stack == NULL) { |
1166 | 0 | return 0; /* no matching scope found */ |
1167 | 0 | } |
1168 | 3.68k | if (stack->type == 1) { |
1169 | 3.68k | avrule_decl_t *decl = stack->decl; |
1170 | 3.68k | if (is_perm_in_scope_index |
1171 | 3.68k | (perm_value, class_value, &decl->required) |
1172 | 3.68k | || is_perm_in_scope_index(perm_value, class_value, |
1173 | 3.68k | &decl->declared)) { |
1174 | 3.68k | return 1; |
1175 | 3.68k | } |
1176 | 3.68k | } else { |
1177 | | /* note that conditionals can't declare or require |
1178 | | * symbols, so skip this level */ |
1179 | 0 | } |
1180 | | |
1181 | | /* not within scope of this stack, so try its parent */ |
1182 | 0 | return is_perm_in_stack(perm_value, class_value, stack->parent); |
1183 | 3.68k | } |
1184 | | |
1185 | | int is_perm_in_scope(const_hashtab_key_t perm_id, const_hashtab_key_t class_id) |
1186 | 3.68k | { |
1187 | 3.68k | const class_datum_t *cladatum = |
1188 | 3.68k | (class_datum_t *) hashtab_search(policydbp->p_classes.table, |
1189 | 3.68k | class_id); |
1190 | 3.68k | const perm_datum_t *perdatum; |
1191 | 3.68k | if (cladatum == NULL) { |
1192 | 0 | return 1; |
1193 | 0 | } |
1194 | 3.68k | perdatum = (perm_datum_t *) hashtab_search(cladatum->permissions.table, |
1195 | 3.68k | perm_id); |
1196 | 3.68k | if (perdatum == NULL) { |
1197 | 0 | return 1; |
1198 | 0 | } |
1199 | 3.68k | return is_perm_in_stack(perdatum->s.value, cladatum->s.value, |
1200 | 3.68k | stack_top); |
1201 | 3.68k | } |
1202 | | |
1203 | | cond_list_t *get_current_cond_list(cond_list_t * cond) |
1204 | 10.2k | { |
1205 | | /* FIX ME: do something different here if in a nested |
1206 | | * conditional? */ |
1207 | 10.2k | avrule_decl_t *decl = stack_top->decl; |
1208 | 10.2k | return get_decl_cond_list(policydbp, decl, cond); |
1209 | 10.2k | } |
1210 | | |
1211 | | /* Append the new conditional node to the existing ones. During |
1212 | | * expansion the list will be reversed -- i.e., the last AV rule will |
1213 | | * be the first one listed in the policy. This matches the behavior |
1214 | | * of the upstream compiler. */ |
1215 | | void append_cond_list(cond_list_t * cond) |
1216 | 5.11k | { |
1217 | 5.11k | cond_list_t *old_cond = get_current_cond_list(cond); |
1218 | 5.11k | avrule_t *tmp; |
1219 | 5.11k | assert(old_cond != NULL); /* probably out of memory */ |
1220 | 5.11k | if (old_cond->avtrue_list == NULL) { |
1221 | 3.35k | old_cond->avtrue_list = cond->avtrue_list; |
1222 | 3.35k | } else { |
1223 | 8.70k | for (tmp = old_cond->avtrue_list; tmp->next != NULL; |
1224 | 6.94k | tmp = tmp->next) ; |
1225 | 1.76k | tmp->next = cond->avtrue_list; |
1226 | 1.76k | } |
1227 | 5.11k | if (old_cond->avfalse_list == NULL) { |
1228 | 2.62k | old_cond->avfalse_list = cond->avfalse_list; |
1229 | 2.62k | } else { |
1230 | 216k | for (tmp = old_cond->avfalse_list; tmp->next != NULL; |
1231 | 213k | tmp = tmp->next) ; |
1232 | 2.49k | tmp->next = cond->avfalse_list; |
1233 | 2.49k | } |
1234 | | |
1235 | 5.11k | old_cond->flags |= cond->flags; |
1236 | 5.11k | } |
1237 | | |
1238 | | void append_avrule(avrule_t * avrule) |
1239 | 15.8k | { |
1240 | 15.8k | avrule_decl_t *decl = stack_top->decl; |
1241 | | |
1242 | | /* currently avrules follow a completely different code path |
1243 | | * for handling avrules and compute types |
1244 | | * (define_cond_avrule_te_avtab, define_cond_compute_type); |
1245 | | * therefore there ought never be a conditional on top of the |
1246 | | * scope stack */ |
1247 | 15.8k | assert(stack_top->type == 1); |
1248 | | |
1249 | 15.8k | if (stack_top->last_avrule == NULL) { |
1250 | 1.28k | decl->avrules = avrule; |
1251 | 14.5k | } else { |
1252 | 14.5k | stack_top->last_avrule->next = avrule; |
1253 | 14.5k | } |
1254 | 15.8k | stack_top->last_avrule = avrule; |
1255 | 15.8k | } |
1256 | | |
1257 | | /* this doesn't actually append, but really prepends it */ |
1258 | | void append_role_trans(role_trans_rule_t * role_tr_rules) |
1259 | 1.27k | { |
1260 | 1.27k | avrule_decl_t *decl = stack_top->decl; |
1261 | | |
1262 | | /* role transitions are not allowed within conditionals */ |
1263 | 1.27k | assert(stack_top->type == 1); |
1264 | | |
1265 | 1.27k | role_tr_rules->next = decl->role_tr_rules; |
1266 | 1.27k | decl->role_tr_rules = role_tr_rules; |
1267 | 1.27k | } |
1268 | | |
1269 | | /* this doesn't actually append, but really prepends it */ |
1270 | | void append_role_allow(role_allow_rule_t * role_allow_rules) |
1271 | 363 | { |
1272 | 363 | avrule_decl_t *decl = stack_top->decl; |
1273 | | |
1274 | | /* role allows are not allowed within conditionals */ |
1275 | 363 | assert(stack_top->type == 1); |
1276 | | |
1277 | 363 | role_allow_rules->next = decl->role_allow_rules; |
1278 | 363 | decl->role_allow_rules = role_allow_rules; |
1279 | 363 | } |
1280 | | |
1281 | | /* this doesn't actually append, but really prepends it */ |
1282 | | void append_filename_trans(filename_trans_rule_t * filename_trans_rules) |
1283 | 3.70k | { |
1284 | 3.70k | avrule_decl_t *decl = stack_top->decl; |
1285 | | |
1286 | | /* filename transitions are not allowed within conditionals */ |
1287 | 3.70k | assert(stack_top->type == 1); |
1288 | | |
1289 | 3.70k | filename_trans_rules->next = decl->filename_trans_rules; |
1290 | 3.70k | decl->filename_trans_rules = filename_trans_rules; |
1291 | 3.70k | } |
1292 | | |
1293 | | /* this doesn't actually append, but really prepends it */ |
1294 | | void append_range_trans(range_trans_rule_t * range_tr_rules) |
1295 | 0 | { |
1296 | 0 | avrule_decl_t *decl = stack_top->decl; |
1297 | | |
1298 | | /* range transitions are not allowed within conditionals */ |
1299 | 0 | assert(stack_top->type == 1); |
1300 | | |
1301 | 0 | range_tr_rules->next = decl->range_tr_rules; |
1302 | 0 | decl->range_tr_rules = range_tr_rules; |
1303 | 0 | } |
1304 | | |
1305 | | int begin_optional(int pass) |
1306 | 190k | { |
1307 | 190k | avrule_block_t *block = NULL; |
1308 | 190k | avrule_decl_t *decl; |
1309 | 190k | if (pass == 1) { |
1310 | | /* allocate a new avrule block for this optional block */ |
1311 | 172k | if ((block = avrule_block_create()) == NULL || |
1312 | 172k | (decl = avrule_decl_create(next_decl_id)) == NULL) { |
1313 | 0 | goto cleanup; |
1314 | 0 | } |
1315 | 172k | block->flags |= AVRULE_OPTIONAL; |
1316 | 172k | block->branch_list = decl; |
1317 | 172k | last_block->next = block; |
1318 | 172k | } else { |
1319 | | /* select the next block from the chain built during pass 1 */ |
1320 | 18.3k | block = last_block->next; |
1321 | 18.3k | assert(block != NULL && |
1322 | 18.3k | block->branch_list != NULL && |
1323 | 18.3k | block->branch_list->decl_id == next_decl_id); |
1324 | 18.3k | decl = block->branch_list; |
1325 | 18.3k | } |
1326 | 190k | if (push_stack(1, block, decl) == -1) { |
1327 | 0 | goto cleanup; |
1328 | 0 | } |
1329 | 190k | stack_top->last_avrule = NULL; |
1330 | 190k | last_block = block; |
1331 | 190k | next_decl_id++; |
1332 | 190k | return 0; |
1333 | 0 | cleanup: |
1334 | 0 | yyerror("Out of memory!"); |
1335 | 0 | avrule_block_destroy(block); |
1336 | 0 | return -1; |
1337 | 190k | } |
1338 | | |
1339 | | int end_optional(int pass __attribute__ ((unused))) |
1340 | 157k | { |
1341 | | /* once nested conditionals are allowed, do the stack unfolding here */ |
1342 | 157k | pop_stack(); |
1343 | 157k | return 0; |
1344 | 157k | } |
1345 | | |
1346 | | int begin_optional_else(int pass) |
1347 | 1.38k | { |
1348 | 1.38k | avrule_decl_t *decl; |
1349 | 1.38k | assert(stack_top->type == 1 && stack_top->in_else == 0); |
1350 | 1.38k | if (pass == 1) { |
1351 | | /* allocate a new declaration and add it to the |
1352 | | * current chain */ |
1353 | 1.17k | if ((decl = avrule_decl_create(next_decl_id)) == NULL) { |
1354 | 0 | yyerror("Out of memory!"); |
1355 | 0 | return -1; |
1356 | 0 | } |
1357 | 1.17k | stack_top->decl->next = decl; |
1358 | 1.17k | } else { |
1359 | | /* pick the (hopefully last) declaration of this |
1360 | | avrule block, built from pass 1 */ |
1361 | 208 | decl = stack_top->decl->next; |
1362 | 208 | assert(decl != NULL && |
1363 | 208 | decl->next == NULL && decl->decl_id == next_decl_id); |
1364 | 208 | } |
1365 | 1.38k | stack_top->in_else = 1; |
1366 | 1.38k | stack_top->decl = decl; |
1367 | 1.38k | stack_top->last_avrule = NULL; |
1368 | 1.38k | stack_top->require_given = 0; |
1369 | 1.38k | next_decl_id++; |
1370 | 1.38k | return 0; |
1371 | 1.38k | } |
1372 | | |
1373 | | static int copy_requirements(avrule_decl_t * dest, const scope_stack_t * stack) |
1374 | 294k | { |
1375 | 294k | uint32_t i; |
1376 | 294k | if (stack == NULL) { |
1377 | 16.3k | return 0; |
1378 | 16.3k | } |
1379 | 278k | if (stack->type == 1) { |
1380 | 278k | const scope_index_t *src_scope = &stack->decl->required; |
1381 | 278k | scope_index_t *dest_scope = &dest->required; |
1382 | 2.50M | for (i = 0; i < SYM_NUM; i++) { |
1383 | 2.22M | const ebitmap_t *src_bitmap = &src_scope->scope[i]; |
1384 | 2.22M | ebitmap_t *dest_bitmap = &dest_scope->scope[i]; |
1385 | 2.22M | if (ebitmap_union(dest_bitmap, src_bitmap)) { |
1386 | 0 | yyerror("Out of memory!"); |
1387 | 0 | return -1; |
1388 | 0 | } |
1389 | 2.22M | } |
1390 | | /* now copy class permissions */ |
1391 | 278k | if (src_scope->class_perms_len > dest_scope->class_perms_len) { |
1392 | 14.7k | ebitmap_t *new_map = |
1393 | 14.7k | realloc(dest_scope->class_perms_map, |
1394 | 14.7k | src_scope->class_perms_len * |
1395 | 14.7k | sizeof(*new_map)); |
1396 | 14.7k | if (new_map == NULL) { |
1397 | 0 | yyerror("Out of memory!"); |
1398 | 0 | return -1; |
1399 | 0 | } |
1400 | 14.7k | dest_scope->class_perms_map = new_map; |
1401 | 14.7k | for (i = dest_scope->class_perms_len; |
1402 | 30.2k | i < src_scope->class_perms_len; i++) { |
1403 | 15.5k | ebitmap_init(dest_scope->class_perms_map + i); |
1404 | 15.5k | } |
1405 | 14.7k | dest_scope->class_perms_len = |
1406 | 14.7k | src_scope->class_perms_len; |
1407 | 14.7k | } |
1408 | 295k | for (i = 0; i < src_scope->class_perms_len; i++) { |
1409 | 17.1k | const ebitmap_t *src_bitmap = &src_scope->class_perms_map[i]; |
1410 | 17.1k | ebitmap_t *dest_bitmap = |
1411 | 17.1k | &dest_scope->class_perms_map[i]; |
1412 | 17.1k | if (ebitmap_union(dest_bitmap, src_bitmap)) { |
1413 | 0 | yyerror("Out of memory!"); |
1414 | 0 | return -1; |
1415 | 0 | } |
1416 | 17.1k | } |
1417 | 278k | } |
1418 | 278k | return copy_requirements(dest, stack->parent); |
1419 | 278k | } |
1420 | | |
1421 | | /* During pass 1, check that at least one thing was required within |
1422 | | * this block, for those places where a REQUIRED is necessary. During |
1423 | | * pass 2, have this block inherit its parents' requirements. Return |
1424 | | * 0 on success, -1 on failure. */ |
1425 | | int end_avrule_block(int pass) |
1426 | 159k | { |
1427 | 159k | avrule_decl_t *decl = stack_top->decl; |
1428 | 159k | assert(stack_top->type == 1); |
1429 | 159k | if (pass == 2) { |
1430 | | /* this avrule_decl inherits all of its parents' |
1431 | | * requirements */ |
1432 | 16.3k | if (copy_requirements(decl, stack_top->parent) == -1) { |
1433 | 0 | return -1; |
1434 | 0 | } |
1435 | 16.3k | return 0; |
1436 | 16.3k | } |
1437 | 142k | if (!stack_top->in_else && !stack_top->require_given) { |
1438 | 131k | if (policydbp->policy_type == POLICY_BASE |
1439 | 131k | && stack_top->parent != NULL) { |
1440 | | /* if this is base no require should be in the global block */ |
1441 | 131k | return 0; |
1442 | 131k | } else { |
1443 | | /* non-ELSE branches must have at least one thing required */ |
1444 | 0 | yyerror("This block has no require section."); |
1445 | 0 | return -1; |
1446 | 0 | } |
1447 | 131k | } |
1448 | 11.3k | return 0; |
1449 | 142k | } |
1450 | | |
1451 | | /* Push a new scope on to the stack and update the 'last' pointer. |
1452 | | * Return 0 on success, -1 if out * of memory. */ |
1453 | | static int push_stack(int stack_type, ...) |
1454 | 202k | { |
1455 | 202k | scope_stack_t *s = calloc(1, sizeof(*s)); |
1456 | 202k | va_list ap; |
1457 | 202k | if (s == NULL) { |
1458 | 0 | return -1; |
1459 | 0 | } |
1460 | 202k | va_start(ap, stack_type); |
1461 | 202k | switch (s->type = stack_type) { |
1462 | 202k | case 1:{ |
1463 | 202k | va_arg(ap, avrule_block_t *); |
1464 | 202k | s->decl = va_arg(ap, avrule_decl_t *); |
1465 | 202k | break; |
1466 | 0 | } |
1467 | 0 | case 2:{ |
1468 | 0 | va_arg(ap, cond_list_t *); |
1469 | 0 | break; |
1470 | 0 | } |
1471 | 0 | default: |
1472 | | /* invalid stack type given */ |
1473 | 0 | assert(0); |
1474 | 202k | } |
1475 | 202k | va_end(ap); |
1476 | 202k | s->parent = stack_top; |
1477 | 202k | stack_top = s; |
1478 | 202k | return 0; |
1479 | 202k | } |
1480 | | |
1481 | | /* Pop off the most recently added from the stack. Update the 'last' |
1482 | | * pointer. */ |
1483 | | static void pop_stack(void) |
1484 | 202k | { |
1485 | 202k | scope_stack_t *parent; |
1486 | 202k | assert(stack_top != NULL); |
1487 | 202k | parent = stack_top->parent; |
1488 | 202k | free(stack_top); |
1489 | 202k | stack_top = parent; |
1490 | 202k | } |
1491 | | |
1492 | | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
1493 | | void module_compiler_reset(void) |
1494 | 8.15k | { |
1495 | 49.0k | while (stack_top) |
1496 | 40.9k | pop_stack(); |
1497 | | |
1498 | 8.15k | last_block = NULL; |
1499 | 8.15k | next_decl_id = 1; |
1500 | 8.15k | } |
1501 | | #endif |