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