/src/selinux/checkpolicy/module_compiler.c
Line | Count | Source |
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 | 17 | { |
61 | 17 | switch (ret) { |
62 | 0 | case -3: |
63 | 0 | yyerror("Out of memory!"); |
64 | 0 | break; |
65 | 8 | case -2: |
66 | 8 | yyerror2("Duplicate declaration of %s", flavor_str[symbol_type]); |
67 | 8 | break; |
68 | 9 | case -1: |
69 | 9 | yyerror2("Could not declare %s here", flavor_str[symbol_type]); |
70 | 9 | break; |
71 | 0 | default: |
72 | 0 | yyerror2("Unknown error %d", ret); |
73 | 17 | } |
74 | 17 | } |
75 | | |
76 | | int define_policy(int pass, int module_header_given) |
77 | 10.1k | { |
78 | 10.1k | char *id; |
79 | | |
80 | 10.1k | 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 | 10.1k | } else { |
106 | 10.1k | 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 | 10.1k | } |
112 | | /* the first declaration within the global avrule |
113 | | block will always have an id of 1 */ |
114 | 10.1k | next_decl_id = 2; |
115 | | |
116 | | /* reset the scoping stack */ |
117 | 13.7k | while (stack_top != NULL) { |
118 | 3.62k | pop_stack(); |
119 | 3.62k | } |
120 | 10.1k | if (push_stack(1, policydbp->global, policydbp->global->branch_list) == |
121 | 10.1k | -1) { |
122 | 0 | return -1; |
123 | 0 | } |
124 | 10.1k | last_block = policydbp->global; |
125 | 10.1k | return 0; |
126 | 10.1k | } |
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 | 489k | { |
135 | 489k | if (stack_top->type != 1 || stack_top->in_else) { |
136 | 11 | return 0; |
137 | 11 | } |
138 | 489k | return 1; |
139 | 489k | } |
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 | 489k | { |
152 | 489k | avrule_decl_t *decl = stack_top->decl; |
153 | 489k | int ret; |
154 | | |
155 | 489k | if (!is_creation_allowed()) { |
156 | 11 | return -1; |
157 | 11 | } |
158 | | |
159 | 489k | ret = symtab_insert(policydbp, symbol_type, key, datum, scope, |
160 | 489k | decl->decl_id, dest_value); |
161 | | |
162 | 489k | if (ret == 1 && dest_value) { |
163 | 393k | hashtab_datum_t s = |
164 | 393k | hashtab_search(policydbp->symtab[symbol_type].table, |
165 | 393k | key); |
166 | 393k | assert(s != NULL); |
167 | | |
168 | 393k | if (symbol_type == SYM_LEVELS) { |
169 | 56.5k | *dest_value = ((level_datum_t *)s)->level->sens; |
170 | 337k | } else { |
171 | 337k | *dest_value = ((symtab_datum_t *)s)->value; |
172 | 337k | } |
173 | 393k | } else if (ret == -2) { |
174 | 29 | return -2; |
175 | 95.0k | } else if (ret < 0) { |
176 | 0 | return -3; |
177 | 0 | } |
178 | | |
179 | 488k | return ret; |
180 | 489k | } |
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 | 166k | { |
195 | 166k | avrule_decl_t *decl = stack_top->decl; |
196 | 166k | int ret = create_symbol(symbol_type, key, datum, dest_value, SCOPE_DECL); |
197 | | |
198 | 166k | if (ret < 0) { |
199 | 34 | return ret; |
200 | 34 | } |
201 | | |
202 | 166k | if (ebitmap_set_bit(decl->declared.scope + symbol_type, |
203 | 166k | *datum_value - 1, 1)) { |
204 | 0 | return -3; |
205 | 0 | } |
206 | | |
207 | 166k | return ret; |
208 | 166k | } |
209 | | |
210 | | static int role_implicit_bounds(hashtab_t roles_tab, |
211 | | char *role_id, role_datum_t *role) |
212 | 103k | { |
213 | 103k | role_datum_t *bounds; |
214 | 103k | char *bounds_id, *delim; |
215 | | |
216 | 103k | delim = strrchr(role_id, '.'); |
217 | 103k | if (!delim) |
218 | 103k | return 0; /* no implicit boundary */ |
219 | | |
220 | 739 | bounds_id = strdup(role_id); |
221 | 739 | if (!bounds_id) { |
222 | 0 | yyerror("out of memory"); |
223 | 0 | return -1; |
224 | 0 | } |
225 | 739 | bounds_id[(size_t)(delim - role_id)] = '\0'; |
226 | | |
227 | 739 | bounds = hashtab_search(roles_tab, bounds_id); |
228 | 739 | if (!bounds) { |
229 | 1 | yyerror2("role %s doesn't exist, is implicit bounds of %s", |
230 | 1 | bounds_id, role_id); |
231 | 1 | free(bounds_id); |
232 | 1 | return -1; |
233 | 1 | } |
234 | | |
235 | 738 | if (!role->bounds) |
236 | 738 | 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 | 738 | free(bounds_id); |
245 | | |
246 | 738 | return 0; |
247 | 738 | } |
248 | | |
249 | | static int create_role(uint32_t scope, unsigned char isattr, role_datum_t **role, char **key) |
250 | 268k | { |
251 | 268k | char *id = queue_remove(id_queue); |
252 | 268k | role_datum_t *datum = NULL; |
253 | 268k | int ret; |
254 | 268k | uint32_t value; |
255 | | |
256 | 268k | *role = NULL; |
257 | 268k | *key = NULL; |
258 | 268k | isattr = isattr ? ROLE_ATTRIB : ROLE_ROLE; |
259 | | |
260 | 268k | if (id == NULL) { |
261 | 2 | yyerror("no role name"); |
262 | 2 | return -1; |
263 | 2 | } |
264 | | |
265 | 268k | datum = malloc(sizeof(*datum)); |
266 | 268k | if (datum == NULL) { |
267 | 0 | yyerror("Out of memory!"); |
268 | 0 | free(id); |
269 | 0 | return -1; |
270 | 0 | } |
271 | | |
272 | 268k | role_datum_init(datum); |
273 | 268k | datum->flavor = isattr; |
274 | | |
275 | 268k | if (scope == SCOPE_DECL) { |
276 | 143k | ret = declare_symbol(SYM_ROLES, id, datum, &value, &value); |
277 | 143k | } else { |
278 | 125k | ret = require_symbol(SYM_ROLES, id, datum, &value, &value); |
279 | 125k | } |
280 | | |
281 | 268k | if (ret == 0) { |
282 | 37.4k | datum->s.value = value; |
283 | 37.4k | *role = datum; |
284 | 37.4k | *key = strdup(id); |
285 | 37.4k | if (*key == NULL) { |
286 | 0 | yyerror("Out of memory!"); |
287 | 0 | return -1; |
288 | 0 | } |
289 | 231k | } else if (ret == 1) { |
290 | 231k | *role = hashtab_search(policydbp->symtab[SYM_ROLES].table, id); |
291 | 231k | if (*role && (isattr != (*role)->flavor)) { |
292 | 3 | yyerror2("Identifier %s used as both an attribute and a role", |
293 | 3 | id); |
294 | 3 | *role = NULL; |
295 | 3 | free(id); |
296 | 3 | role_datum_destroy(datum); |
297 | 3 | free(datum); |
298 | 3 | return -1; |
299 | 3 | } |
300 | 231k | datum->s.value = value; |
301 | 231k | *role = datum; |
302 | 231k | *key = id; |
303 | 231k | } 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 | 268k | return ret; |
311 | 268k | } |
312 | | |
313 | | role_datum_t *declare_role(unsigned char isattr) |
314 | 143k | { |
315 | 143k | char *key = NULL; |
316 | 143k | role_datum_t *role = NULL; |
317 | 143k | role_datum_t *dest_role = NULL; |
318 | 143k | hashtab_t roles_tab; |
319 | 143k | int ret, ret2; |
320 | | |
321 | 143k | ret = create_role(SCOPE_DECL, isattr, &role, &key); |
322 | 143k | if (ret < 0) { |
323 | 4 | return NULL; |
324 | 4 | } |
325 | | |
326 | | /* create a new role_datum_t for this decl, if necessary */ |
327 | 143k | assert(stack_top->type == 1); |
328 | | |
329 | 143k | if (stack_top->parent == NULL) { |
330 | | /* in parent, so use global symbol table */ |
331 | 31.9k | roles_tab = policydbp->p_roles.table; |
332 | 111k | } else { |
333 | 111k | roles_tab = stack_top->decl->p_roles.table; |
334 | 111k | } |
335 | | |
336 | 143k | dest_role = hashtab_search(roles_tab, key); |
337 | 143k | if (dest_role == NULL) { |
338 | 103k | if (ret == 0) { |
339 | 6.66k | dest_role = malloc(sizeof(*dest_role)); |
340 | 6.66k | if (dest_role == NULL) { |
341 | 0 | yyerror("Out of memory!"); |
342 | 0 | free(key); |
343 | 0 | return NULL; |
344 | 0 | } |
345 | 6.66k | role_datum_init(dest_role); |
346 | 6.66k | dest_role->s.value = role->s.value; |
347 | 6.66k | dest_role->flavor = role->flavor; |
348 | 97.1k | } else { |
349 | 97.1k | dest_role = role; |
350 | 97.1k | } |
351 | 103k | ret2 = role_implicit_bounds(roles_tab, key, dest_role); |
352 | 103k | if (ret2 != 0) { |
353 | 1 | free(key); |
354 | 1 | role_datum_destroy(dest_role); |
355 | 1 | free(dest_role); |
356 | 1 | return NULL; |
357 | 1 | } |
358 | 103k | ret2 = hashtab_insert(roles_tab, key, dest_role); |
359 | 103k | 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 | 103k | } else { |
367 | 39.5k | free(key); |
368 | 39.5k | if (ret == 1) { |
369 | 17.7k | role_datum_destroy(role); |
370 | 17.7k | free(role); |
371 | 17.7k | } |
372 | 39.5k | } |
373 | | |
374 | 143k | if (ret == 0) { |
375 | 28.3k | ret2 = ebitmap_set_bit(&dest_role->dominates, dest_role->s.value - 1, 1); |
376 | 28.3k | if (ret2 != 0) { |
377 | 0 | yyerror("out of memory"); |
378 | 0 | return NULL; |
379 | 0 | } |
380 | 28.3k | } |
381 | | |
382 | 143k | return dest_role; |
383 | 143k | } |
384 | | |
385 | | static int create_type(uint32_t scope, unsigned char isattr, type_datum_t **type) |
386 | 67.8k | { |
387 | 67.8k | char *id; |
388 | 67.8k | type_datum_t *datum; |
389 | 67.8k | int ret; |
390 | 67.8k | uint32_t value = 0; |
391 | | |
392 | 67.8k | *type = NULL; |
393 | 67.8k | isattr = isattr ? TYPE_ATTRIB : TYPE_TYPE; |
394 | | |
395 | 67.8k | id = (char *)queue_remove(id_queue); |
396 | 67.8k | if (!id) { |
397 | 1 | yyerror("no type/attribute name?"); |
398 | 1 | return -1; |
399 | 1 | } |
400 | 67.8k | if (strcmp(id, "self") == 0) { |
401 | 3 | yyerror("\"self\" is a reserved type name."); |
402 | 3 | free(id); |
403 | 3 | return -1; |
404 | 3 | } |
405 | | |
406 | 67.8k | datum = malloc(sizeof(*datum)); |
407 | 67.8k | if (!datum) { |
408 | 0 | yyerror("Out of memory!"); |
409 | 0 | free(id); |
410 | 0 | return -1; |
411 | 0 | } |
412 | 67.8k | type_datum_init(datum); |
413 | 67.8k | datum->primary = 1; |
414 | 67.8k | datum->flavor = isattr; |
415 | | |
416 | 67.8k | if (scope == SCOPE_DECL) { |
417 | 2.06k | ret = declare_symbol(SYM_TYPES, id, datum, &value, &value); |
418 | 65.7k | } else { |
419 | 65.7k | ret = require_symbol(SYM_TYPES, id, datum, &value, &value); |
420 | 65.7k | } |
421 | | |
422 | 67.8k | if (ret == 0) { |
423 | 22.2k | datum->s.value = value; |
424 | 22.2k | *type = datum; |
425 | 45.5k | } else if (ret == 1) { |
426 | 45.5k | type_datum_destroy(datum); |
427 | 45.5k | free(datum); |
428 | 45.5k | *type = hashtab_search(policydbp->symtab[SYM_TYPES].table, id); |
429 | 45.5k | if (*type && (isattr != (*type)->flavor)) { |
430 | 3 | yyerror2("Identifier %s used as both an attribute and a type", |
431 | 3 | id); |
432 | 3 | *type = NULL; |
433 | 3 | free(id); |
434 | 3 | return -1; |
435 | 3 | } |
436 | 45.5k | free(id); |
437 | 45.5k | } else { |
438 | 8 | print_error_msg(ret, SYM_TYPES); |
439 | 8 | free(id); |
440 | 8 | type_datum_destroy(datum); |
441 | 8 | free(datum); |
442 | 8 | } |
443 | | |
444 | 67.8k | return ret; |
445 | 67.8k | } |
446 | | |
447 | | type_datum_t *declare_type(unsigned char primary, unsigned char isattr) |
448 | 2.06k | { |
449 | 2.06k | type_datum_t *type = NULL; |
450 | 2.06k | int ret = create_type(SCOPE_DECL, isattr, &type); |
451 | | |
452 | 2.06k | if (ret == 0) { |
453 | 2.02k | type->primary = primary; |
454 | 2.02k | } |
455 | | |
456 | 2.06k | return type; |
457 | 2.06k | } |
458 | | |
459 | | static int user_implicit_bounds(hashtab_t users_tab, |
460 | | char *user_id, user_datum_t *user) |
461 | 2.81k | { |
462 | 2.81k | user_datum_t *bounds; |
463 | 2.81k | char *bounds_id, *delim; |
464 | | |
465 | 2.81k | delim = strrchr(user_id, '.'); |
466 | 2.81k | if (!delim) |
467 | 2.55k | return 0; /* no implicit boundary */ |
468 | | |
469 | 261 | bounds_id = strdup(user_id); |
470 | 261 | if (!bounds_id) { |
471 | 0 | yyerror("out of memory"); |
472 | 0 | return -1; |
473 | 0 | } |
474 | 261 | bounds_id[(size_t)(delim - user_id)] = '\0'; |
475 | | |
476 | 261 | bounds = hashtab_search(users_tab, bounds_id); |
477 | 261 | if (!bounds) { |
478 | 1 | yyerror2("user %s doesn't exist, is implicit bounds of %s", |
479 | 1 | bounds_id, user_id); |
480 | 1 | free(bounds_id); |
481 | 1 | return -1; |
482 | 1 | } |
483 | | |
484 | 260 | if (!user->bounds) |
485 | 260 | 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 | 260 | free(bounds_id); |
494 | | |
495 | 260 | return 0; |
496 | 260 | } |
497 | | |
498 | | static int create_user(uint32_t scope, user_datum_t **user, char **key) |
499 | 11.9k | { |
500 | 11.9k | char *id = queue_remove(id_queue); |
501 | 11.9k | user_datum_t *datum = NULL; |
502 | 11.9k | int ret; |
503 | 11.9k | uint32_t value; |
504 | | |
505 | 11.9k | *user = NULL; |
506 | 11.9k | *key = NULL; |
507 | | |
508 | 11.9k | if (id == NULL) { |
509 | 1 | yyerror("no user name"); |
510 | 1 | return -1; |
511 | 1 | } |
512 | | |
513 | 11.9k | datum = malloc(sizeof(*datum)); |
514 | 11.9k | if (datum == NULL) { |
515 | 0 | yyerror("Out of memory!"); |
516 | 0 | free(id); |
517 | 0 | return -1; |
518 | 0 | } |
519 | | |
520 | 11.9k | user_datum_init(datum); |
521 | | |
522 | 11.9k | if (scope == SCOPE_DECL) { |
523 | 7.43k | ret = declare_symbol(SYM_USERS, id, datum, &value, &value); |
524 | 7.43k | } else { |
525 | 4.49k | ret = require_symbol(SYM_USERS, id, datum, &value, &value); |
526 | 4.49k | } |
527 | | |
528 | 11.9k | if (ret == 0) { |
529 | 7.08k | datum->s.value = value; |
530 | 7.08k | *user = datum; |
531 | 7.08k | *key = strdup(id); |
532 | 7.08k | if (*key == NULL) { |
533 | 0 | yyerror("Out of memory!"); |
534 | 0 | return -1; |
535 | 0 | } |
536 | 7.08k | } else if (ret == 1) { |
537 | 4.84k | datum->s.value = value; |
538 | 4.84k | *user = datum; |
539 | 4.84k | *key = id; |
540 | 4.84k | } 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 | 11.9k | return ret; |
548 | 11.9k | } |
549 | | |
550 | | user_datum_t *declare_user(void) |
551 | 7.43k | { |
552 | 7.43k | char *key = NULL; |
553 | 7.43k | user_datum_t *user = NULL; |
554 | 7.43k | user_datum_t *dest_user = NULL; |
555 | 7.43k | hashtab_t users_tab; |
556 | 7.43k | int ret, ret2; |
557 | | |
558 | 7.43k | ret = create_user(SCOPE_DECL, &user, &key); |
559 | 7.43k | if (ret < 0) { |
560 | 1 | return NULL; |
561 | 1 | } |
562 | | |
563 | | /* create a new user_datum_t for this decl, if necessary */ |
564 | 7.43k | assert(stack_top->type == 1); |
565 | | |
566 | 7.43k | if (stack_top->parent == NULL) { |
567 | | /* in parent, so use global symbol table */ |
568 | 3.70k | users_tab = policydbp->p_users.table; |
569 | 3.73k | } else { |
570 | 3.73k | users_tab = stack_top->decl->p_users.table; |
571 | 3.73k | } |
572 | | |
573 | 7.43k | dest_user = hashtab_search(users_tab, key); |
574 | 7.43k | if (dest_user == NULL) { |
575 | 2.81k | if (ret == 0) { |
576 | 906 | dest_user = malloc(sizeof(*dest_user)); |
577 | 906 | if (dest_user == NULL) { |
578 | 0 | yyerror("Out of memory!"); |
579 | 0 | free(key); |
580 | 0 | return NULL; |
581 | 0 | } |
582 | 906 | user_datum_init(dest_user); |
583 | 906 | dest_user->s.value = user->s.value; |
584 | 1.91k | } else { |
585 | 1.91k | dest_user = user; |
586 | 1.91k | } |
587 | 2.81k | ret2 = user_implicit_bounds(users_tab, key, dest_user); |
588 | 2.81k | if (ret2 != 0) { |
589 | 1 | free(key); |
590 | 1 | user_datum_destroy(dest_user); |
591 | 1 | free(dest_user); |
592 | 1 | return NULL; |
593 | 1 | } |
594 | 2.81k | ret2 = hashtab_insert(users_tab, key, dest_user); |
595 | 2.81k | 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 | 4.61k | } else { |
603 | 4.61k | free(key); |
604 | 4.61k | if (ret == 1) { |
605 | 1.67k | user_datum_destroy(user); |
606 | 1.67k | free(user); |
607 | 1.67k | } |
608 | 4.61k | } |
609 | | |
610 | 7.43k | return dest_user; |
611 | 7.43k | } |
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.00k | { |
623 | 1.00k | type_datum_t *dest_typdatum; |
624 | 1.00k | hashtab_t types_tab; |
625 | 1.00k | assert(stack_top->type == 1); |
626 | 1.00k | if (stack_top->parent == NULL) { |
627 | | /* in global, so use global symbol table */ |
628 | 640 | types_tab = policydbp->p_types.table; |
629 | 640 | } else { |
630 | 368 | types_tab = stack_top->decl->p_types.table; |
631 | 368 | } |
632 | 1.00k | dest_typdatum = hashtab_search(types_tab, id); |
633 | 1.00k | if (!dest_typdatum) { |
634 | 150 | dest_typdatum = (type_datum_t *) malloc(sizeof(type_datum_t)); |
635 | 150 | if (dest_typdatum == NULL) { |
636 | 0 | free(id); |
637 | 0 | return NULL; |
638 | 0 | } |
639 | 150 | type_datum_init(dest_typdatum); |
640 | 150 | dest_typdatum->s.value = value; |
641 | 150 | dest_typdatum->flavor = isattr ? TYPE_ATTRIB : TYPE_TYPE; |
642 | 150 | dest_typdatum->primary = 1; |
643 | 150 | 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 | 858 | } else { |
651 | 858 | free(id); |
652 | 858 | if (dest_typdatum->flavor != isattr ? TYPE_ATTRIB : TYPE_TYPE) { |
653 | 0 | return NULL; |
654 | 0 | } |
655 | 858 | } |
656 | 1.00k | return dest_typdatum; |
657 | 1.00k | } |
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 | 10.9k | { |
669 | 10.9k | role_datum_t *dest_roledatum; |
670 | 10.9k | hashtab_t roles_tab; |
671 | | |
672 | 10.9k | assert(stack_top->type == 1); |
673 | | |
674 | 10.9k | if (stack_top->parent == NULL) { |
675 | | /* in global, so use global symbol table */ |
676 | 4.99k | roles_tab = policydbp->p_roles.table; |
677 | 5.94k | } else { |
678 | 5.94k | roles_tab = stack_top->decl->p_roles.table; |
679 | 5.94k | } |
680 | | |
681 | 10.9k | dest_roledatum = hashtab_search(roles_tab, id); |
682 | 10.9k | if (!dest_roledatum) { |
683 | 2.70k | dest_roledatum = (role_datum_t *)malloc(sizeof(role_datum_t)); |
684 | 2.70k | if (dest_roledatum == NULL) { |
685 | 0 | free(id); |
686 | 0 | return NULL; |
687 | 0 | } |
688 | | |
689 | 2.70k | role_datum_init(dest_roledatum); |
690 | 2.70k | dest_roledatum->s.value = value; |
691 | 2.70k | dest_roledatum->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE; |
692 | | |
693 | 2.70k | 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.23k | } else { |
700 | 8.23k | free(id); |
701 | 8.23k | if (dest_roledatum->flavor != isattr ? ROLE_ATTRIB : ROLE_ROLE) |
702 | 0 | return NULL; |
703 | 8.23k | } |
704 | | |
705 | 10.9k | return dest_roledatum; |
706 | 10.9k | } |
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 | 322k | { |
720 | 322k | avrule_decl_t *decl = stack_top->decl; |
721 | 322k | int ret = create_symbol(symbol_type, key, datum, dest_value, SCOPE_REQ); |
722 | | |
723 | 322k | if (ret < 0) { |
724 | 6 | return ret; |
725 | 6 | } |
726 | | |
727 | 322k | if (ebitmap_set_bit(decl->required.scope + symbol_type, |
728 | 322k | *datum_value - 1, 1)) { |
729 | 0 | return -3; |
730 | 0 | } |
731 | | |
732 | 322k | stack_top->require_given = 1; |
733 | 322k | return ret; |
734 | 322k | } |
735 | | |
736 | | int add_perm_to_class(uint32_t perm_value, uint32_t class_value) |
737 | 14.7k | { |
738 | 14.7k | avrule_decl_t *decl = stack_top->decl; |
739 | 14.7k | scope_index_t *scope; |
740 | | |
741 | 14.7k | assert(perm_value >= 1); |
742 | 14.7k | assert(class_value >= 1); |
743 | 14.7k | scope = &decl->required; |
744 | 14.7k | if (class_value > scope->class_perms_len) { |
745 | 8.48k | uint32_t i; |
746 | 8.48k | ebitmap_t *new_map = realloc(scope->class_perms_map, |
747 | 8.48k | class_value * sizeof(*new_map)); |
748 | 8.48k | if (new_map == NULL) { |
749 | 0 | return -1; |
750 | 0 | } |
751 | 8.48k | scope->class_perms_map = new_map; |
752 | 17.8k | for (i = scope->class_perms_len; i < class_value; i++) { |
753 | 9.35k | ebitmap_init(scope->class_perms_map + i); |
754 | 9.35k | } |
755 | 8.48k | scope->class_perms_len = class_value; |
756 | 8.48k | } |
757 | 14.7k | if (ebitmap_set_bit(scope->class_perms_map + class_value - 1, |
758 | 14.7k | perm_value - 1, 1)) { |
759 | 0 | return -1; |
760 | 0 | } |
761 | 14.7k | return 0; |
762 | 14.7k | } |
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.22k | { |
775 | 3.22k | if (cladatum != NULL) { |
776 | 3.22k | hashtab_map(cladatum->permissions.table, perm_destroy, NULL); |
777 | 3.22k | hashtab_destroy(cladatum->permissions.table); |
778 | 3.22k | free(cladatum); |
779 | 3.22k | } |
780 | 3.22k | } |
781 | | |
782 | | int require_class(int pass) |
783 | 3.75k | { |
784 | 3.75k | char *class_id = queue_remove(id_queue); |
785 | 3.75k | char *perm_id = NULL; |
786 | 3.75k | class_datum_t *datum = NULL; |
787 | 3.75k | perm_datum_t *perm = NULL; |
788 | 3.75k | int ret; |
789 | | |
790 | 3.75k | if (pass == 2) { |
791 | 523 | free(class_id); |
792 | 1.08k | while ((perm_id = queue_remove(id_queue)) != NULL) |
793 | 557 | free(perm_id); |
794 | 523 | return 0; |
795 | 523 | } |
796 | | |
797 | | /* first add the class if it is not already there */ |
798 | 3.23k | if (class_id == NULL) { |
799 | 1 | yyerror("no class name for class definition?"); |
800 | 1 | return -1; |
801 | 1 | } |
802 | | |
803 | 3.23k | if ((datum = calloc(1, sizeof(*datum))) == NULL || |
804 | 3.23k | 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.23k | ret = |
810 | 3.23k | require_symbol(SYM_CLASSES, class_id, datum, &datum->s.value, |
811 | 3.23k | &datum->s.value); |
812 | 3.23k | 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.23k | if (ret == 0) { |
820 | | /* a new class was added; reindex everything */ |
821 | 14 | if (policydb_index_classes(policydbp)) { |
822 | 0 | yyerror("Out of memory!"); |
823 | 0 | return -1; |
824 | 0 | } |
825 | 3.22k | } else { |
826 | 3.22k | class_datum_destroy(datum); |
827 | 3.22k | datum = hashtab_search(policydbp->p_classes.table, class_id); |
828 | 3.22k | assert(datum); /* the class datum should have existed */ |
829 | 3.22k | free(class_id); |
830 | 3.22k | } |
831 | | |
832 | | /* now add each of the permissions to this class's requirements */ |
833 | 6.64k | while ((perm_id = queue_remove(id_queue)) != NULL) { |
834 | 3.42k | int allocated = 0; |
835 | | |
836 | | /* Is the permission already in the table? */ |
837 | 3.42k | perm = hashtab_search(datum->permissions.table, perm_id); |
838 | 3.42k | if (!perm && datum->comdatum) |
839 | 0 | perm = |
840 | 0 | hashtab_search(datum->comdatum->permissions.table, |
841 | 0 | perm_id); |
842 | 3.42k | if (perm) { |
843 | | /* Yes, drop the name. */ |
844 | 3.41k | free(perm_id); |
845 | 3.41k | } else { |
846 | | /* No - allocate and insert an entry for it. */ |
847 | 11 | if (policydbp->policy_type == POLICY_BASE) { |
848 | 11 | yyerror2 |
849 | 11 | ("Base policy - require of permission %s without prior declaration.", |
850 | 11 | perm_id); |
851 | 11 | free(perm_id); |
852 | 11 | return -1; |
853 | 11 | } |
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 | 3.41k | 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 | 3.41k | if (allocated) |
888 | 0 | datum->permissions.nprim++; |
889 | 3.41k | } |
890 | 3.22k | return 0; |
891 | 3.23k | } |
892 | | |
893 | | static int require_role_or_attribute(int pass, unsigned char isattr) |
894 | 224k | { |
895 | 224k | char *key = NULL; |
896 | 224k | role_datum_t *role = NULL; |
897 | 224k | int ret; |
898 | | |
899 | 224k | if (pass == 2) { |
900 | 98.8k | free(queue_remove(id_queue)); |
901 | 98.8k | return 0; |
902 | 98.8k | } |
903 | | |
904 | 125k | ret = create_role(SCOPE_REQ, isattr, &role, &key); |
905 | 125k | if (ret < 0) { |
906 | 5 | return -1; |
907 | 5 | } |
908 | | |
909 | 125k | free(key); |
910 | | |
911 | 125k | if (ret == 0) { |
912 | 9.10k | ret = ebitmap_set_bit(&role->dominates, role->s.value - 1, 1); |
913 | 9.10k | if (ret != 0) { |
914 | 0 | yyerror("Out of memory"); |
915 | 0 | return -1; |
916 | 0 | } |
917 | 116k | } else { |
918 | 116k | role_datum_destroy(role); |
919 | 116k | free(role); |
920 | 116k | } |
921 | | |
922 | 125k | return 0; |
923 | 125k | } |
924 | | |
925 | | int require_role(int pass) |
926 | 97.7k | { |
927 | 97.7k | return require_role_or_attribute(pass, 0); |
928 | 97.7k | } |
929 | | |
930 | | int require_attribute_role(int pass) |
931 | 126k | { |
932 | 126k | return require_role_or_attribute(pass, 1); |
933 | 126k | } |
934 | | |
935 | | static int require_type_or_attribute(int pass, unsigned char isattr) |
936 | 119k | { |
937 | 119k | type_datum_t *type = NULL; |
938 | 119k | int ret; |
939 | | |
940 | 119k | if (pass == 2) { |
941 | 53.8k | free(queue_remove(id_queue)); |
942 | 53.8k | return 0; |
943 | 53.8k | } |
944 | | |
945 | 65.7k | ret = create_type(SCOPE_REQ, isattr, &type); |
946 | | |
947 | 65.7k | if (ret < 0) { |
948 | 4 | return -1; |
949 | 4 | } |
950 | | |
951 | 65.7k | return 0; |
952 | 65.7k | } |
953 | | |
954 | | int require_type(int pass) |
955 | 62.3k | { |
956 | 62.3k | return require_type_or_attribute(pass, 0); |
957 | 62.3k | } |
958 | | |
959 | | int require_attribute(int pass) |
960 | 57.2k | { |
961 | 57.2k | return require_type_or_attribute(pass, 1); |
962 | 57.2k | } |
963 | | |
964 | | int require_user(int pass) |
965 | 10.2k | { |
966 | 10.2k | char *key = NULL; |
967 | 10.2k | user_datum_t *user = NULL; |
968 | 10.2k | int ret; |
969 | | |
970 | 10.2k | if (pass == 1) { |
971 | 5.72k | free(queue_remove(id_queue)); |
972 | 5.72k | return 0; |
973 | 5.72k | } |
974 | | |
975 | 4.49k | ret = create_user(SCOPE_REQ, &user, &key); |
976 | 4.49k | if (ret < 0) { |
977 | 2 | return -1; |
978 | 2 | } |
979 | | |
980 | 4.49k | free(key); |
981 | | |
982 | 4.49k | if (ret == 1) { |
983 | 1.26k | user_datum_destroy(user); |
984 | 1.26k | free(user); |
985 | 1.26k | } |
986 | | |
987 | 4.49k | return 0; |
988 | 4.49k | } |
989 | | |
990 | | static int require_bool_tunable(int pass, int is_tunable) |
991 | 116k | { |
992 | 116k | char *id = queue_remove(id_queue); |
993 | 116k | cond_bool_datum_t *booldatum = NULL; |
994 | 116k | int retval; |
995 | 116k | if (pass == 2) { |
996 | 56.4k | free(id); |
997 | 56.4k | return 0; |
998 | 56.4k | } |
999 | 60.3k | if (id == NULL) { |
1000 | 1 | yyerror("no boolean name"); |
1001 | 1 | return -1; |
1002 | 1 | } |
1003 | 60.3k | 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 | 60.3k | if (is_tunable) |
1009 | 409 | booldatum->flags |= COND_BOOL_FLAGS_TUNABLE; |
1010 | 60.3k | retval = |
1011 | 60.3k | require_symbol(SYM_BOOLS, id, booldatum, |
1012 | 60.3k | &booldatum->s.value, &booldatum->s.value); |
1013 | 60.3k | if (retval != 0) { |
1014 | 51.0k | cond_destroy_bool(id, booldatum, NULL); |
1015 | 51.0k | if (retval < 0) { |
1016 | 1 | print_error_msg(retval, SYM_BOOLS); |
1017 | 1 | return -1; |
1018 | 1 | } |
1019 | 51.0k | } |
1020 | | |
1021 | 60.3k | return 0; |
1022 | 60.3k | } |
1023 | | |
1024 | | int require_bool(int pass) |
1025 | 116k | { |
1026 | 116k | return require_bool_tunable(pass, 0); |
1027 | 116k | } |
1028 | | |
1029 | | int require_tunable(int pass) |
1030 | 557 | { |
1031 | 557 | return require_bool_tunable(pass, 1); |
1032 | 557 | } |
1033 | | |
1034 | | int require_sens(int pass) |
1035 | 101k | { |
1036 | 101k | char *id = queue_remove(id_queue); |
1037 | 101k | level_datum_t *level = NULL; |
1038 | 101k | int retval; |
1039 | 101k | if (pass == 2) { |
1040 | 41.5k | free(id); |
1041 | 41.5k | return 0; |
1042 | 41.5k | } |
1043 | 60.0k | if (!id) { |
1044 | 1 | yyerror("no sensitivity name"); |
1045 | 1 | return -1; |
1046 | 1 | } |
1047 | 60.0k | level = malloc(sizeof(level_datum_t)); |
1048 | 60.0k | if (!level) { |
1049 | 0 | free(id); |
1050 | 0 | yyerror("Out of memory!"); |
1051 | 0 | return -1; |
1052 | 0 | } |
1053 | 60.0k | level_datum_init(level); |
1054 | 60.0k | level->level = malloc(sizeof(mls_level_t)); |
1055 | 60.0k | 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 | 60.0k | mls_level_init(level->level); |
1063 | 60.0k | retval = require_symbol(SYM_LEVELS, id, level, |
1064 | 60.0k | &level->level->sens, &level->level->sens); |
1065 | 60.0k | if (retval != 0) { |
1066 | 56.5k | free(id); |
1067 | 56.5k | mls_level_destroy(level->level); |
1068 | 56.5k | free(level->level); |
1069 | 56.5k | level_datum_destroy(level); |
1070 | 56.5k | free(level); |
1071 | 56.5k | if (retval < 0) { |
1072 | 0 | print_error_msg(retval, SYM_LEVELS); |
1073 | 0 | return -1; |
1074 | 0 | } |
1075 | 56.5k | } |
1076 | | |
1077 | 60.0k | return 0; |
1078 | 60.0k | } |
1079 | | |
1080 | | int require_cat(int pass) |
1081 | 4.31k | { |
1082 | 4.31k | char *id = queue_remove(id_queue); |
1083 | 4.31k | cat_datum_t *cat = NULL; |
1084 | 4.31k | int retval; |
1085 | 4.31k | if (pass == 2) { |
1086 | 1.49k | free(id); |
1087 | 1.49k | return 0; |
1088 | 1.49k | } |
1089 | 2.82k | if (!id) { |
1090 | 1 | yyerror("no category name"); |
1091 | 1 | return -1; |
1092 | 1 | } |
1093 | 2.82k | cat = malloc(sizeof(cat_datum_t)); |
1094 | 2.82k | if (!cat) { |
1095 | 0 | free(id); |
1096 | 0 | yyerror("Out of memory!"); |
1097 | 0 | return -1; |
1098 | 0 | } |
1099 | 2.82k | cat_datum_init(cat); |
1100 | | |
1101 | 2.82k | retval = require_symbol(SYM_CATS, id, cat, |
1102 | 2.82k | &cat->s.value, &cat->s.value); |
1103 | 2.82k | if (retval != 0) { |
1104 | 1.32k | free(id); |
1105 | 1.32k | cat_datum_destroy(cat); |
1106 | 1.32k | free(cat); |
1107 | 1.32k | if (retval < 0) { |
1108 | 1 | print_error_msg(retval, SYM_CATS); |
1109 | 1 | return -1; |
1110 | 1 | } |
1111 | 1.32k | } |
1112 | | |
1113 | 2.82k | return 0; |
1114 | 2.82k | } |
1115 | | |
1116 | | static int is_scope_in_stack(const scope_datum_t * scope, const scope_stack_t * stack) |
1117 | 701k | { |
1118 | 701k | uint32_t i; |
1119 | 701k | if (stack == NULL) { |
1120 | 442 | return 0; /* no matching scope found */ |
1121 | 442 | } |
1122 | 700k | if (stack->type == 1) { |
1123 | 700k | const avrule_decl_t *decl = stack->decl; |
1124 | 4.78M | for (i = 0; i < scope->decl_ids_len; i++) { |
1125 | 4.41M | if (scope->decl_ids[i] == decl->decl_id) { |
1126 | 326k | return 1; |
1127 | 326k | } |
1128 | 4.41M | } |
1129 | 700k | } 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 | 374k | return is_scope_in_stack(scope, stack->parent); |
1136 | 700k | } |
1137 | | |
1138 | | int is_id_in_scope(uint32_t symbol_type, const_hashtab_key_t id) |
1139 | 328k | { |
1140 | 328k | const scope_datum_t *scope = |
1141 | 328k | (scope_datum_t *) hashtab_search(policydbp->scope[symbol_type]. |
1142 | 328k | table, id); |
1143 | 328k | if (scope == NULL) { |
1144 | 2.42k | return 1; /* id is not known, so return success */ |
1145 | 2.42k | } |
1146 | 326k | return is_scope_in_stack(scope, stack_top); |
1147 | 328k | } |
1148 | | |
1149 | | static int is_perm_in_scope_index(uint32_t perm_value, uint32_t class_value, |
1150 | | const scope_index_t * scope) |
1151 | 2.00k | { |
1152 | 2.00k | if (class_value > scope->class_perms_len) { |
1153 | 955 | return 1; |
1154 | 955 | } |
1155 | 1.05k | if (ebitmap_get_bit(scope->class_perms_map + class_value - 1, |
1156 | 1.05k | perm_value - 1)) { |
1157 | 901 | return 1; |
1158 | 901 | } |
1159 | 149 | return 0; |
1160 | 1.05k | } |
1161 | | |
1162 | | static int is_perm_in_stack(uint32_t perm_value, uint32_t class_value, |
1163 | | const scope_stack_t * stack) |
1164 | 1.85k | { |
1165 | 1.85k | if (stack == NULL) { |
1166 | 0 | return 0; /* no matching scope found */ |
1167 | 0 | } |
1168 | 1.85k | if (stack->type == 1) { |
1169 | 1.85k | avrule_decl_t *decl = stack->decl; |
1170 | 1.85k | if (is_perm_in_scope_index |
1171 | 1.85k | (perm_value, class_value, &decl->required) |
1172 | 149 | || is_perm_in_scope_index(perm_value, class_value, |
1173 | 1.85k | &decl->declared)) { |
1174 | 1.85k | return 1; |
1175 | 1.85k | } |
1176 | 1.85k | } 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 | 1.85k | } |
1184 | | |
1185 | | int is_perm_in_scope(const_hashtab_key_t perm_id, const_hashtab_key_t class_id) |
1186 | 1.85k | { |
1187 | 1.85k | const class_datum_t *cladatum = |
1188 | 1.85k | (class_datum_t *) hashtab_search(policydbp->p_classes.table, |
1189 | 1.85k | class_id); |
1190 | 1.85k | const perm_datum_t *perdatum; |
1191 | 1.85k | if (cladatum == NULL) { |
1192 | 0 | return 1; |
1193 | 0 | } |
1194 | 1.85k | perdatum = (perm_datum_t *) hashtab_search(cladatum->permissions.table, |
1195 | 1.85k | perm_id); |
1196 | 1.85k | if (perdatum == NULL) { |
1197 | 0 | return 1; |
1198 | 0 | } |
1199 | 1.85k | return is_perm_in_stack(perdatum->s.value, cladatum->s.value, |
1200 | 1.85k | stack_top); |
1201 | 1.85k | } |
1202 | | |
1203 | | cond_list_t *get_current_cond_list(cond_list_t * cond) |
1204 | 8.38k | { |
1205 | | /* FIX ME: do something different here if in a nested |
1206 | | * conditional? */ |
1207 | 8.38k | avrule_decl_t *decl = stack_top->decl; |
1208 | 8.38k | return get_decl_cond_list(policydbp, decl, cond); |
1209 | 8.38k | } |
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 | 4.19k | { |
1217 | 4.19k | cond_list_t *old_cond = get_current_cond_list(cond); |
1218 | 4.19k | avrule_t *tmp; |
1219 | 4.19k | assert(old_cond != NULL); /* probably out of memory */ |
1220 | 4.19k | if (old_cond->avtrue_list == NULL) { |
1221 | 2.89k | old_cond->avtrue_list = cond->avtrue_list; |
1222 | 2.89k | } else { |
1223 | 7.65k | for (tmp = old_cond->avtrue_list; tmp->next != NULL; |
1224 | 6.35k | tmp = tmp->next) ; |
1225 | 1.29k | tmp->next = cond->avtrue_list; |
1226 | 1.29k | } |
1227 | 4.19k | if (old_cond->avfalse_list == NULL) { |
1228 | 2.66k | old_cond->avfalse_list = cond->avfalse_list; |
1229 | 2.66k | } else { |
1230 | 67.9k | for (tmp = old_cond->avfalse_list; tmp->next != NULL; |
1231 | 66.3k | tmp = tmp->next) ; |
1232 | 1.53k | tmp->next = cond->avfalse_list; |
1233 | 1.53k | } |
1234 | | |
1235 | 4.19k | old_cond->flags |= cond->flags; |
1236 | 4.19k | } |
1237 | | |
1238 | | void append_avrule(avrule_t * avrule) |
1239 | 11.6k | { |
1240 | 11.6k | 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 | 11.6k | assert(stack_top->type == 1); |
1248 | | |
1249 | 11.6k | if (stack_top->last_avrule == NULL) { |
1250 | 865 | decl->avrules = avrule; |
1251 | 10.7k | } else { |
1252 | 10.7k | stack_top->last_avrule->next = avrule; |
1253 | 10.7k | } |
1254 | 11.6k | stack_top->last_avrule = avrule; |
1255 | 11.6k | } |
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.48k | { |
1260 | 1.48k | avrule_decl_t *decl = stack_top->decl; |
1261 | | |
1262 | | /* role transitions are not allowed within conditionals */ |
1263 | 1.48k | assert(stack_top->type == 1); |
1264 | | |
1265 | 1.48k | role_tr_rules->next = decl->role_tr_rules; |
1266 | 1.48k | decl->role_tr_rules = role_tr_rules; |
1267 | 1.48k | } |
1268 | | |
1269 | | /* this doesn't actually append, but really prepends it */ |
1270 | | void append_role_allow(role_allow_rule_t * role_allow_rules) |
1271 | 4.92k | { |
1272 | 4.92k | avrule_decl_t *decl = stack_top->decl; |
1273 | | |
1274 | | /* role allows are not allowed within conditionals */ |
1275 | 4.92k | assert(stack_top->type == 1); |
1276 | | |
1277 | 4.92k | role_allow_rules->next = decl->role_allow_rules; |
1278 | 4.92k | decl->role_allow_rules = role_allow_rules; |
1279 | 4.92k | } |
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.36k | { |
1284 | 3.36k | avrule_decl_t *decl = stack_top->decl; |
1285 | | |
1286 | | /* filename transitions are not allowed within conditionals */ |
1287 | 3.36k | assert(stack_top->type == 1); |
1288 | | |
1289 | 3.36k | filename_trans_rules->next = decl->filename_trans_rules; |
1290 | 3.36k | decl->filename_trans_rules = filename_trans_rules; |
1291 | 3.36k | } |
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 | 116k | { |
1307 | 116k | avrule_block_t *block = NULL; |
1308 | 116k | avrule_decl_t *decl; |
1309 | 116k | if (pass == 1) { |
1310 | | /* allocate a new avrule block for this optional block */ |
1311 | 101k | if ((block = avrule_block_create()) == NULL || |
1312 | 101k | (decl = avrule_decl_create(next_decl_id)) == NULL) { |
1313 | 0 | goto cleanup; |
1314 | 0 | } |
1315 | 101k | block->flags |= AVRULE_OPTIONAL; |
1316 | 101k | block->branch_list = decl; |
1317 | 101k | last_block->next = block; |
1318 | 101k | } else { |
1319 | | /* select the next block from the chain built during pass 1 */ |
1320 | 14.2k | block = last_block->next; |
1321 | 14.2k | assert(block != NULL && |
1322 | 14.2k | block->branch_list != NULL && |
1323 | 14.2k | block->branch_list->decl_id == next_decl_id); |
1324 | 14.2k | decl = block->branch_list; |
1325 | 14.2k | } |
1326 | 116k | if (push_stack(1, block, decl) == -1) { |
1327 | 0 | goto cleanup; |
1328 | 0 | } |
1329 | 116k | stack_top->last_avrule = NULL; |
1330 | 116k | last_block = block; |
1331 | 116k | next_decl_id++; |
1332 | 116k | return 0; |
1333 | 0 | cleanup: |
1334 | 0 | yyerror("Out of memory!"); |
1335 | 0 | avrule_block_destroy(block); |
1336 | 0 | return -1; |
1337 | 116k | } |
1338 | | |
1339 | | int end_optional(int pass __attribute__ ((unused))) |
1340 | 95.0k | { |
1341 | | /* once nested conditionals are allowed, do the stack unfolding here */ |
1342 | 95.0k | pop_stack(); |
1343 | 95.0k | return 0; |
1344 | 95.0k | } |
1345 | | |
1346 | | int begin_optional_else(int pass) |
1347 | 1.28k | { |
1348 | 1.28k | avrule_decl_t *decl; |
1349 | 1.28k | assert(stack_top->type == 1 && stack_top->in_else == 0); |
1350 | 1.28k | if (pass == 1) { |
1351 | | /* allocate a new declaration and add it to the |
1352 | | * current chain */ |
1353 | 1.09k | if ((decl = avrule_decl_create(next_decl_id)) == NULL) { |
1354 | 0 | yyerror("Out of memory!"); |
1355 | 0 | return -1; |
1356 | 0 | } |
1357 | 1.09k | stack_top->decl->next = decl; |
1358 | 1.09k | } else { |
1359 | | /* pick the (hopefully last) declaration of this |
1360 | | avrule block, built from pass 1 */ |
1361 | 190 | decl = stack_top->decl->next; |
1362 | 190 | assert(decl != NULL && |
1363 | 190 | decl->next == NULL && decl->decl_id == next_decl_id); |
1364 | 190 | } |
1365 | 1.28k | stack_top->in_else = 1; |
1366 | 1.28k | stack_top->decl = decl; |
1367 | 1.28k | stack_top->last_avrule = NULL; |
1368 | 1.28k | stack_top->require_given = 0; |
1369 | 1.28k | next_decl_id++; |
1370 | 1.28k | return 0; |
1371 | 1.28k | } |
1372 | | |
1373 | | static int copy_requirements(avrule_decl_t * dest, const scope_stack_t * stack) |
1374 | 342k | { |
1375 | 342k | uint32_t i; |
1376 | 342k | if (stack == NULL) { |
1377 | 11.4k | return 0; |
1378 | 11.4k | } |
1379 | 331k | if (stack->type == 1) { |
1380 | 331k | const scope_index_t *src_scope = &stack->decl->required; |
1381 | 331k | scope_index_t *dest_scope = &dest->required; |
1382 | 2.98M | for (i = 0; i < SYM_NUM; i++) { |
1383 | 2.65M | const ebitmap_t *src_bitmap = &src_scope->scope[i]; |
1384 | 2.65M | ebitmap_t *dest_bitmap = &dest_scope->scope[i]; |
1385 | 2.65M | if (ebitmap_union(dest_bitmap, src_bitmap)) { |
1386 | 0 | yyerror("Out of memory!"); |
1387 | 0 | return -1; |
1388 | 0 | } |
1389 | 2.65M | } |
1390 | | /* now copy class permissions */ |
1391 | 331k | if (src_scope->class_perms_len > dest_scope->class_perms_len) { |
1392 | 11.2k | ebitmap_t *new_map = |
1393 | 11.2k | realloc(dest_scope->class_perms_map, |
1394 | 11.2k | src_scope->class_perms_len * |
1395 | 11.2k | sizeof(*new_map)); |
1396 | 11.2k | if (new_map == NULL) { |
1397 | 0 | yyerror("Out of memory!"); |
1398 | 0 | return -1; |
1399 | 0 | } |
1400 | 11.2k | dest_scope->class_perms_map = new_map; |
1401 | 11.2k | for (i = dest_scope->class_perms_len; |
1402 | 29.9k | i < src_scope->class_perms_len; i++) { |
1403 | 18.6k | ebitmap_init(dest_scope->class_perms_map + i); |
1404 | 18.6k | } |
1405 | 11.2k | dest_scope->class_perms_len = |
1406 | 11.2k | src_scope->class_perms_len; |
1407 | 11.2k | } |
1408 | 350k | for (i = 0; i < src_scope->class_perms_len; i++) { |
1409 | 18.8k | const ebitmap_t *src_bitmap = &src_scope->class_perms_map[i]; |
1410 | 18.8k | ebitmap_t *dest_bitmap = |
1411 | 18.8k | &dest_scope->class_perms_map[i]; |
1412 | 18.8k | if (ebitmap_union(dest_bitmap, src_bitmap)) { |
1413 | 0 | yyerror("Out of memory!"); |
1414 | 0 | return -1; |
1415 | 0 | } |
1416 | 18.8k | } |
1417 | 331k | } |
1418 | 331k | return copy_requirements(dest, stack->parent); |
1419 | 331k | } |
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 | 96.3k | { |
1427 | 96.3k | avrule_decl_t *decl = stack_top->decl; |
1428 | 96.3k | assert(stack_top->type == 1); |
1429 | 96.3k | if (pass == 2) { |
1430 | | /* this avrule_decl inherits all of its parents' |
1431 | | * requirements */ |
1432 | 11.4k | if (copy_requirements(decl, stack_top->parent) == -1) { |
1433 | 0 | return -1; |
1434 | 0 | } |
1435 | 11.4k | return 0; |
1436 | 11.4k | } |
1437 | 84.8k | if (!stack_top->in_else && !stack_top->require_given) { |
1438 | 77.5k | if (policydbp->policy_type == POLICY_BASE |
1439 | 77.5k | && stack_top->parent != NULL) { |
1440 | | /* if this is base no require should be in the global block */ |
1441 | 77.5k | return 0; |
1442 | 77.5k | } 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 | 77.5k | } |
1448 | 7.32k | return 0; |
1449 | 84.8k | } |
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 | 126k | { |
1455 | 126k | scope_stack_t *s = calloc(1, sizeof(*s)); |
1456 | 126k | va_list ap; |
1457 | 126k | if (s == NULL) { |
1458 | 0 | return -1; |
1459 | 0 | } |
1460 | 126k | va_start(ap, stack_type); |
1461 | 126k | switch (s->type = stack_type) { |
1462 | 126k | case 1:{ |
1463 | 126k | va_arg(ap, avrule_block_t *); |
1464 | 126k | s->decl = va_arg(ap, avrule_decl_t *); |
1465 | 126k | 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 | 126k | } |
1475 | 126k | va_end(ap); |
1476 | 126k | s->parent = stack_top; |
1477 | 126k | stack_top = s; |
1478 | 126k | return 0; |
1479 | 126k | } |
1480 | | |
1481 | | /* Pop off the most recently added from the stack. Update the 'last' |
1482 | | * pointer. */ |
1483 | | static void pop_stack(void) |
1484 | 126k | { |
1485 | 126k | scope_stack_t *parent; |
1486 | 126k | assert(stack_top != NULL); |
1487 | 126k | parent = stack_top->parent; |
1488 | 126k | free(stack_top); |
1489 | 126k | stack_top = parent; |
1490 | 126k | } |
1491 | | |
1492 | | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
1493 | | void module_compiler_reset(void) |
1494 | 6.65k | { |
1495 | 34.2k | while (stack_top) |
1496 | 27.5k | pop_stack(); |
1497 | | |
1498 | | last_block = NULL; |
1499 | 6.65k | next_decl_id = 1; |
1500 | 6.65k | } |
1501 | | #endif |