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