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