16cd6a6acSopenharmony_ci/* Author : Joshua Brindle <jbrindle@tresys.com> 26cd6a6acSopenharmony_ci * Karl MacMillan <kmacmillan@tresys.com> 36cd6a6acSopenharmony_ci * Jason Tang <jtang@tresys.com> 46cd6a6acSopenharmony_ci * Added support for binary policy modules 56cd6a6acSopenharmony_ci * 66cd6a6acSopenharmony_ci * Copyright (C) 2004 - 2005 Tresys Technology, LLC 76cd6a6acSopenharmony_ci * This program is free software; you can redistribute it and/or modify 86cd6a6acSopenharmony_ci * it under the terms of the GNU General Public License as published by 96cd6a6acSopenharmony_ci * the Free Software Foundation, version 2. 106cd6a6acSopenharmony_ci */ 116cd6a6acSopenharmony_ci 126cd6a6acSopenharmony_ci#include <assert.h> 136cd6a6acSopenharmony_ci#include <stdarg.h> 146cd6a6acSopenharmony_ci#include <stdlib.h> 156cd6a6acSopenharmony_ci#include <string.h> 166cd6a6acSopenharmony_ci 176cd6a6acSopenharmony_ci#include <sepol/policydb/policydb.h> 186cd6a6acSopenharmony_ci#include <sepol/policydb/avrule_block.h> 196cd6a6acSopenharmony_ci#include <sepol/policydb/conditional.h> 206cd6a6acSopenharmony_ci 216cd6a6acSopenharmony_ci#include "queue.h" 226cd6a6acSopenharmony_ci#include "module_compiler.h" 236cd6a6acSopenharmony_ci 246cd6a6acSopenharmony_ciunion stack_item_u { 256cd6a6acSopenharmony_ci avrule_block_t *avrule; 266cd6a6acSopenharmony_ci cond_list_t *cond_list; 276cd6a6acSopenharmony_ci}; 286cd6a6acSopenharmony_ci 296cd6a6acSopenharmony_citypedef struct scope_stack { 306cd6a6acSopenharmony_ci union stack_item_u u; 316cd6a6acSopenharmony_ci int type; /* for above union: 1 = avrule block, 2 = conditional */ 326cd6a6acSopenharmony_ci avrule_decl_t *decl; /* if in an avrule block, which 336cd6a6acSopenharmony_ci * declaration is current */ 346cd6a6acSopenharmony_ci avrule_t *last_avrule; 356cd6a6acSopenharmony_ci int in_else; /* if in an avrule block, within ELSE branch */ 366cd6a6acSopenharmony_ci int require_given; /* 1 if this block had at least one require */ 376cd6a6acSopenharmony_ci struct scope_stack *parent, *child; 386cd6a6acSopenharmony_ci} scope_stack_t; 396cd6a6acSopenharmony_ci 406cd6a6acSopenharmony_ciextern policydb_t *policydbp; 416cd6a6acSopenharmony_ciextern queue_t id_queue; 426cd6a6acSopenharmony_ciextern int yyerror(const char *msg); 436cd6a6acSopenharmony_ci__attribute__ ((format(printf, 1, 2))) 446cd6a6acSopenharmony_ciextern void yyerror2(const char *fmt, ...); 456cd6a6acSopenharmony_ci 466cd6a6acSopenharmony_cistatic int push_stack(int stack_type, ...); 476cd6a6acSopenharmony_cistatic void pop_stack(void); 486cd6a6acSopenharmony_ci 496cd6a6acSopenharmony_ci/* keep track of the last item added to the stack */ 506cd6a6acSopenharmony_cistatic scope_stack_t *stack_top = NULL; 516cd6a6acSopenharmony_cistatic avrule_block_t *last_block; 526cd6a6acSopenharmony_cistatic uint32_t next_decl_id = 1; 536cd6a6acSopenharmony_ci 546cd6a6acSopenharmony_cistatic const char * const flavor_str[SYM_NUM] = { 556cd6a6acSopenharmony_ci [SYM_COMMONS] = "common", 566cd6a6acSopenharmony_ci [SYM_CLASSES] = "class", 576cd6a6acSopenharmony_ci [SYM_ROLES] = "role", 586cd6a6acSopenharmony_ci [SYM_TYPES] = "type", 596cd6a6acSopenharmony_ci [SYM_USERS] = "user", 606cd6a6acSopenharmony_ci [SYM_BOOLS] = "bool", 616cd6a6acSopenharmony_ci [SYM_LEVELS] = "level", 626cd6a6acSopenharmony_ci [SYM_CATS] = "cat" 636cd6a6acSopenharmony_ci}; 646cd6a6acSopenharmony_ci 656cd6a6acSopenharmony_cistatic void print_error_msg(int ret, uint32_t symbol_type) 666cd6a6acSopenharmony_ci{ 676cd6a6acSopenharmony_ci switch (ret) { 686cd6a6acSopenharmony_ci case -3: 696cd6a6acSopenharmony_ci yyerror("Out of memory!"); 706cd6a6acSopenharmony_ci break; 716cd6a6acSopenharmony_ci case -2: 726cd6a6acSopenharmony_ci yyerror2("Duplicate declaration of %s", flavor_str[symbol_type]); 736cd6a6acSopenharmony_ci break; 746cd6a6acSopenharmony_ci case -1: 756cd6a6acSopenharmony_ci yyerror2("Could not declare %s here", flavor_str[symbol_type]); 766cd6a6acSopenharmony_ci break; 776cd6a6acSopenharmony_ci default: 786cd6a6acSopenharmony_ci yyerror("Unknown error"); 796cd6a6acSopenharmony_ci } 806cd6a6acSopenharmony_ci} 816cd6a6acSopenharmony_ci 826cd6a6acSopenharmony_ciint define_policy(int pass, int module_header_given) 836cd6a6acSopenharmony_ci{ 846cd6a6acSopenharmony_ci char *id; 856cd6a6acSopenharmony_ci 866cd6a6acSopenharmony_ci if (module_header_given) { 876cd6a6acSopenharmony_ci if (policydbp->policy_type != POLICY_MOD) { 886cd6a6acSopenharmony_ci yyerror 896cd6a6acSopenharmony_ci ("Module specification found while not building a policy module.\n"); 906cd6a6acSopenharmony_ci return -1; 916cd6a6acSopenharmony_ci } 926cd6a6acSopenharmony_ci 936cd6a6acSopenharmony_ci if (pass == 2) { 946cd6a6acSopenharmony_ci while ((id = queue_remove(id_queue)) != NULL) 956cd6a6acSopenharmony_ci free(id); 966cd6a6acSopenharmony_ci } else { 976cd6a6acSopenharmony_ci id = (char *)queue_remove(id_queue); 986cd6a6acSopenharmony_ci if (!id) { 996cd6a6acSopenharmony_ci yyerror("no module name"); 1006cd6a6acSopenharmony_ci return -1; 1016cd6a6acSopenharmony_ci } 1026cd6a6acSopenharmony_ci free(policydbp->name); 1036cd6a6acSopenharmony_ci policydbp->name = id; 1046cd6a6acSopenharmony_ci if ((policydbp->version = 1056cd6a6acSopenharmony_ci queue_remove(id_queue)) == NULL) { 1066cd6a6acSopenharmony_ci yyerror 1076cd6a6acSopenharmony_ci ("Expected a module version but none was found."); 1086cd6a6acSopenharmony_ci return -1; 1096cd6a6acSopenharmony_ci } 1106cd6a6acSopenharmony_ci } 1116cd6a6acSopenharmony_ci } else { 1126cd6a6acSopenharmony_ci if (policydbp->policy_type == POLICY_MOD) { 1136cd6a6acSopenharmony_ci yyerror 1146cd6a6acSopenharmony_ci ("Building a policy module, but no module specification found.\n"); 1156cd6a6acSopenharmony_ci return -1; 1166cd6a6acSopenharmony_ci } 1176cd6a6acSopenharmony_ci } 1186cd6a6acSopenharmony_ci /* the first declaration within the global avrule 1196cd6a6acSopenharmony_ci block will always have an id of 1 */ 1206cd6a6acSopenharmony_ci next_decl_id = 2; 1216cd6a6acSopenharmony_ci 1226cd6a6acSopenharmony_ci /* reset the scoping stack */ 1236cd6a6acSopenharmony_ci while (stack_top != NULL) { 1246cd6a6acSopenharmony_ci pop_stack(); 1256cd6a6acSopenharmony_ci } 1266cd6a6acSopenharmony_ci if (push_stack(1, policydbp->global, policydbp->global->branch_list) == 1276cd6a6acSopenharmony_ci -1) { 1286cd6a6acSopenharmony_ci return -1; 1296cd6a6acSopenharmony_ci } 1306cd6a6acSopenharmony_ci last_block = policydbp->global; 1316cd6a6acSopenharmony_ci return 0; 1326cd6a6acSopenharmony_ci} 1336cd6a6acSopenharmony_ci 1346cd6a6acSopenharmony_ci/* Given the current parse stack, returns 1 if a declaration or require would 1356cd6a6acSopenharmony_ci * be allowed here or 0 if not. For example, declarations and requirements are 1366cd6a6acSopenharmony_ci * not allowed in conditionals, so if there are any conditionals in the 1376cd6a6acSopenharmony_ci * current scope stack then this would return a 0. 1386cd6a6acSopenharmony_ci */ 1396cd6a6acSopenharmony_cistatic int is_creation_allowed(void) 1406cd6a6acSopenharmony_ci{ 1416cd6a6acSopenharmony_ci if (stack_top->type != 1 || stack_top->in_else) { 1426cd6a6acSopenharmony_ci return 0; 1436cd6a6acSopenharmony_ci } 1446cd6a6acSopenharmony_ci return 1; 1456cd6a6acSopenharmony_ci} 1466cd6a6acSopenharmony_ci 1476cd6a6acSopenharmony_ci/* Attempt to declare or require a symbol within the current scope. 1486cd6a6acSopenharmony_ci * Returns: 1496cd6a6acSopenharmony_ci * 0: Success - Symbol had not been previously created. 1506cd6a6acSopenharmony_ci * 1: Success - Symbol had already been created and caller must free datum. 1516cd6a6acSopenharmony_ci * -1: Failure - Symbol cannot be created here 1526cd6a6acSopenharmony_ci * -2: Failure - Duplicate declaration or type/attribute mismatch 1536cd6a6acSopenharmony_ci * -3: Failure - Out of memory or some other error 1546cd6a6acSopenharmony_ci */ 1556cd6a6acSopenharmony_cistatic int create_symbol(uint32_t symbol_type, hashtab_key_t key, hashtab_datum_t datum, 1566cd6a6acSopenharmony_ci uint32_t * dest_value, uint32_t scope) 1576cd6a6acSopenharmony_ci{ 1586cd6a6acSopenharmony_ci avrule_decl_t *decl = stack_top->decl; 1596cd6a6acSopenharmony_ci int ret; 1606cd6a6acSopenharmony_ci 1616cd6a6acSopenharmony_ci if (!is_creation_allowed()) { 1626cd6a6acSopenharmony_ci return -1; 1636cd6a6acSopenharmony_ci } 1646cd6a6acSopenharmony_ci 1656cd6a6acSopenharmony_ci ret = symtab_insert(policydbp, symbol_type, key, datum, scope, 1666cd6a6acSopenharmony_ci decl->decl_id, dest_value); 1676cd6a6acSopenharmony_ci 1686cd6a6acSopenharmony_ci if (ret == 1 && dest_value) { 1696cd6a6acSopenharmony_ci hashtab_datum_t s = 1706cd6a6acSopenharmony_ci hashtab_search(policydbp->symtab[symbol_type].table, 1716cd6a6acSopenharmony_ci key); 1726cd6a6acSopenharmony_ci assert(s != NULL); 1736cd6a6acSopenharmony_ci 1746cd6a6acSopenharmony_ci if (symbol_type == SYM_LEVELS) { 1756cd6a6acSopenharmony_ci *dest_value = ((level_datum_t *)s)->level->sens; 1766cd6a6acSopenharmony_ci } else { 1776cd6a6acSopenharmony_ci *dest_value = ((symtab_datum_t *)s)->value; 1786cd6a6acSopenharmony_ci } 1796cd6a6acSopenharmony_ci } else if (ret == -2) { 1806cd6a6acSopenharmony_ci return -2; 1816cd6a6acSopenharmony_ci } else if (ret < 0) { 1826cd6a6acSopenharmony_ci return -3; 1836cd6a6acSopenharmony_ci } 1846cd6a6acSopenharmony_ci 1856cd6a6acSopenharmony_ci return ret; 1866cd6a6acSopenharmony_ci} 1876cd6a6acSopenharmony_ci 1886cd6a6acSopenharmony_ci/* Attempt to declare a symbol within the current declaration. If 1896cd6a6acSopenharmony_ci * currently within a non-conditional and in a non-else branch then 1906cd6a6acSopenharmony_ci * insert the symbol, return 0 on success if symbol was undeclared. 1916cd6a6acSopenharmony_ci * For roles and users, it is legal to have multiple declarations; as 1926cd6a6acSopenharmony_ci * such return 1 to indicate that caller must free() the datum because 1936cd6a6acSopenharmony_ci * it was not added. If symbols may not be declared here return -1. 1946cd6a6acSopenharmony_ci * For duplicate declarations return -2. For all else, including out 1956cd6a6acSopenharmony_ci * of memory, return -3. Note that dest_value and datum_value might 1966cd6a6acSopenharmony_ci * not be restricted pointers. */ 1976cd6a6acSopenharmony_ciint declare_symbol(uint32_t symbol_type, 1986cd6a6acSopenharmony_ci hashtab_key_t key, hashtab_datum_t datum, 1996cd6a6acSopenharmony_ci uint32_t * dest_value, uint32_t * datum_value) 2006cd6a6acSopenharmony_ci{ 2016cd6a6acSopenharmony_ci avrule_decl_t *decl = stack_top->decl; 2026cd6a6acSopenharmony_ci int ret = create_symbol(symbol_type, key, datum, dest_value, SCOPE_DECL); 2036cd6a6acSopenharmony_ci 2046cd6a6acSopenharmony_ci if (ret < 0) { 2056cd6a6acSopenharmony_ci return ret; 2066cd6a6acSopenharmony_ci } 2076cd6a6acSopenharmony_ci 2086cd6a6acSopenharmony_ci if (ebitmap_set_bit(decl->declared.scope + symbol_type, 2096cd6a6acSopenharmony_ci *datum_value - 1, 1)) { 2106cd6a6acSopenharmony_ci return -3; 2116cd6a6acSopenharmony_ci } 2126cd6a6acSopenharmony_ci 2136cd6a6acSopenharmony_ci return ret; 2146cd6a6acSopenharmony_ci} 2156cd6a6acSopenharmony_ci 2166cd6a6acSopenharmony_cistatic int role_implicit_bounds(hashtab_t roles_tab, 2176cd6a6acSopenharmony_ci char *role_id, role_datum_t *role) 2186cd6a6acSopenharmony_ci{ 2196cd6a6acSopenharmony_ci role_datum_t *bounds; 2206cd6a6acSopenharmony_ci char *bounds_id, *delim; 2216cd6a6acSopenharmony_ci 2226cd6a6acSopenharmony_ci delim = strrchr(role_id, '.'); 2236cd6a6acSopenharmony_ci if (!delim) 2246cd6a6acSopenharmony_ci return 0; /* no implicit boundary */ 2256cd6a6acSopenharmony_ci 2266cd6a6acSopenharmony_ci bounds_id = strdup(role_id); 2276cd6a6acSopenharmony_ci if (!bounds_id) { 2286cd6a6acSopenharmony_ci yyerror("out of memory"); 2296cd6a6acSopenharmony_ci return -1; 2306cd6a6acSopenharmony_ci } 2316cd6a6acSopenharmony_ci bounds_id[(size_t)(delim - role_id)] = '\0'; 2326cd6a6acSopenharmony_ci 2336cd6a6acSopenharmony_ci bounds = hashtab_search(roles_tab, bounds_id); 2346cd6a6acSopenharmony_ci if (!bounds) { 2356cd6a6acSopenharmony_ci yyerror2("role %s doesn't exist, is implicit bounds of %s", 2366cd6a6acSopenharmony_ci bounds_id, role_id); 2376cd6a6acSopenharmony_ci return -1; 2386cd6a6acSopenharmony_ci } 2396cd6a6acSopenharmony_ci 2406cd6a6acSopenharmony_ci if (!role->bounds) 2416cd6a6acSopenharmony_ci role->bounds = bounds->s.value; 2426cd6a6acSopenharmony_ci else if (role->bounds != bounds->s.value) { 2436cd6a6acSopenharmony_ci yyerror2("role %s has inconsistent bounds %s/%s", 2446cd6a6acSopenharmony_ci role_id, bounds_id, 2456cd6a6acSopenharmony_ci policydbp->p_role_val_to_name[role->bounds - 1]); 2466cd6a6acSopenharmony_ci return -1; 2476cd6a6acSopenharmony_ci } 2486cd6a6acSopenharmony_ci free(bounds_id); 2496cd6a6acSopenharmony_ci 2506cd6a6acSopenharmony_ci return 0; 2516cd6a6acSopenharmony_ci} 2526cd6a6acSopenharmony_ci 2536cd6a6acSopenharmony_cistatic int create_role(uint32_t scope, unsigned char isattr, role_datum_t **role, char **key) 2546cd6a6acSopenharmony_ci{ 2556cd6a6acSopenharmony_ci char *id = queue_remove(id_queue); 2566cd6a6acSopenharmony_ci role_datum_t *datum = NULL; 2576cd6a6acSopenharmony_ci int ret; 2586cd6a6acSopenharmony_ci uint32_t value; 2596cd6a6acSopenharmony_ci 2606cd6a6acSopenharmony_ci *role = NULL; 2616cd6a6acSopenharmony_ci *key = NULL; 2626cd6a6acSopenharmony_ci isattr = isattr ? ROLE_ATTRIB : ROLE_ROLE; 2636cd6a6acSopenharmony_ci 2646cd6a6acSopenharmony_ci if (id == NULL) { 2656cd6a6acSopenharmony_ci yyerror("no role name"); 2666cd6a6acSopenharmony_ci return -1; 2676cd6a6acSopenharmony_ci } 2686cd6a6acSopenharmony_ci 2696cd6a6acSopenharmony_ci datum = malloc(sizeof(*datum)); 2706cd6a6acSopenharmony_ci if (datum == NULL) { 2716cd6a6acSopenharmony_ci yyerror("Out of memory!"); 2726cd6a6acSopenharmony_ci free(id); 2736cd6a6acSopenharmony_ci return -1; 2746cd6a6acSopenharmony_ci } 2756cd6a6acSopenharmony_ci 2766cd6a6acSopenharmony_ci role_datum_init(datum); 2776cd6a6acSopenharmony_ci datum->flavor = isattr; 2786cd6a6acSopenharmony_ci 2796cd6a6acSopenharmony_ci if (scope == SCOPE_DECL) { 2806cd6a6acSopenharmony_ci ret = declare_symbol(SYM_ROLES, id, datum, &value, &value); 2816cd6a6acSopenharmony_ci } else { 2826cd6a6acSopenharmony_ci ret = require_symbol(SYM_ROLES, id, datum, &value, &value); 2836cd6a6acSopenharmony_ci } 2846cd6a6acSopenharmony_ci 2856cd6a6acSopenharmony_ci datum->s.value = value; 2866cd6a6acSopenharmony_ci 2876cd6a6acSopenharmony_ci if (ret == 0) { 2886cd6a6acSopenharmony_ci *role = datum; 2896cd6a6acSopenharmony_ci *key = strdup(id); 2906cd6a6acSopenharmony_ci if (*key == NULL) { 2916cd6a6acSopenharmony_ci yyerror("Out of memory!"); 2926cd6a6acSopenharmony_ci return -1; 2936cd6a6acSopenharmony_ci } 2946cd6a6acSopenharmony_ci } else if (ret == 1) { 2956cd6a6acSopenharmony_ci *role = hashtab_search(policydbp->symtab[SYM_ROLES].table, id); 2966cd6a6acSopenharmony_ci if (*role && (isattr != (*role)->flavor)) { 2976cd6a6acSopenharmony_ci yyerror2("Identifier %s used as both an attribute and a role", 2986cd6a6acSopenharmony_ci id); 2996cd6a6acSopenharmony_ci free(id); 3006cd6a6acSopenharmony_ci role_datum_destroy(datum); 3016cd6a6acSopenharmony_ci free(datum); 3026cd6a6acSopenharmony_ci return -1; 3036cd6a6acSopenharmony_ci } 3046cd6a6acSopenharmony_ci *role = datum; 3056cd6a6acSopenharmony_ci *key = id; 3066cd6a6acSopenharmony_ci } else { 3076cd6a6acSopenharmony_ci print_error_msg(ret, SYM_ROLES); 3086cd6a6acSopenharmony_ci free(id); 3096cd6a6acSopenharmony_ci role_datum_destroy(datum); 3106cd6a6acSopenharmony_ci free(datum); 3116cd6a6acSopenharmony_ci } 3126cd6a6acSopenharmony_ci 3136cd6a6acSopenharmony_ci return ret; 3146cd6a6acSopenharmony_ci} 3156cd6a6acSopenharmony_ci 3166cd6a6acSopenharmony_cirole_datum_t *declare_role(unsigned char isattr) 3176cd6a6acSopenharmony_ci{ 3186cd6a6acSopenharmony_ci char *key = NULL; 3196cd6a6acSopenharmony_ci role_datum_t *role = NULL; 3206cd6a6acSopenharmony_ci role_datum_t *dest_role = NULL; 3216cd6a6acSopenharmony_ci hashtab_t roles_tab; 3226cd6a6acSopenharmony_ci int ret, ret2; 3236cd6a6acSopenharmony_ci 3246cd6a6acSopenharmony_ci ret = create_role(SCOPE_DECL, isattr, &role, &key); 3256cd6a6acSopenharmony_ci if (ret < 0) { 3266cd6a6acSopenharmony_ci return NULL; 3276cd6a6acSopenharmony_ci } 3286cd6a6acSopenharmony_ci 3296cd6a6acSopenharmony_ci /* create a new role_datum_t for this decl, if necessary */ 3306cd6a6acSopenharmony_ci assert(stack_top->type == 1); 3316cd6a6acSopenharmony_ci 3326cd6a6acSopenharmony_ci if (stack_top->parent == NULL) { 3336cd6a6acSopenharmony_ci /* in parent, so use global symbol table */ 3346cd6a6acSopenharmony_ci roles_tab = policydbp->p_roles.table; 3356cd6a6acSopenharmony_ci } else { 3366cd6a6acSopenharmony_ci roles_tab = stack_top->decl->p_roles.table; 3376cd6a6acSopenharmony_ci } 3386cd6a6acSopenharmony_ci 3396cd6a6acSopenharmony_ci dest_role = hashtab_search(roles_tab, key); 3406cd6a6acSopenharmony_ci if (dest_role == NULL) { 3416cd6a6acSopenharmony_ci if (ret == 0) { 3426cd6a6acSopenharmony_ci dest_role = malloc(sizeof(*dest_role)); 3436cd6a6acSopenharmony_ci if (dest_role == NULL) { 3446cd6a6acSopenharmony_ci yyerror("Out of memory!"); 3456cd6a6acSopenharmony_ci free(key); 3466cd6a6acSopenharmony_ci return NULL; 3476cd6a6acSopenharmony_ci } 3486cd6a6acSopenharmony_ci role_datum_init(dest_role); 3496cd6a6acSopenharmony_ci dest_role->s.value = role->s.value; 3506cd6a6acSopenharmony_ci dest_role->flavor = role->flavor; 3516cd6a6acSopenharmony_ci } else { 3526cd6a6acSopenharmony_ci dest_role = role; 3536cd6a6acSopenharmony_ci } 3546cd6a6acSopenharmony_ci ret2 = role_implicit_bounds(roles_tab, key, dest_role); 3556cd6a6acSopenharmony_ci if (ret2 != 0) { 3566cd6a6acSopenharmony_ci free(key); 3576cd6a6acSopenharmony_ci role_datum_destroy(dest_role); 3586cd6a6acSopenharmony_ci free(dest_role); 3596cd6a6acSopenharmony_ci return NULL; 3606cd6a6acSopenharmony_ci } 3616cd6a6acSopenharmony_ci ret2 = hashtab_insert(roles_tab, key, dest_role); 3626cd6a6acSopenharmony_ci if (ret2 != 0) { 3636cd6a6acSopenharmony_ci yyerror("Out of memory!"); 3646cd6a6acSopenharmony_ci free(key); 3656cd6a6acSopenharmony_ci role_datum_destroy(dest_role); 3666cd6a6acSopenharmony_ci free(dest_role); 3676cd6a6acSopenharmony_ci return NULL; 3686cd6a6acSopenharmony_ci } 3696cd6a6acSopenharmony_ci } else { 3706cd6a6acSopenharmony_ci free(key); 3716cd6a6acSopenharmony_ci if (ret == 1) { 3726cd6a6acSopenharmony_ci role_datum_destroy(role); 3736cd6a6acSopenharmony_ci free(role); 3746cd6a6acSopenharmony_ci } 3756cd6a6acSopenharmony_ci } 3766cd6a6acSopenharmony_ci 3776cd6a6acSopenharmony_ci if (ret == 0) { 3786cd6a6acSopenharmony_ci ret2 = ebitmap_set_bit(&dest_role->dominates, dest_role->s.value - 1, 1); 3796cd6a6acSopenharmony_ci if (ret2 != 0) { 3806cd6a6acSopenharmony_ci yyerror("out of memory"); 3816cd6a6acSopenharmony_ci return NULL; 3826cd6a6acSopenharmony_ci } 3836cd6a6acSopenharmony_ci } 3846cd6a6acSopenharmony_ci 3856cd6a6acSopenharmony_ci return dest_role; 3866cd6a6acSopenharmony_ci} 3876cd6a6acSopenharmony_ci 3886cd6a6acSopenharmony_cistatic int create_type(uint32_t scope, unsigned char isattr, type_datum_t **type) 3896cd6a6acSopenharmony_ci{ 3906cd6a6acSopenharmony_ci char *id; 3916cd6a6acSopenharmony_ci type_datum_t *datum; 3926cd6a6acSopenharmony_ci int ret; 3936cd6a6acSopenharmony_ci uint32_t value = 0; 3946cd6a6acSopenharmony_ci 3956cd6a6acSopenharmony_ci *type = NULL; 3966cd6a6acSopenharmony_ci isattr = isattr ? TYPE_ATTRIB : TYPE_TYPE; 3976cd6a6acSopenharmony_ci 3986cd6a6acSopenharmony_ci id = (char *)queue_remove(id_queue); 3996cd6a6acSopenharmony_ci if (!id) { 4006cd6a6acSopenharmony_ci yyerror("no type/attribute name?"); 4016cd6a6acSopenharmony_ci return -1; 4026cd6a6acSopenharmony_ci } 4036cd6a6acSopenharmony_ci if (strcmp(id, "self") == 0) { 4046cd6a6acSopenharmony_ci yyerror("\"self\" is a reserved type name."); 4056cd6a6acSopenharmony_ci free(id); 4066cd6a6acSopenharmony_ci return -1; 4076cd6a6acSopenharmony_ci } 4086cd6a6acSopenharmony_ci 4096cd6a6acSopenharmony_ci datum = malloc(sizeof(*datum)); 4106cd6a6acSopenharmony_ci if (!datum) { 4116cd6a6acSopenharmony_ci yyerror("Out of memory!"); 4126cd6a6acSopenharmony_ci free(id); 4136cd6a6acSopenharmony_ci return -1; 4146cd6a6acSopenharmony_ci } 4156cd6a6acSopenharmony_ci type_datum_init(datum); 4166cd6a6acSopenharmony_ci datum->primary = 1; 4176cd6a6acSopenharmony_ci datum->flavor = isattr; 4186cd6a6acSopenharmony_ci 4196cd6a6acSopenharmony_ci if (scope == SCOPE_DECL) { 4206cd6a6acSopenharmony_ci ret = declare_symbol(SYM_TYPES, id, datum, &value, &value); 4216cd6a6acSopenharmony_ci } else { 4226cd6a6acSopenharmony_ci ret = require_symbol(SYM_TYPES, id, datum, &value, &value); 4236cd6a6acSopenharmony_ci } 4246cd6a6acSopenharmony_ci 4256cd6a6acSopenharmony_ci if (ret == 0) { 4266cd6a6acSopenharmony_ci datum->s.value = value; 4276cd6a6acSopenharmony_ci *type = datum; 4286cd6a6acSopenharmony_ci } else if (ret == 1) { 4296cd6a6acSopenharmony_ci type_datum_destroy(datum); 4306cd6a6acSopenharmony_ci free(datum); 4316cd6a6acSopenharmony_ci *type = hashtab_search(policydbp->symtab[SYM_TYPES].table, id); 4326cd6a6acSopenharmony_ci if (*type && (isattr != (*type)->flavor)) { 4336cd6a6acSopenharmony_ci yyerror2("Identifier %s used as both an attribute and a type", 4346cd6a6acSopenharmony_ci id); 4356cd6a6acSopenharmony_ci free(id); 4366cd6a6acSopenharmony_ci return -1; 4376cd6a6acSopenharmony_ci } 4386cd6a6acSopenharmony_ci free(id); 4396cd6a6acSopenharmony_ci } else { 4406cd6a6acSopenharmony_ci print_error_msg(ret, SYM_TYPES); 4416cd6a6acSopenharmony_ci free(id); 4426cd6a6acSopenharmony_ci type_datum_destroy(datum); 4436cd6a6acSopenharmony_ci free(datum); 4446cd6a6acSopenharmony_ci } 4456cd6a6acSopenharmony_ci 4466cd6a6acSopenharmony_ci return ret; 4476cd6a6acSopenharmony_ci} 4486cd6a6acSopenharmony_ci 4496cd6a6acSopenharmony_citype_datum_t *declare_type(unsigned char primary, unsigned char isattr) 4506cd6a6acSopenharmony_ci{ 4516cd6a6acSopenharmony_ci type_datum_t *type = NULL; 4526cd6a6acSopenharmony_ci int ret = create_type(SCOPE_DECL, isattr, &type); 4536cd6a6acSopenharmony_ci 4546cd6a6acSopenharmony_ci if (ret == 0) { 4556cd6a6acSopenharmony_ci type->primary = primary; 4566cd6a6acSopenharmony_ci } 4576cd6a6acSopenharmony_ci 4586cd6a6acSopenharmony_ci return type; 4596cd6a6acSopenharmony_ci} 4606cd6a6acSopenharmony_ci 4616cd6a6acSopenharmony_cistatic int user_implicit_bounds(hashtab_t users_tab, 4626cd6a6acSopenharmony_ci char *user_id, user_datum_t *user) 4636cd6a6acSopenharmony_ci{ 4646cd6a6acSopenharmony_ci user_datum_t *bounds; 4656cd6a6acSopenharmony_ci char *bounds_id, *delim; 4666cd6a6acSopenharmony_ci 4676cd6a6acSopenharmony_ci delim = strrchr(user_id, '.'); 4686cd6a6acSopenharmony_ci if (!delim) 4696cd6a6acSopenharmony_ci return 0; /* no implicit boundary */ 4706cd6a6acSopenharmony_ci 4716cd6a6acSopenharmony_ci bounds_id = strdup(user_id); 4726cd6a6acSopenharmony_ci if (!bounds_id) { 4736cd6a6acSopenharmony_ci yyerror("out of memory"); 4746cd6a6acSopenharmony_ci return -1; 4756cd6a6acSopenharmony_ci } 4766cd6a6acSopenharmony_ci bounds_id[(size_t)(delim - user_id)] = '\0'; 4776cd6a6acSopenharmony_ci 4786cd6a6acSopenharmony_ci bounds = hashtab_search(users_tab, bounds_id); 4796cd6a6acSopenharmony_ci if (!bounds) { 4806cd6a6acSopenharmony_ci yyerror2("user %s doesn't exist, is implicit bounds of %s", 4816cd6a6acSopenharmony_ci bounds_id, user_id); 4826cd6a6acSopenharmony_ci return -1; 4836cd6a6acSopenharmony_ci } 4846cd6a6acSopenharmony_ci 4856cd6a6acSopenharmony_ci if (!user->bounds) 4866cd6a6acSopenharmony_ci user->bounds = bounds->s.value; 4876cd6a6acSopenharmony_ci else if (user->bounds != bounds->s.value) { 4886cd6a6acSopenharmony_ci yyerror2("user %s has inconsistent bounds %s/%s", 4896cd6a6acSopenharmony_ci user_id, bounds_id, 4906cd6a6acSopenharmony_ci policydbp->p_role_val_to_name[user->bounds - 1]); 4916cd6a6acSopenharmony_ci return -1; 4926cd6a6acSopenharmony_ci } 4936cd6a6acSopenharmony_ci free(bounds_id); 4946cd6a6acSopenharmony_ci 4956cd6a6acSopenharmony_ci return 0; 4966cd6a6acSopenharmony_ci} 4976cd6a6acSopenharmony_ci 4986cd6a6acSopenharmony_cistatic int create_user(uint32_t scope, user_datum_t **user, char **key) 4996cd6a6acSopenharmony_ci{ 5006cd6a6acSopenharmony_ci char *id = queue_remove(id_queue); 5016cd6a6acSopenharmony_ci user_datum_t *datum = NULL; 5026cd6a6acSopenharmony_ci int ret; 5036cd6a6acSopenharmony_ci uint32_t value; 5046cd6a6acSopenharmony_ci 5056cd6a6acSopenharmony_ci *user = NULL; 5066cd6a6acSopenharmony_ci *key = NULL; 5076cd6a6acSopenharmony_ci 5086cd6a6acSopenharmony_ci if (id == NULL) { 5096cd6a6acSopenharmony_ci yyerror("no user name"); 5106cd6a6acSopenharmony_ci return -1; 5116cd6a6acSopenharmony_ci } 5126cd6a6acSopenharmony_ci 5136cd6a6acSopenharmony_ci datum = malloc(sizeof(*datum)); 5146cd6a6acSopenharmony_ci if (datum == NULL) { 5156cd6a6acSopenharmony_ci yyerror("Out of memory!"); 5166cd6a6acSopenharmony_ci free(id); 5176cd6a6acSopenharmony_ci return -1; 5186cd6a6acSopenharmony_ci } 5196cd6a6acSopenharmony_ci 5206cd6a6acSopenharmony_ci user_datum_init(datum); 5216cd6a6acSopenharmony_ci 5226cd6a6acSopenharmony_ci if (scope == SCOPE_DECL) { 5236cd6a6acSopenharmony_ci ret = declare_symbol(SYM_USERS, id, datum, &value, &value); 5246cd6a6acSopenharmony_ci } else { 5256cd6a6acSopenharmony_ci ret = require_symbol(SYM_USERS, id, datum, &value, &value); 5266cd6a6acSopenharmony_ci } 5276cd6a6acSopenharmony_ci 5286cd6a6acSopenharmony_ci datum->s.value = value; 5296cd6a6acSopenharmony_ci 5306cd6a6acSopenharmony_ci if (ret == 0) { 5316cd6a6acSopenharmony_ci *user = datum; 5326cd6a6acSopenharmony_ci *key = strdup(id); 5336cd6a6acSopenharmony_ci if (*key == NULL) { 5346cd6a6acSopenharmony_ci yyerror("Out of memory!"); 5356cd6a6acSopenharmony_ci return -1; 5366cd6a6acSopenharmony_ci } 5376cd6a6acSopenharmony_ci } else if (ret == 1) { 5386cd6a6acSopenharmony_ci *user = datum; 5396cd6a6acSopenharmony_ci *key = id; 5406cd6a6acSopenharmony_ci } else { 5416cd6a6acSopenharmony_ci print_error_msg(ret, SYM_USERS); 5426cd6a6acSopenharmony_ci free(id); 5436cd6a6acSopenharmony_ci user_datum_destroy(datum); 5446cd6a6acSopenharmony_ci free(datum); 5456cd6a6acSopenharmony_ci } 5466cd6a6acSopenharmony_ci 5476cd6a6acSopenharmony_ci return ret; 5486cd6a6acSopenharmony_ci} 5496cd6a6acSopenharmony_ci 5506cd6a6acSopenharmony_ciuser_datum_t *declare_user(void) 5516cd6a6acSopenharmony_ci{ 5526cd6a6acSopenharmony_ci char *key = NULL; 5536cd6a6acSopenharmony_ci user_datum_t *user = NULL; 5546cd6a6acSopenharmony_ci user_datum_t *dest_user = NULL; 5556cd6a6acSopenharmony_ci hashtab_t users_tab; 5566cd6a6acSopenharmony_ci int ret, ret2; 5576cd6a6acSopenharmony_ci 5586cd6a6acSopenharmony_ci ret = create_user(SCOPE_DECL, &user, &key); 5596cd6a6acSopenharmony_ci if (ret < 0) { 5606cd6a6acSopenharmony_ci return NULL; 5616cd6a6acSopenharmony_ci } 5626cd6a6acSopenharmony_ci 5636cd6a6acSopenharmony_ci /* create a new user_datum_t for this decl, if necessary */ 5646cd6a6acSopenharmony_ci assert(stack_top->type == 1); 5656cd6a6acSopenharmony_ci 5666cd6a6acSopenharmony_ci if (stack_top->parent == NULL) { 5676cd6a6acSopenharmony_ci /* in parent, so use global symbol table */ 5686cd6a6acSopenharmony_ci users_tab = policydbp->p_users.table; 5696cd6a6acSopenharmony_ci } else { 5706cd6a6acSopenharmony_ci users_tab = stack_top->decl->p_users.table; 5716cd6a6acSopenharmony_ci } 5726cd6a6acSopenharmony_ci 5736cd6a6acSopenharmony_ci dest_user = hashtab_search(users_tab, key); 5746cd6a6acSopenharmony_ci if (dest_user == NULL) { 5756cd6a6acSopenharmony_ci if (ret == 0) { 5766cd6a6acSopenharmony_ci dest_user = malloc(sizeof(*dest_user)); 5776cd6a6acSopenharmony_ci if (dest_user == NULL) { 5786cd6a6acSopenharmony_ci yyerror("Out of memory!"); 5796cd6a6acSopenharmony_ci free(key); 5806cd6a6acSopenharmony_ci return NULL; 5816cd6a6acSopenharmony_ci } 5826cd6a6acSopenharmony_ci user_datum_init(dest_user); 5836cd6a6acSopenharmony_ci dest_user->s.value = user->s.value; 5846cd6a6acSopenharmony_ci } else { 5856cd6a6acSopenharmony_ci dest_user = user; 5866cd6a6acSopenharmony_ci } 5876cd6a6acSopenharmony_ci ret2 = user_implicit_bounds(users_tab, key, dest_user); 5886cd6a6acSopenharmony_ci if (ret2 != 0) { 5896cd6a6acSopenharmony_ci free(key); 5906cd6a6acSopenharmony_ci user_datum_destroy(dest_user); 5916cd6a6acSopenharmony_ci free(dest_user); 5926cd6a6acSopenharmony_ci return NULL; 5936cd6a6acSopenharmony_ci } 5946cd6a6acSopenharmony_ci ret2 = hashtab_insert(users_tab, key, dest_user); 5956cd6a6acSopenharmony_ci if (ret2 != 0) { 5966cd6a6acSopenharmony_ci yyerror("Out of memory!"); 5976cd6a6acSopenharmony_ci free(key); 5986cd6a6acSopenharmony_ci user_datum_destroy(dest_user); 5996cd6a6acSopenharmony_ci free(dest_user); 6006cd6a6acSopenharmony_ci return NULL; 6016cd6a6acSopenharmony_ci } 6026cd6a6acSopenharmony_ci } else { 6036cd6a6acSopenharmony_ci free(key); 6046cd6a6acSopenharmony_ci if (ret == 1) { 6056cd6a6acSopenharmony_ci user_datum_destroy(user); 6066cd6a6acSopenharmony_ci free(user); 6076cd6a6acSopenharmony_ci } 6086cd6a6acSopenharmony_ci } 6096cd6a6acSopenharmony_ci 6106cd6a6acSopenharmony_ci return dest_user; 6116cd6a6acSopenharmony_ci} 6126cd6a6acSopenharmony_ci 6136cd6a6acSopenharmony_ci/* Return a type_datum_t for the local avrule_decl with the given ID. 6146cd6a6acSopenharmony_ci * If it does not exist, create one with the same value as 'value'. 6156cd6a6acSopenharmony_ci * This function assumes that the ID is within scope. c.f., 6166cd6a6acSopenharmony_ci * is_id_in_scope(). 6176cd6a6acSopenharmony_ci * 6186cd6a6acSopenharmony_ci * NOTE: this function usurps ownership of id afterwards. The caller 6196cd6a6acSopenharmony_ci * shall not reference it nor free() it afterwards. 6206cd6a6acSopenharmony_ci */ 6216cd6a6acSopenharmony_citype_datum_t *get_local_type(char *id, uint32_t value, unsigned char isattr) 6226cd6a6acSopenharmony_ci{ 6236cd6a6acSopenharmony_ci type_datum_t *dest_typdatum; 6246cd6a6acSopenharmony_ci hashtab_t types_tab; 6256cd6a6acSopenharmony_ci assert(stack_top->type == 1); 6266cd6a6acSopenharmony_ci if (stack_top->parent == NULL) { 6276cd6a6acSopenharmony_ci /* in global, so use global symbol table */ 6286cd6a6acSopenharmony_ci types_tab = policydbp->p_types.table; 6296cd6a6acSopenharmony_ci } else { 6306cd6a6acSopenharmony_ci types_tab = stack_top->decl->p_types.table; 6316cd6a6acSopenharmony_ci } 6326cd6a6acSopenharmony_ci dest_typdatum = hashtab_search(types_tab, id); 6336cd6a6acSopenharmony_ci if (!dest_typdatum) { 6346cd6a6acSopenharmony_ci dest_typdatum = (type_datum_t *) malloc(sizeof(type_datum_t)); 6356cd6a6acSopenharmony_ci if (dest_typdatum == NULL) { 6366cd6a6acSopenharmony_ci free(id); 6376cd6a6acSopenharmony_ci return NULL; 6386cd6a6acSopenharmony_ci } 6396cd6a6acSopenharmony_ci type_datum_init(dest_typdatum); 6406cd6a6acSopenharmony_ci dest_typdatum->s.value = value; 6416cd6a6acSopenharmony_ci dest_typdatum->flavor = isattr ? TYPE_ATTRIB : TYPE_TYPE; 6426cd6a6acSopenharmony_ci dest_typdatum->primary = 1; 6436cd6a6acSopenharmony_ci if (hashtab_insert(types_tab, id, dest_typdatum)) { 6446cd6a6acSopenharmony_ci free(id); 6456cd6a6acSopenharmony_ci type_datum_destroy(dest_typdatum); 6466cd6a6acSopenharmony_ci free(dest_typdatum); 6476cd6a6acSopenharmony_ci return NULL; 6486cd6a6acSopenharmony_ci } 6496cd6a6acSopenharmony_ci 6506cd6a6acSopenharmony_ci } else { 6516cd6a6acSopenharmony_ci free(id); 6526cd6a6acSopenharmony_ci if (dest_typdatum->flavor != isattr ? TYPE_ATTRIB : TYPE_TYPE) { 6536cd6a6acSopenharmony_ci return NULL; 6546cd6a6acSopenharmony_ci } 6556cd6a6acSopenharmony_ci } 6566cd6a6acSopenharmony_ci return dest_typdatum; 6576cd6a6acSopenharmony_ci} 6586cd6a6acSopenharmony_ci 6596cd6a6acSopenharmony_ci/* Return a role_datum_t for the local avrule_decl with the given ID. 6606cd6a6acSopenharmony_ci * If it does not exist, create one with the same value as 'value'. 6616cd6a6acSopenharmony_ci * This function assumes that the ID is within scope. c.f., 6626cd6a6acSopenharmony_ci * is_id_in_scope(). 6636cd6a6acSopenharmony_ci * 6646cd6a6acSopenharmony_ci * NOTE: this function usurps ownership of id afterwards. The caller 6656cd6a6acSopenharmony_ci * shall not reference it nor free() it afterwards. 6666cd6a6acSopenharmony_ci */ 6676cd6a6acSopenharmony_cirole_datum_t *get_local_role(char *id, uint32_t value, unsigned char isattr) 6686cd6a6acSopenharmony_ci{ 6696cd6a6acSopenharmony_ci role_datum_t *dest_roledatum; 6706cd6a6acSopenharmony_ci hashtab_t roles_tab; 6716cd6a6acSopenharmony_ci 6726cd6a6acSopenharmony_ci assert(stack_top->type == 1); 6736cd6a6acSopenharmony_ci 6746cd6a6acSopenharmony_ci if (stack_top->parent == NULL) { 6756cd6a6acSopenharmony_ci /* in global, so use global symbol table */ 6766cd6a6acSopenharmony_ci roles_tab = policydbp->p_roles.table; 6776cd6a6acSopenharmony_ci } else { 6786cd6a6acSopenharmony_ci roles_tab = stack_top->decl->p_roles.table; 6796cd6a6acSopenharmony_ci } 6806cd6a6acSopenharmony_ci 6816cd6a6acSopenharmony_ci dest_roledatum = hashtab_search(roles_tab, id); 6826cd6a6acSopenharmony_ci if (!dest_roledatum) { 6836cd6a6acSopenharmony_ci dest_roledatum = (role_datum_t *)malloc(sizeof(role_datum_t)); 6846cd6a6acSopenharmony_ci if (dest_roledatum == NULL) { 6856cd6a6acSopenharmony_ci free(id); 6866cd6a6acSopenharmony_ci return NULL; 6876cd6a6acSopenharmony_ci } 6886cd6a6acSopenharmony_ci 6896cd6a6acSopenharmony_ci role_datum_init(dest_roledatum); 6906cd6a6acSopenharmony_ci dest_roledatum->s.value = value; 6916cd6a6acSopenharmony_ci dest_roledatum->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE; 6926cd6a6acSopenharmony_ci 6936cd6a6acSopenharmony_ci if (hashtab_insert(roles_tab, id, dest_roledatum)) { 6946cd6a6acSopenharmony_ci free(id); 6956cd6a6acSopenharmony_ci role_datum_destroy(dest_roledatum); 6966cd6a6acSopenharmony_ci free(dest_roledatum); 6976cd6a6acSopenharmony_ci return NULL; 6986cd6a6acSopenharmony_ci } 6996cd6a6acSopenharmony_ci } else { 7006cd6a6acSopenharmony_ci free(id); 7016cd6a6acSopenharmony_ci if (dest_roledatum->flavor != isattr ? ROLE_ATTRIB : ROLE_ROLE) 7026cd6a6acSopenharmony_ci return NULL; 7036cd6a6acSopenharmony_ci } 7046cd6a6acSopenharmony_ci 7056cd6a6acSopenharmony_ci return dest_roledatum; 7066cd6a6acSopenharmony_ci} 7076cd6a6acSopenharmony_ci 7086cd6a6acSopenharmony_ci/* Attempt to require a symbol within the current scope. If currently 7096cd6a6acSopenharmony_ci * within an optional (and not its else branch), add the symbol to the 7106cd6a6acSopenharmony_ci * required list. Return 0 on success, 1 if caller needs to free() 7116cd6a6acSopenharmony_ci * datum. If symbols may not be declared here return -1. For duplicate 7126cd6a6acSopenharmony_ci * declarations return -2. For all else, including out of memory, 7136cd6a6acSopenharmony_ci * return -3.. Note that dest_value and datum_value might not be 7146cd6a6acSopenharmony_ci * restricted pointers. 7156cd6a6acSopenharmony_ci */ 7166cd6a6acSopenharmony_ciint require_symbol(uint32_t symbol_type, 7176cd6a6acSopenharmony_ci hashtab_key_t key, hashtab_datum_t datum, 7186cd6a6acSopenharmony_ci uint32_t * dest_value, uint32_t * datum_value) 7196cd6a6acSopenharmony_ci{ 7206cd6a6acSopenharmony_ci avrule_decl_t *decl = stack_top->decl; 7216cd6a6acSopenharmony_ci int ret = create_symbol(symbol_type, key, datum, dest_value, SCOPE_REQ); 7226cd6a6acSopenharmony_ci 7236cd6a6acSopenharmony_ci if (ret < 0) { 7246cd6a6acSopenharmony_ci return ret; 7256cd6a6acSopenharmony_ci } 7266cd6a6acSopenharmony_ci 7276cd6a6acSopenharmony_ci if (ebitmap_set_bit(decl->required.scope + symbol_type, 7286cd6a6acSopenharmony_ci *datum_value - 1, 1)) { 7296cd6a6acSopenharmony_ci return -3; 7306cd6a6acSopenharmony_ci } 7316cd6a6acSopenharmony_ci 7326cd6a6acSopenharmony_ci stack_top->require_given = 1; 7336cd6a6acSopenharmony_ci return ret; 7346cd6a6acSopenharmony_ci} 7356cd6a6acSopenharmony_ci 7366cd6a6acSopenharmony_ciint add_perm_to_class(uint32_t perm_value, uint32_t class_value) 7376cd6a6acSopenharmony_ci{ 7386cd6a6acSopenharmony_ci avrule_decl_t *decl = stack_top->decl; 7396cd6a6acSopenharmony_ci scope_index_t *scope; 7406cd6a6acSopenharmony_ci 7416cd6a6acSopenharmony_ci assert(perm_value >= 1); 7426cd6a6acSopenharmony_ci assert(class_value >= 1); 7436cd6a6acSopenharmony_ci scope = &decl->required; 7446cd6a6acSopenharmony_ci if (class_value > scope->class_perms_len) { 7456cd6a6acSopenharmony_ci uint32_t i; 7466cd6a6acSopenharmony_ci ebitmap_t *new_map = realloc(scope->class_perms_map, 7476cd6a6acSopenharmony_ci class_value * sizeof(*new_map)); 7486cd6a6acSopenharmony_ci if (new_map == NULL) { 7496cd6a6acSopenharmony_ci return -1; 7506cd6a6acSopenharmony_ci } 7516cd6a6acSopenharmony_ci scope->class_perms_map = new_map; 7526cd6a6acSopenharmony_ci for (i = scope->class_perms_len; i < class_value; i++) { 7536cd6a6acSopenharmony_ci ebitmap_init(scope->class_perms_map + i); 7546cd6a6acSopenharmony_ci } 7556cd6a6acSopenharmony_ci scope->class_perms_len = class_value; 7566cd6a6acSopenharmony_ci } 7576cd6a6acSopenharmony_ci if (ebitmap_set_bit(scope->class_perms_map + class_value - 1, 7586cd6a6acSopenharmony_ci perm_value - 1, 1)) { 7596cd6a6acSopenharmony_ci return -1; 7606cd6a6acSopenharmony_ci } 7616cd6a6acSopenharmony_ci return 0; 7626cd6a6acSopenharmony_ci} 7636cd6a6acSopenharmony_ci 7646cd6a6acSopenharmony_cistatic int perm_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p 7656cd6a6acSopenharmony_ci __attribute__ ((unused))) 7666cd6a6acSopenharmony_ci{ 7676cd6a6acSopenharmony_ci if (key) 7686cd6a6acSopenharmony_ci free(key); 7696cd6a6acSopenharmony_ci free(datum); 7706cd6a6acSopenharmony_ci return 0; 7716cd6a6acSopenharmony_ci} 7726cd6a6acSopenharmony_ci 7736cd6a6acSopenharmony_cistatic void class_datum_destroy(class_datum_t * cladatum) 7746cd6a6acSopenharmony_ci{ 7756cd6a6acSopenharmony_ci if (cladatum != NULL) { 7766cd6a6acSopenharmony_ci hashtab_map(cladatum->permissions.table, perm_destroy, NULL); 7776cd6a6acSopenharmony_ci hashtab_destroy(cladatum->permissions.table); 7786cd6a6acSopenharmony_ci free(cladatum); 7796cd6a6acSopenharmony_ci } 7806cd6a6acSopenharmony_ci} 7816cd6a6acSopenharmony_ci 7826cd6a6acSopenharmony_ciint require_class(int pass) 7836cd6a6acSopenharmony_ci{ 7846cd6a6acSopenharmony_ci char *class_id = queue_remove(id_queue); 7856cd6a6acSopenharmony_ci char *perm_id = NULL; 7866cd6a6acSopenharmony_ci class_datum_t *datum = NULL; 7876cd6a6acSopenharmony_ci perm_datum_t *perm = NULL; 7886cd6a6acSopenharmony_ci int ret; 7896cd6a6acSopenharmony_ci 7906cd6a6acSopenharmony_ci if (pass == 2) { 7916cd6a6acSopenharmony_ci free(class_id); 7926cd6a6acSopenharmony_ci while ((perm_id = queue_remove(id_queue)) != NULL) 7936cd6a6acSopenharmony_ci free(perm_id); 7946cd6a6acSopenharmony_ci return 0; 7956cd6a6acSopenharmony_ci } 7966cd6a6acSopenharmony_ci 7976cd6a6acSopenharmony_ci /* first add the class if it is not already there */ 7986cd6a6acSopenharmony_ci if (class_id == NULL) { 7996cd6a6acSopenharmony_ci yyerror("no class name for class definition?"); 8006cd6a6acSopenharmony_ci return -1; 8016cd6a6acSopenharmony_ci } 8026cd6a6acSopenharmony_ci 8036cd6a6acSopenharmony_ci if ((datum = calloc(1, sizeof(*datum))) == NULL || 8046cd6a6acSopenharmony_ci symtab_init(&datum->permissions, PERM_SYMTAB_SIZE)) { 8056cd6a6acSopenharmony_ci yyerror("Out of memory!"); 8066cd6a6acSopenharmony_ci class_datum_destroy(datum); 8076cd6a6acSopenharmony_ci return -1; 8086cd6a6acSopenharmony_ci } 8096cd6a6acSopenharmony_ci ret = 8106cd6a6acSopenharmony_ci require_symbol(SYM_CLASSES, class_id, datum, &datum->s.value, 8116cd6a6acSopenharmony_ci &datum->s.value); 8126cd6a6acSopenharmony_ci if (ret < 0) { 8136cd6a6acSopenharmony_ci print_error_msg(ret, SYM_CLASSES); 8146cd6a6acSopenharmony_ci free(class_id); 8156cd6a6acSopenharmony_ci class_datum_destroy(datum); 8166cd6a6acSopenharmony_ci return -1; 8176cd6a6acSopenharmony_ci } 8186cd6a6acSopenharmony_ci 8196cd6a6acSopenharmony_ci if (ret == 0) { 8206cd6a6acSopenharmony_ci /* a new class was added; reindex everything */ 8216cd6a6acSopenharmony_ci if (policydb_index_classes(policydbp)) { 8226cd6a6acSopenharmony_ci yyerror("Out of memory!"); 8236cd6a6acSopenharmony_ci return -1; 8246cd6a6acSopenharmony_ci } 8256cd6a6acSopenharmony_ci } else { 8266cd6a6acSopenharmony_ci class_datum_destroy(datum); 8276cd6a6acSopenharmony_ci datum = hashtab_search(policydbp->p_classes.table, class_id); 8286cd6a6acSopenharmony_ci assert(datum); /* the class datum should have existed */ 8296cd6a6acSopenharmony_ci free(class_id); 8306cd6a6acSopenharmony_ci } 8316cd6a6acSopenharmony_ci 8326cd6a6acSopenharmony_ci /* now add each of the permissions to this class's requirements */ 8336cd6a6acSopenharmony_ci while ((perm_id = queue_remove(id_queue)) != NULL) { 8346cd6a6acSopenharmony_ci int allocated = 0; 8356cd6a6acSopenharmony_ci 8366cd6a6acSopenharmony_ci /* Is the permission already in the table? */ 8376cd6a6acSopenharmony_ci perm = hashtab_search(datum->permissions.table, perm_id); 8386cd6a6acSopenharmony_ci if (!perm && datum->comdatum) 8396cd6a6acSopenharmony_ci perm = 8406cd6a6acSopenharmony_ci hashtab_search(datum->comdatum->permissions.table, 8416cd6a6acSopenharmony_ci perm_id); 8426cd6a6acSopenharmony_ci if (perm) { 8436cd6a6acSopenharmony_ci /* Yes, drop the name. */ 8446cd6a6acSopenharmony_ci free(perm_id); 8456cd6a6acSopenharmony_ci } else { 8466cd6a6acSopenharmony_ci /* No - allocate and insert an entry for it. */ 8476cd6a6acSopenharmony_ci if (policydbp->policy_type == POLICY_BASE) { 8486cd6a6acSopenharmony_ci yyerror2 8496cd6a6acSopenharmony_ci ("Base policy - require of permission %s without prior declaration.", 8506cd6a6acSopenharmony_ci perm_id); 8516cd6a6acSopenharmony_ci free(perm_id); 8526cd6a6acSopenharmony_ci return -1; 8536cd6a6acSopenharmony_ci } 8546cd6a6acSopenharmony_ci if (datum->permissions.nprim >= PERM_SYMTAB_SIZE) { 8556cd6a6acSopenharmony_ci yyerror2("Class %s would have too many permissions " 8566cd6a6acSopenharmony_ci "to fit in an access vector with permission %s", 8576cd6a6acSopenharmony_ci policydbp->p_class_val_to_name[datum->s.value - 1], 8586cd6a6acSopenharmony_ci perm_id); 8596cd6a6acSopenharmony_ci free(perm_id); 8606cd6a6acSopenharmony_ci return -1; 8616cd6a6acSopenharmony_ci } 8626cd6a6acSopenharmony_ci allocated = 1; 8636cd6a6acSopenharmony_ci if ((perm = malloc(sizeof(*perm))) == NULL) { 8646cd6a6acSopenharmony_ci yyerror("Out of memory!"); 8656cd6a6acSopenharmony_ci free(perm_id); 8666cd6a6acSopenharmony_ci return -1; 8676cd6a6acSopenharmony_ci } 8686cd6a6acSopenharmony_ci memset(perm, 0, sizeof(*perm)); 8696cd6a6acSopenharmony_ci ret = 8706cd6a6acSopenharmony_ci hashtab_insert(datum->permissions.table, perm_id, 8716cd6a6acSopenharmony_ci perm); 8726cd6a6acSopenharmony_ci if (ret) { 8736cd6a6acSopenharmony_ci yyerror("Out of memory!"); 8746cd6a6acSopenharmony_ci free(perm_id); 8756cd6a6acSopenharmony_ci free(perm); 8766cd6a6acSopenharmony_ci return -1; 8776cd6a6acSopenharmony_ci } 8786cd6a6acSopenharmony_ci perm->s.value = datum->permissions.nprim + 1; 8796cd6a6acSopenharmony_ci } 8806cd6a6acSopenharmony_ci 8816cd6a6acSopenharmony_ci if (add_perm_to_class(perm->s.value, datum->s.value) == -1) { 8826cd6a6acSopenharmony_ci yyerror("Out of memory!"); 8836cd6a6acSopenharmony_ci return -1; 8846cd6a6acSopenharmony_ci } 8856cd6a6acSopenharmony_ci 8866cd6a6acSopenharmony_ci /* Update number of primitives if we allocated one. */ 8876cd6a6acSopenharmony_ci if (allocated) 8886cd6a6acSopenharmony_ci datum->permissions.nprim++; 8896cd6a6acSopenharmony_ci } 8906cd6a6acSopenharmony_ci return 0; 8916cd6a6acSopenharmony_ci} 8926cd6a6acSopenharmony_ci 8936cd6a6acSopenharmony_cistatic int require_role_or_attribute(int pass, unsigned char isattr) 8946cd6a6acSopenharmony_ci{ 8956cd6a6acSopenharmony_ci char *key = NULL; 8966cd6a6acSopenharmony_ci role_datum_t *role = NULL; 8976cd6a6acSopenharmony_ci int ret; 8986cd6a6acSopenharmony_ci 8996cd6a6acSopenharmony_ci if (pass == 2) { 9006cd6a6acSopenharmony_ci free(queue_remove(id_queue)); 9016cd6a6acSopenharmony_ci return 0; 9026cd6a6acSopenharmony_ci } 9036cd6a6acSopenharmony_ci 9046cd6a6acSopenharmony_ci ret = create_role(SCOPE_REQ, isattr, &role, &key); 9056cd6a6acSopenharmony_ci if (ret < 0) { 9066cd6a6acSopenharmony_ci return -1; 9076cd6a6acSopenharmony_ci } 9086cd6a6acSopenharmony_ci 9096cd6a6acSopenharmony_ci free(key); 9106cd6a6acSopenharmony_ci 9116cd6a6acSopenharmony_ci if (ret == 0) { 9126cd6a6acSopenharmony_ci ret = ebitmap_set_bit(&role->dominates, role->s.value - 1, 1); 9136cd6a6acSopenharmony_ci if (ret != 0) { 9146cd6a6acSopenharmony_ci yyerror("Out of memory"); 9156cd6a6acSopenharmony_ci return -1; 9166cd6a6acSopenharmony_ci } 9176cd6a6acSopenharmony_ci } else { 9186cd6a6acSopenharmony_ci role_datum_destroy(role); 9196cd6a6acSopenharmony_ci free(role); 9206cd6a6acSopenharmony_ci } 9216cd6a6acSopenharmony_ci 9226cd6a6acSopenharmony_ci return 0; 9236cd6a6acSopenharmony_ci} 9246cd6a6acSopenharmony_ci 9256cd6a6acSopenharmony_ciint require_role(int pass) 9266cd6a6acSopenharmony_ci{ 9276cd6a6acSopenharmony_ci return require_role_or_attribute(pass, 0); 9286cd6a6acSopenharmony_ci} 9296cd6a6acSopenharmony_ci 9306cd6a6acSopenharmony_ciint require_attribute_role(int pass) 9316cd6a6acSopenharmony_ci{ 9326cd6a6acSopenharmony_ci return require_role_or_attribute(pass, 1); 9336cd6a6acSopenharmony_ci} 9346cd6a6acSopenharmony_ci 9356cd6a6acSopenharmony_cistatic int require_type_or_attribute(int pass, unsigned char isattr) 9366cd6a6acSopenharmony_ci{ 9376cd6a6acSopenharmony_ci type_datum_t *type = NULL; 9386cd6a6acSopenharmony_ci int ret; 9396cd6a6acSopenharmony_ci 9406cd6a6acSopenharmony_ci if (pass == 2) { 9416cd6a6acSopenharmony_ci free(queue_remove(id_queue)); 9426cd6a6acSopenharmony_ci return 0; 9436cd6a6acSopenharmony_ci } 9446cd6a6acSopenharmony_ci 9456cd6a6acSopenharmony_ci ret = create_type(SCOPE_REQ, isattr, &type); 9466cd6a6acSopenharmony_ci 9476cd6a6acSopenharmony_ci if (ret < 0) { 9486cd6a6acSopenharmony_ci return -1; 9496cd6a6acSopenharmony_ci } 9506cd6a6acSopenharmony_ci 9516cd6a6acSopenharmony_ci return 0; 9526cd6a6acSopenharmony_ci} 9536cd6a6acSopenharmony_ci 9546cd6a6acSopenharmony_ciint require_type(int pass) 9556cd6a6acSopenharmony_ci{ 9566cd6a6acSopenharmony_ci return require_type_or_attribute(pass, 0); 9576cd6a6acSopenharmony_ci} 9586cd6a6acSopenharmony_ci 9596cd6a6acSopenharmony_ciint require_attribute(int pass) 9606cd6a6acSopenharmony_ci{ 9616cd6a6acSopenharmony_ci return require_type_or_attribute(pass, 1); 9626cd6a6acSopenharmony_ci} 9636cd6a6acSopenharmony_ci 9646cd6a6acSopenharmony_ciint require_user(int pass) 9656cd6a6acSopenharmony_ci{ 9666cd6a6acSopenharmony_ci char *key = NULL; 9676cd6a6acSopenharmony_ci user_datum_t *user = NULL; 9686cd6a6acSopenharmony_ci int ret; 9696cd6a6acSopenharmony_ci 9706cd6a6acSopenharmony_ci if (pass == 1) { 9716cd6a6acSopenharmony_ci free(queue_remove(id_queue)); 9726cd6a6acSopenharmony_ci return 0; 9736cd6a6acSopenharmony_ci } 9746cd6a6acSopenharmony_ci 9756cd6a6acSopenharmony_ci ret = create_user(SCOPE_REQ, &user, &key); 9766cd6a6acSopenharmony_ci if (ret < 0) { 9776cd6a6acSopenharmony_ci return -1; 9786cd6a6acSopenharmony_ci } 9796cd6a6acSopenharmony_ci 9806cd6a6acSopenharmony_ci free(key); 9816cd6a6acSopenharmony_ci 9826cd6a6acSopenharmony_ci if (ret == 1) { 9836cd6a6acSopenharmony_ci user_datum_destroy(user); 9846cd6a6acSopenharmony_ci free(user); 9856cd6a6acSopenharmony_ci } 9866cd6a6acSopenharmony_ci 9876cd6a6acSopenharmony_ci return 0; 9886cd6a6acSopenharmony_ci} 9896cd6a6acSopenharmony_ci 9906cd6a6acSopenharmony_cistatic int require_bool_tunable(int pass, int is_tunable) 9916cd6a6acSopenharmony_ci{ 9926cd6a6acSopenharmony_ci char *id = queue_remove(id_queue); 9936cd6a6acSopenharmony_ci cond_bool_datum_t *booldatum = NULL; 9946cd6a6acSopenharmony_ci int retval; 9956cd6a6acSopenharmony_ci if (pass == 2) { 9966cd6a6acSopenharmony_ci free(id); 9976cd6a6acSopenharmony_ci return 0; 9986cd6a6acSopenharmony_ci } 9996cd6a6acSopenharmony_ci if (id == NULL) { 10006cd6a6acSopenharmony_ci yyerror("no boolean name"); 10016cd6a6acSopenharmony_ci return -1; 10026cd6a6acSopenharmony_ci } 10036cd6a6acSopenharmony_ci if ((booldatum = calloc(1, sizeof(*booldatum))) == NULL) { 10046cd6a6acSopenharmony_ci cond_destroy_bool(id, booldatum, NULL); 10056cd6a6acSopenharmony_ci yyerror("Out of memory!"); 10066cd6a6acSopenharmony_ci return -1; 10076cd6a6acSopenharmony_ci } 10086cd6a6acSopenharmony_ci if (is_tunable) 10096cd6a6acSopenharmony_ci booldatum->flags |= COND_BOOL_FLAGS_TUNABLE; 10106cd6a6acSopenharmony_ci retval = 10116cd6a6acSopenharmony_ci require_symbol(SYM_BOOLS, id, booldatum, 10126cd6a6acSopenharmony_ci &booldatum->s.value, &booldatum->s.value); 10136cd6a6acSopenharmony_ci if (retval != 0) { 10146cd6a6acSopenharmony_ci cond_destroy_bool(id, booldatum, NULL); 10156cd6a6acSopenharmony_ci if (retval < 0) { 10166cd6a6acSopenharmony_ci print_error_msg(retval, SYM_BOOLS); 10176cd6a6acSopenharmony_ci return -1; 10186cd6a6acSopenharmony_ci } 10196cd6a6acSopenharmony_ci } 10206cd6a6acSopenharmony_ci 10216cd6a6acSopenharmony_ci return 0; 10226cd6a6acSopenharmony_ci} 10236cd6a6acSopenharmony_ci 10246cd6a6acSopenharmony_ciint require_bool(int pass) 10256cd6a6acSopenharmony_ci{ 10266cd6a6acSopenharmony_ci return require_bool_tunable(pass, 0); 10276cd6a6acSopenharmony_ci} 10286cd6a6acSopenharmony_ci 10296cd6a6acSopenharmony_ciint require_tunable(int pass) 10306cd6a6acSopenharmony_ci{ 10316cd6a6acSopenharmony_ci return require_bool_tunable(pass, 1); 10326cd6a6acSopenharmony_ci} 10336cd6a6acSopenharmony_ci 10346cd6a6acSopenharmony_ciint require_sens(int pass) 10356cd6a6acSopenharmony_ci{ 10366cd6a6acSopenharmony_ci char *id = queue_remove(id_queue); 10376cd6a6acSopenharmony_ci level_datum_t *level = NULL; 10386cd6a6acSopenharmony_ci int retval; 10396cd6a6acSopenharmony_ci if (pass == 2) { 10406cd6a6acSopenharmony_ci free(id); 10416cd6a6acSopenharmony_ci return 0; 10426cd6a6acSopenharmony_ci } 10436cd6a6acSopenharmony_ci if (!id) { 10446cd6a6acSopenharmony_ci yyerror("no sensitivity name"); 10456cd6a6acSopenharmony_ci return -1; 10466cd6a6acSopenharmony_ci } 10476cd6a6acSopenharmony_ci level = malloc(sizeof(level_datum_t)); 10486cd6a6acSopenharmony_ci if (!level) { 10496cd6a6acSopenharmony_ci free(id); 10506cd6a6acSopenharmony_ci yyerror("Out of memory!"); 10516cd6a6acSopenharmony_ci return -1; 10526cd6a6acSopenharmony_ci } 10536cd6a6acSopenharmony_ci level_datum_init(level); 10546cd6a6acSopenharmony_ci level->level = malloc(sizeof(mls_level_t)); 10556cd6a6acSopenharmony_ci if (!level->level) { 10566cd6a6acSopenharmony_ci free(id); 10576cd6a6acSopenharmony_ci level_datum_destroy(level); 10586cd6a6acSopenharmony_ci free(level); 10596cd6a6acSopenharmony_ci yyerror("Out of memory!"); 10606cd6a6acSopenharmony_ci return -1; 10616cd6a6acSopenharmony_ci } 10626cd6a6acSopenharmony_ci mls_level_init(level->level); 10636cd6a6acSopenharmony_ci retval = require_symbol(SYM_LEVELS, id, level, 10646cd6a6acSopenharmony_ci &level->level->sens, &level->level->sens); 10656cd6a6acSopenharmony_ci if (retval != 0) { 10666cd6a6acSopenharmony_ci free(id); 10676cd6a6acSopenharmony_ci mls_level_destroy(level->level); 10686cd6a6acSopenharmony_ci free(level->level); 10696cd6a6acSopenharmony_ci level_datum_destroy(level); 10706cd6a6acSopenharmony_ci free(level); 10716cd6a6acSopenharmony_ci if (retval < 0) { 10726cd6a6acSopenharmony_ci print_error_msg(retval, SYM_LEVELS); 10736cd6a6acSopenharmony_ci return -1; 10746cd6a6acSopenharmony_ci } 10756cd6a6acSopenharmony_ci } 10766cd6a6acSopenharmony_ci 10776cd6a6acSopenharmony_ci return 0; 10786cd6a6acSopenharmony_ci} 10796cd6a6acSopenharmony_ci 10806cd6a6acSopenharmony_ciint require_cat(int pass) 10816cd6a6acSopenharmony_ci{ 10826cd6a6acSopenharmony_ci char *id = queue_remove(id_queue); 10836cd6a6acSopenharmony_ci cat_datum_t *cat = NULL; 10846cd6a6acSopenharmony_ci int retval; 10856cd6a6acSopenharmony_ci if (pass == 2) { 10866cd6a6acSopenharmony_ci free(id); 10876cd6a6acSopenharmony_ci return 0; 10886cd6a6acSopenharmony_ci } 10896cd6a6acSopenharmony_ci if (!id) { 10906cd6a6acSopenharmony_ci yyerror("no category name"); 10916cd6a6acSopenharmony_ci return -1; 10926cd6a6acSopenharmony_ci } 10936cd6a6acSopenharmony_ci cat = malloc(sizeof(cat_datum_t)); 10946cd6a6acSopenharmony_ci if (!cat) { 10956cd6a6acSopenharmony_ci free(id); 10966cd6a6acSopenharmony_ci yyerror("Out of memory!"); 10976cd6a6acSopenharmony_ci return -1; 10986cd6a6acSopenharmony_ci } 10996cd6a6acSopenharmony_ci cat_datum_init(cat); 11006cd6a6acSopenharmony_ci 11016cd6a6acSopenharmony_ci retval = require_symbol(SYM_CATS, id, cat, 11026cd6a6acSopenharmony_ci &cat->s.value, &cat->s.value); 11036cd6a6acSopenharmony_ci if (retval != 0) { 11046cd6a6acSopenharmony_ci free(id); 11056cd6a6acSopenharmony_ci cat_datum_destroy(cat); 11066cd6a6acSopenharmony_ci free(cat); 11076cd6a6acSopenharmony_ci if (retval < 0) { 11086cd6a6acSopenharmony_ci print_error_msg(retval, SYM_CATS); 11096cd6a6acSopenharmony_ci return -1; 11106cd6a6acSopenharmony_ci } 11116cd6a6acSopenharmony_ci } 11126cd6a6acSopenharmony_ci 11136cd6a6acSopenharmony_ci return 0; 11146cd6a6acSopenharmony_ci} 11156cd6a6acSopenharmony_ci 11166cd6a6acSopenharmony_cistatic int is_scope_in_stack(const scope_datum_t * scope, const scope_stack_t * stack) 11176cd6a6acSopenharmony_ci{ 11186cd6a6acSopenharmony_ci uint32_t i; 11196cd6a6acSopenharmony_ci if (stack == NULL) { 11206cd6a6acSopenharmony_ci return 0; /* no matching scope found */ 11216cd6a6acSopenharmony_ci } 11226cd6a6acSopenharmony_ci if (stack->type == 1) { 11236cd6a6acSopenharmony_ci const avrule_decl_t *decl = stack->decl; 11246cd6a6acSopenharmony_ci for (i = 0; i < scope->decl_ids_len; i++) { 11256cd6a6acSopenharmony_ci if (scope->decl_ids[i] == decl->decl_id) { 11266cd6a6acSopenharmony_ci return 1; 11276cd6a6acSopenharmony_ci } 11286cd6a6acSopenharmony_ci } 11296cd6a6acSopenharmony_ci } else { 11306cd6a6acSopenharmony_ci /* note that conditionals can't declare or require 11316cd6a6acSopenharmony_ci * symbols, so skip this level */ 11326cd6a6acSopenharmony_ci } 11336cd6a6acSopenharmony_ci 11346cd6a6acSopenharmony_ci /* not within scope of this stack, so try its parent */ 11356cd6a6acSopenharmony_ci return is_scope_in_stack(scope, stack->parent); 11366cd6a6acSopenharmony_ci} 11376cd6a6acSopenharmony_ci 11386cd6a6acSopenharmony_ciint is_id_in_scope(uint32_t symbol_type, const_hashtab_key_t id) 11396cd6a6acSopenharmony_ci{ 11406cd6a6acSopenharmony_ci const scope_datum_t *scope = 11416cd6a6acSopenharmony_ci (scope_datum_t *) hashtab_search(policydbp->scope[symbol_type]. 11426cd6a6acSopenharmony_ci table, id); 11436cd6a6acSopenharmony_ci if (scope == NULL) { 11446cd6a6acSopenharmony_ci return 1; /* id is not known, so return success */ 11456cd6a6acSopenharmony_ci } 11466cd6a6acSopenharmony_ci return is_scope_in_stack(scope, stack_top); 11476cd6a6acSopenharmony_ci} 11486cd6a6acSopenharmony_ci 11496cd6a6acSopenharmony_cistatic int is_perm_in_scope_index(uint32_t perm_value, uint32_t class_value, 11506cd6a6acSopenharmony_ci const scope_index_t * scope) 11516cd6a6acSopenharmony_ci{ 11526cd6a6acSopenharmony_ci if (class_value > scope->class_perms_len) { 11536cd6a6acSopenharmony_ci return 1; 11546cd6a6acSopenharmony_ci } 11556cd6a6acSopenharmony_ci if (ebitmap_get_bit(scope->class_perms_map + class_value - 1, 11566cd6a6acSopenharmony_ci perm_value - 1)) { 11576cd6a6acSopenharmony_ci return 1; 11586cd6a6acSopenharmony_ci } 11596cd6a6acSopenharmony_ci return 0; 11606cd6a6acSopenharmony_ci} 11616cd6a6acSopenharmony_ci 11626cd6a6acSopenharmony_cistatic int is_perm_in_stack(uint32_t perm_value, uint32_t class_value, 11636cd6a6acSopenharmony_ci const scope_stack_t * stack) 11646cd6a6acSopenharmony_ci{ 11656cd6a6acSopenharmony_ci if (stack == NULL) { 11666cd6a6acSopenharmony_ci return 0; /* no matching scope found */ 11676cd6a6acSopenharmony_ci } 11686cd6a6acSopenharmony_ci if (stack->type == 1) { 11696cd6a6acSopenharmony_ci avrule_decl_t *decl = stack->decl; 11706cd6a6acSopenharmony_ci if (is_perm_in_scope_index 11716cd6a6acSopenharmony_ci (perm_value, class_value, &decl->required) 11726cd6a6acSopenharmony_ci || is_perm_in_scope_index(perm_value, class_value, 11736cd6a6acSopenharmony_ci &decl->declared)) { 11746cd6a6acSopenharmony_ci return 1; 11756cd6a6acSopenharmony_ci } 11766cd6a6acSopenharmony_ci } else { 11776cd6a6acSopenharmony_ci /* note that conditionals can't declare or require 11786cd6a6acSopenharmony_ci * symbols, so skip this level */ 11796cd6a6acSopenharmony_ci } 11806cd6a6acSopenharmony_ci 11816cd6a6acSopenharmony_ci /* not within scope of this stack, so try its parent */ 11826cd6a6acSopenharmony_ci return is_perm_in_stack(perm_value, class_value, stack->parent); 11836cd6a6acSopenharmony_ci} 11846cd6a6acSopenharmony_ci 11856cd6a6acSopenharmony_ciint is_perm_in_scope(const_hashtab_key_t perm_id, const_hashtab_key_t class_id) 11866cd6a6acSopenharmony_ci{ 11876cd6a6acSopenharmony_ci const class_datum_t *cladatum = 11886cd6a6acSopenharmony_ci (class_datum_t *) hashtab_search(policydbp->p_classes.table, 11896cd6a6acSopenharmony_ci class_id); 11906cd6a6acSopenharmony_ci const perm_datum_t *perdatum; 11916cd6a6acSopenharmony_ci if (cladatum == NULL) { 11926cd6a6acSopenharmony_ci return 1; 11936cd6a6acSopenharmony_ci } 11946cd6a6acSopenharmony_ci perdatum = (perm_datum_t *) hashtab_search(cladatum->permissions.table, 11956cd6a6acSopenharmony_ci perm_id); 11966cd6a6acSopenharmony_ci if (perdatum == NULL) { 11976cd6a6acSopenharmony_ci return 1; 11986cd6a6acSopenharmony_ci } 11996cd6a6acSopenharmony_ci return is_perm_in_stack(perdatum->s.value, cladatum->s.value, 12006cd6a6acSopenharmony_ci stack_top); 12016cd6a6acSopenharmony_ci} 12026cd6a6acSopenharmony_ci 12036cd6a6acSopenharmony_cicond_list_t *get_current_cond_list(cond_list_t * cond) 12046cd6a6acSopenharmony_ci{ 12056cd6a6acSopenharmony_ci /* FIX ME: do something different here if in a nested 12066cd6a6acSopenharmony_ci * conditional? */ 12076cd6a6acSopenharmony_ci avrule_decl_t *decl = stack_top->decl; 12086cd6a6acSopenharmony_ci return get_decl_cond_list(policydbp, decl, cond); 12096cd6a6acSopenharmony_ci} 12106cd6a6acSopenharmony_ci 12116cd6a6acSopenharmony_ci/* Append the new conditional node to the existing ones. During 12126cd6a6acSopenharmony_ci * expansion the list will be reversed -- i.e., the last AV rule will 12136cd6a6acSopenharmony_ci * be the first one listed in the policy. This matches the behavior 12146cd6a6acSopenharmony_ci * of the upstream compiler. */ 12156cd6a6acSopenharmony_civoid append_cond_list(cond_list_t * cond) 12166cd6a6acSopenharmony_ci{ 12176cd6a6acSopenharmony_ci cond_list_t *old_cond = get_current_cond_list(cond); 12186cd6a6acSopenharmony_ci avrule_t *tmp; 12196cd6a6acSopenharmony_ci assert(old_cond != NULL); /* probably out of memory */ 12206cd6a6acSopenharmony_ci if (old_cond->avtrue_list == NULL) { 12216cd6a6acSopenharmony_ci old_cond->avtrue_list = cond->avtrue_list; 12226cd6a6acSopenharmony_ci } else { 12236cd6a6acSopenharmony_ci for (tmp = old_cond->avtrue_list; tmp->next != NULL; 12246cd6a6acSopenharmony_ci tmp = tmp->next) ; 12256cd6a6acSopenharmony_ci tmp->next = cond->avtrue_list; 12266cd6a6acSopenharmony_ci } 12276cd6a6acSopenharmony_ci if (old_cond->avfalse_list == NULL) { 12286cd6a6acSopenharmony_ci old_cond->avfalse_list = cond->avfalse_list; 12296cd6a6acSopenharmony_ci } else { 12306cd6a6acSopenharmony_ci for (tmp = old_cond->avfalse_list; tmp->next != NULL; 12316cd6a6acSopenharmony_ci tmp = tmp->next) ; 12326cd6a6acSopenharmony_ci tmp->next = cond->avfalse_list; 12336cd6a6acSopenharmony_ci } 12346cd6a6acSopenharmony_ci 12356cd6a6acSopenharmony_ci old_cond->flags |= cond->flags; 12366cd6a6acSopenharmony_ci} 12376cd6a6acSopenharmony_ci 12386cd6a6acSopenharmony_civoid append_avrule(avrule_t * avrule) 12396cd6a6acSopenharmony_ci{ 12406cd6a6acSopenharmony_ci avrule_decl_t *decl = stack_top->decl; 12416cd6a6acSopenharmony_ci 12426cd6a6acSopenharmony_ci /* currently avrules follow a completely different code path 12436cd6a6acSopenharmony_ci * for handling avrules and compute types 12446cd6a6acSopenharmony_ci * (define_cond_avrule_te_avtab, define_cond_compute_type); 12456cd6a6acSopenharmony_ci * therefore there ought never be a conditional on top of the 12466cd6a6acSopenharmony_ci * scope stack */ 12476cd6a6acSopenharmony_ci assert(stack_top->type == 1); 12486cd6a6acSopenharmony_ci 12496cd6a6acSopenharmony_ci if (stack_top->last_avrule == NULL) { 12506cd6a6acSopenharmony_ci decl->avrules = avrule; 12516cd6a6acSopenharmony_ci } else { 12526cd6a6acSopenharmony_ci stack_top->last_avrule->next = avrule; 12536cd6a6acSopenharmony_ci } 12546cd6a6acSopenharmony_ci stack_top->last_avrule = avrule; 12556cd6a6acSopenharmony_ci} 12566cd6a6acSopenharmony_ci 12576cd6a6acSopenharmony_ci/* this doesn't actually append, but really prepends it */ 12586cd6a6acSopenharmony_civoid append_role_trans(role_trans_rule_t * role_tr_rules) 12596cd6a6acSopenharmony_ci{ 12606cd6a6acSopenharmony_ci avrule_decl_t *decl = stack_top->decl; 12616cd6a6acSopenharmony_ci 12626cd6a6acSopenharmony_ci /* role transitions are not allowed within conditionals */ 12636cd6a6acSopenharmony_ci assert(stack_top->type == 1); 12646cd6a6acSopenharmony_ci 12656cd6a6acSopenharmony_ci role_tr_rules->next = decl->role_tr_rules; 12666cd6a6acSopenharmony_ci decl->role_tr_rules = role_tr_rules; 12676cd6a6acSopenharmony_ci} 12686cd6a6acSopenharmony_ci 12696cd6a6acSopenharmony_ci/* this doesn't actually append, but really prepends it */ 12706cd6a6acSopenharmony_civoid append_role_allow(role_allow_rule_t * role_allow_rules) 12716cd6a6acSopenharmony_ci{ 12726cd6a6acSopenharmony_ci avrule_decl_t *decl = stack_top->decl; 12736cd6a6acSopenharmony_ci 12746cd6a6acSopenharmony_ci /* role allows are not allowed within conditionals */ 12756cd6a6acSopenharmony_ci assert(stack_top->type == 1); 12766cd6a6acSopenharmony_ci 12776cd6a6acSopenharmony_ci role_allow_rules->next = decl->role_allow_rules; 12786cd6a6acSopenharmony_ci decl->role_allow_rules = role_allow_rules; 12796cd6a6acSopenharmony_ci} 12806cd6a6acSopenharmony_ci 12816cd6a6acSopenharmony_ci/* this doesn't actually append, but really prepends it */ 12826cd6a6acSopenharmony_civoid append_filename_trans(filename_trans_rule_t * filename_trans_rules) 12836cd6a6acSopenharmony_ci{ 12846cd6a6acSopenharmony_ci avrule_decl_t *decl = stack_top->decl; 12856cd6a6acSopenharmony_ci 12866cd6a6acSopenharmony_ci /* filename transitions are not allowed within conditionals */ 12876cd6a6acSopenharmony_ci assert(stack_top->type == 1); 12886cd6a6acSopenharmony_ci 12896cd6a6acSopenharmony_ci filename_trans_rules->next = decl->filename_trans_rules; 12906cd6a6acSopenharmony_ci decl->filename_trans_rules = filename_trans_rules; 12916cd6a6acSopenharmony_ci} 12926cd6a6acSopenharmony_ci 12936cd6a6acSopenharmony_ci/* this doesn't actually append, but really prepends it */ 12946cd6a6acSopenharmony_civoid append_range_trans(range_trans_rule_t * range_tr_rules) 12956cd6a6acSopenharmony_ci{ 12966cd6a6acSopenharmony_ci avrule_decl_t *decl = stack_top->decl; 12976cd6a6acSopenharmony_ci 12986cd6a6acSopenharmony_ci /* range transitions are not allowed within conditionals */ 12996cd6a6acSopenharmony_ci assert(stack_top->type == 1); 13006cd6a6acSopenharmony_ci 13016cd6a6acSopenharmony_ci range_tr_rules->next = decl->range_tr_rules; 13026cd6a6acSopenharmony_ci decl->range_tr_rules = range_tr_rules; 13036cd6a6acSopenharmony_ci} 13046cd6a6acSopenharmony_ci 13056cd6a6acSopenharmony_ciint begin_optional(int pass) 13066cd6a6acSopenharmony_ci{ 13076cd6a6acSopenharmony_ci avrule_block_t *block = NULL; 13086cd6a6acSopenharmony_ci avrule_decl_t *decl; 13096cd6a6acSopenharmony_ci if (pass == 1) { 13106cd6a6acSopenharmony_ci /* allocate a new avrule block for this optional block */ 13116cd6a6acSopenharmony_ci if ((block = avrule_block_create()) == NULL || 13126cd6a6acSopenharmony_ci (decl = avrule_decl_create(next_decl_id)) == NULL) { 13136cd6a6acSopenharmony_ci goto cleanup; 13146cd6a6acSopenharmony_ci } 13156cd6a6acSopenharmony_ci block->flags |= AVRULE_OPTIONAL; 13166cd6a6acSopenharmony_ci block->branch_list = decl; 13176cd6a6acSopenharmony_ci last_block->next = block; 13186cd6a6acSopenharmony_ci } else { 13196cd6a6acSopenharmony_ci /* select the next block from the chain built during pass 1 */ 13206cd6a6acSopenharmony_ci block = last_block->next; 13216cd6a6acSopenharmony_ci assert(block != NULL && 13226cd6a6acSopenharmony_ci block->branch_list != NULL && 13236cd6a6acSopenharmony_ci block->branch_list->decl_id == next_decl_id); 13246cd6a6acSopenharmony_ci decl = block->branch_list; 13256cd6a6acSopenharmony_ci } 13266cd6a6acSopenharmony_ci if (push_stack(1, block, decl) == -1) { 13276cd6a6acSopenharmony_ci goto cleanup; 13286cd6a6acSopenharmony_ci } 13296cd6a6acSopenharmony_ci stack_top->last_avrule = NULL; 13306cd6a6acSopenharmony_ci last_block = block; 13316cd6a6acSopenharmony_ci next_decl_id++; 13326cd6a6acSopenharmony_ci return 0; 13336cd6a6acSopenharmony_ci cleanup: 13346cd6a6acSopenharmony_ci yyerror("Out of memory!"); 13356cd6a6acSopenharmony_ci avrule_block_destroy(block); 13366cd6a6acSopenharmony_ci return -1; 13376cd6a6acSopenharmony_ci} 13386cd6a6acSopenharmony_ci 13396cd6a6acSopenharmony_ciint end_optional(int pass __attribute__ ((unused))) 13406cd6a6acSopenharmony_ci{ 13416cd6a6acSopenharmony_ci /* once nested conditionals are allowed, do the stack unfolding here */ 13426cd6a6acSopenharmony_ci pop_stack(); 13436cd6a6acSopenharmony_ci return 0; 13446cd6a6acSopenharmony_ci} 13456cd6a6acSopenharmony_ci 13466cd6a6acSopenharmony_ciint begin_optional_else(int pass) 13476cd6a6acSopenharmony_ci{ 13486cd6a6acSopenharmony_ci avrule_decl_t *decl; 13496cd6a6acSopenharmony_ci assert(stack_top->type == 1 && stack_top->in_else == 0); 13506cd6a6acSopenharmony_ci if (pass == 1) { 13516cd6a6acSopenharmony_ci /* allocate a new declaration and add it to the 13526cd6a6acSopenharmony_ci * current chain */ 13536cd6a6acSopenharmony_ci if ((decl = avrule_decl_create(next_decl_id)) == NULL) { 13546cd6a6acSopenharmony_ci yyerror("Out of memory!"); 13556cd6a6acSopenharmony_ci return -1; 13566cd6a6acSopenharmony_ci } 13576cd6a6acSopenharmony_ci stack_top->decl->next = decl; 13586cd6a6acSopenharmony_ci } else { 13596cd6a6acSopenharmony_ci /* pick the (hopefully last) declaration of this 13606cd6a6acSopenharmony_ci avrule block, built from pass 1 */ 13616cd6a6acSopenharmony_ci decl = stack_top->decl->next; 13626cd6a6acSopenharmony_ci assert(decl != NULL && 13636cd6a6acSopenharmony_ci decl->next == NULL && decl->decl_id == next_decl_id); 13646cd6a6acSopenharmony_ci } 13656cd6a6acSopenharmony_ci stack_top->in_else = 1; 13666cd6a6acSopenharmony_ci stack_top->decl = decl; 13676cd6a6acSopenharmony_ci stack_top->last_avrule = NULL; 13686cd6a6acSopenharmony_ci stack_top->require_given = 0; 13696cd6a6acSopenharmony_ci next_decl_id++; 13706cd6a6acSopenharmony_ci return 0; 13716cd6a6acSopenharmony_ci} 13726cd6a6acSopenharmony_ci 13736cd6a6acSopenharmony_cistatic int copy_requirements(avrule_decl_t * dest, const scope_stack_t * stack) 13746cd6a6acSopenharmony_ci{ 13756cd6a6acSopenharmony_ci uint32_t i; 13766cd6a6acSopenharmony_ci if (stack == NULL) { 13776cd6a6acSopenharmony_ci return 0; 13786cd6a6acSopenharmony_ci } 13796cd6a6acSopenharmony_ci if (stack->type == 1) { 13806cd6a6acSopenharmony_ci const scope_index_t *src_scope = &stack->decl->required; 13816cd6a6acSopenharmony_ci scope_index_t *dest_scope = &dest->required; 13826cd6a6acSopenharmony_ci for (i = 0; i < SYM_NUM; i++) { 13836cd6a6acSopenharmony_ci const ebitmap_t *src_bitmap = &src_scope->scope[i]; 13846cd6a6acSopenharmony_ci ebitmap_t *dest_bitmap = &dest_scope->scope[i]; 13856cd6a6acSopenharmony_ci if (ebitmap_union(dest_bitmap, src_bitmap)) { 13866cd6a6acSopenharmony_ci yyerror("Out of memory!"); 13876cd6a6acSopenharmony_ci return -1; 13886cd6a6acSopenharmony_ci } 13896cd6a6acSopenharmony_ci } 13906cd6a6acSopenharmony_ci /* now copy class permissions */ 13916cd6a6acSopenharmony_ci if (src_scope->class_perms_len > dest_scope->class_perms_len) { 13926cd6a6acSopenharmony_ci ebitmap_t *new_map = 13936cd6a6acSopenharmony_ci realloc(dest_scope->class_perms_map, 13946cd6a6acSopenharmony_ci src_scope->class_perms_len * 13956cd6a6acSopenharmony_ci sizeof(*new_map)); 13966cd6a6acSopenharmony_ci if (new_map == NULL) { 13976cd6a6acSopenharmony_ci yyerror("Out of memory!"); 13986cd6a6acSopenharmony_ci return -1; 13996cd6a6acSopenharmony_ci } 14006cd6a6acSopenharmony_ci dest_scope->class_perms_map = new_map; 14016cd6a6acSopenharmony_ci for (i = dest_scope->class_perms_len; 14026cd6a6acSopenharmony_ci i < src_scope->class_perms_len; i++) { 14036cd6a6acSopenharmony_ci ebitmap_init(dest_scope->class_perms_map + i); 14046cd6a6acSopenharmony_ci } 14056cd6a6acSopenharmony_ci dest_scope->class_perms_len = 14066cd6a6acSopenharmony_ci src_scope->class_perms_len; 14076cd6a6acSopenharmony_ci } 14086cd6a6acSopenharmony_ci for (i = 0; i < src_scope->class_perms_len; i++) { 14096cd6a6acSopenharmony_ci const ebitmap_t *src_bitmap = &src_scope->class_perms_map[i]; 14106cd6a6acSopenharmony_ci ebitmap_t *dest_bitmap = 14116cd6a6acSopenharmony_ci &dest_scope->class_perms_map[i]; 14126cd6a6acSopenharmony_ci if (ebitmap_union(dest_bitmap, src_bitmap)) { 14136cd6a6acSopenharmony_ci yyerror("Out of memory!"); 14146cd6a6acSopenharmony_ci return -1; 14156cd6a6acSopenharmony_ci } 14166cd6a6acSopenharmony_ci } 14176cd6a6acSopenharmony_ci } 14186cd6a6acSopenharmony_ci return copy_requirements(dest, stack->parent); 14196cd6a6acSopenharmony_ci} 14206cd6a6acSopenharmony_ci 14216cd6a6acSopenharmony_ci/* During pass 1, check that at least one thing was required within 14226cd6a6acSopenharmony_ci * this block, for those places where a REQUIRED is necessary. During 14236cd6a6acSopenharmony_ci * pass 2, have this block inherit its parents' requirements. Return 14246cd6a6acSopenharmony_ci * 0 on success, -1 on failure. */ 14256cd6a6acSopenharmony_ciint end_avrule_block(int pass) 14266cd6a6acSopenharmony_ci{ 14276cd6a6acSopenharmony_ci avrule_decl_t *decl = stack_top->decl; 14286cd6a6acSopenharmony_ci assert(stack_top->type == 1); 14296cd6a6acSopenharmony_ci if (pass == 2) { 14306cd6a6acSopenharmony_ci /* this avrule_decl inherits all of its parents' 14316cd6a6acSopenharmony_ci * requirements */ 14326cd6a6acSopenharmony_ci if (copy_requirements(decl, stack_top->parent) == -1) { 14336cd6a6acSopenharmony_ci return -1; 14346cd6a6acSopenharmony_ci } 14356cd6a6acSopenharmony_ci return 0; 14366cd6a6acSopenharmony_ci } 14376cd6a6acSopenharmony_ci if (!stack_top->in_else && !stack_top->require_given) { 14386cd6a6acSopenharmony_ci if (policydbp->policy_type == POLICY_BASE 14396cd6a6acSopenharmony_ci && stack_top->parent != NULL) { 14406cd6a6acSopenharmony_ci /* if this is base no require should be in the global block */ 14416cd6a6acSopenharmony_ci return 0; 14426cd6a6acSopenharmony_ci } else { 14436cd6a6acSopenharmony_ci /* non-ELSE branches must have at least one thing required */ 14446cd6a6acSopenharmony_ci yyerror("This block has no require section."); 14456cd6a6acSopenharmony_ci return -1; 14466cd6a6acSopenharmony_ci } 14476cd6a6acSopenharmony_ci } 14486cd6a6acSopenharmony_ci return 0; 14496cd6a6acSopenharmony_ci} 14506cd6a6acSopenharmony_ci 14516cd6a6acSopenharmony_ci/* Push a new scope on to the stack and update the 'last' pointer. 14526cd6a6acSopenharmony_ci * Return 0 on success, -1 if out * of memory. */ 14536cd6a6acSopenharmony_cistatic int push_stack(int stack_type, ...) 14546cd6a6acSopenharmony_ci{ 14556cd6a6acSopenharmony_ci scope_stack_t *s = calloc(1, sizeof(*s)); 14566cd6a6acSopenharmony_ci va_list ap; 14576cd6a6acSopenharmony_ci if (s == NULL) { 14586cd6a6acSopenharmony_ci return -1; 14596cd6a6acSopenharmony_ci } 14606cd6a6acSopenharmony_ci va_start(ap, stack_type); 14616cd6a6acSopenharmony_ci switch (s->type = stack_type) { 14626cd6a6acSopenharmony_ci case 1:{ 14636cd6a6acSopenharmony_ci s->u.avrule = va_arg(ap, avrule_block_t *); 14646cd6a6acSopenharmony_ci s->decl = va_arg(ap, avrule_decl_t *); 14656cd6a6acSopenharmony_ci break; 14666cd6a6acSopenharmony_ci } 14676cd6a6acSopenharmony_ci case 2:{ 14686cd6a6acSopenharmony_ci s->u.cond_list = va_arg(ap, cond_list_t *); 14696cd6a6acSopenharmony_ci break; 14706cd6a6acSopenharmony_ci } 14716cd6a6acSopenharmony_ci default: 14726cd6a6acSopenharmony_ci /* invalid stack type given */ 14736cd6a6acSopenharmony_ci assert(0); 14746cd6a6acSopenharmony_ci } 14756cd6a6acSopenharmony_ci va_end(ap); 14766cd6a6acSopenharmony_ci s->parent = stack_top; 14776cd6a6acSopenharmony_ci s->child = NULL; 14786cd6a6acSopenharmony_ci stack_top = s; 14796cd6a6acSopenharmony_ci return 0; 14806cd6a6acSopenharmony_ci} 14816cd6a6acSopenharmony_ci 14826cd6a6acSopenharmony_ci/* Pop off the most recently added from the stack. Update the 'last' 14836cd6a6acSopenharmony_ci * pointer. */ 14846cd6a6acSopenharmony_cistatic void pop_stack(void) 14856cd6a6acSopenharmony_ci{ 14866cd6a6acSopenharmony_ci scope_stack_t *parent; 14876cd6a6acSopenharmony_ci assert(stack_top != NULL); 14886cd6a6acSopenharmony_ci parent = stack_top->parent; 14896cd6a6acSopenharmony_ci if (parent != NULL) { 14906cd6a6acSopenharmony_ci parent->child = NULL; 14916cd6a6acSopenharmony_ci } 14926cd6a6acSopenharmony_ci free(stack_top); 14936cd6a6acSopenharmony_ci stack_top = parent; 14946cd6a6acSopenharmony_ci} 1495