| /* |
| * Copyright 2011 Tresys Technology, LLC. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS |
| * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
| * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
| * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * The views and conclusions contained in the software and documentation are those |
| * of the authors and should not be interpreted as representing official policies, |
| * either expressed or implied, of Tresys Technology, LLC. |
| */ |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <assert.h> |
| #include <netinet/in.h> |
| #ifndef IPPROTO_DCCP |
| #define IPPROTO_DCCP 33 |
| #endif |
| #ifndef IPPROTO_SCTP |
| #define IPPROTO_SCTP 132 |
| #endif |
| |
| #include <sepol/policydb/policydb.h> |
| #include <sepol/policydb/polcaps.h> |
| #include <sepol/policydb/conditional.h> |
| #include <sepol/policydb/constraint.h> |
| #include <sepol/policydb/expand.h> |
| #include <sepol/policydb/hierarchy.h> |
| |
| #include "cil_internal.h" |
| #include "cil_flavor.h" |
| #include "cil_log.h" |
| #include "cil_mem.h" |
| #include "cil_tree.h" |
| #include "cil_binary.h" |
| #include "cil_symtab.h" |
| #include "cil_find.h" |
| #include "cil_build_ast.h" |
| |
| #define ROLE_TRANS_TABLE_SIZE (1 << 10) |
| #define AVRULEX_TABLE_SIZE (1 << 10) |
| #define PERMS_PER_CLASS 32 |
| |
| struct cil_args_binary { |
| const struct cil_db *db; |
| policydb_t *pdb; |
| struct cil_list *neverallows; |
| int pass; |
| hashtab_t role_trans_table; |
| hashtab_t avrulex_ioctl_table; |
| void **type_value_to_cil; |
| }; |
| |
| struct cil_args_booleanif { |
| const struct cil_db *db; |
| policydb_t *pdb; |
| cond_node_t *cond_node; |
| enum cil_flavor cond_flavor; |
| }; |
| |
| static int __cil_get_sepol_user_datum(policydb_t *pdb, struct cil_symtab_datum *datum, user_datum_t **sepol_user) |
| { |
| *sepol_user = hashtab_search(pdb->p_users.table, datum->fqn); |
| if (*sepol_user == NULL) { |
| cil_log(CIL_INFO, "Failed to find user %s in sepol hashtab\n", datum->fqn); |
| return SEPOL_ERR; |
| } |
| |
| return SEPOL_OK; |
| } |
| |
| static int __cil_get_sepol_role_datum(policydb_t *pdb, struct cil_symtab_datum *datum, role_datum_t **sepol_role) |
| { |
| *sepol_role = hashtab_search(pdb->p_roles.table, datum->fqn); |
| if (*sepol_role == NULL) { |
| cil_log(CIL_INFO, "Failed to find role %s in sepol hashtab\n", datum->fqn); |
| return SEPOL_ERR; |
| } |
| |
| return SEPOL_OK; |
| } |
| |
| static int __cil_get_sepol_type_datum(policydb_t *pdb, struct cil_symtab_datum *datum, type_datum_t **sepol_type) |
| { |
| *sepol_type = hashtab_search(pdb->p_types.table, datum->fqn); |
| if (*sepol_type == NULL) { |
| cil_log(CIL_INFO, "Failed to find type %s in sepol hashtab\n", datum->fqn); |
| return SEPOL_ERR; |
| } |
| |
| return SEPOL_OK; |
| } |
| |
| static int __cil_get_sepol_class_datum(policydb_t *pdb, struct cil_symtab_datum *datum, class_datum_t **sepol_class) |
| { |
| *sepol_class = hashtab_search(pdb->p_classes.table, datum->fqn); |
| if (*sepol_class == NULL) { |
| cil_log(CIL_INFO, "Failed to find class %s in sepol hashtab\n", datum->fqn); |
| return SEPOL_ERR; |
| } |
| |
| return SEPOL_OK; |
| } |
| |
| static int __cil_get_sepol_cat_datum(policydb_t *pdb, struct cil_symtab_datum *datum, cat_datum_t **sepol_cat) |
| { |
| *sepol_cat = hashtab_search(pdb->p_cats.table, datum->fqn); |
| if (*sepol_cat == NULL) { |
| cil_log(CIL_INFO, "Failed to find category %s in sepol hashtab\n", datum->fqn); |
| return SEPOL_ERR; |
| } |
| |
| return SEPOL_OK; |
| } |
| |
| static int __cil_get_sepol_level_datum(policydb_t *pdb, struct cil_symtab_datum *datum, level_datum_t **sepol_level) |
| { |
| *sepol_level = hashtab_search(pdb->p_levels.table, datum->fqn); |
| if (*sepol_level == NULL) { |
| cil_log(CIL_INFO, "Failed to find level %s in sepol hashtab\n", datum->fqn); |
| return SEPOL_ERR; |
| } |
| |
| return SEPOL_OK; |
| } |
| |
| static int __cil_expand_user(struct cil_symtab_datum *datum, ebitmap_t *new) |
| { |
| struct cil_tree_node *node = NODE(datum); |
| struct cil_user *user = NULL; |
| struct cil_userattribute *attr = NULL; |
| |
| if (node->flavor == CIL_USERATTRIBUTE) { |
| attr = (struct cil_userattribute *)datum; |
| if (ebitmap_cpy(new, attr->users)) { |
| cil_log(CIL_ERR, "Failed to copy user bits\n"); |
| goto exit; |
| } |
| } else { |
| user = (struct cil_user *)datum; |
| ebitmap_init(new); |
| if (ebitmap_set_bit(new, user->value, 1)) { |
| cil_log(CIL_ERR, "Failed to set user bit\n"); |
| ebitmap_destroy(new); |
| goto exit; |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return SEPOL_ERR; |
| } |
| |
| static int __cil_expand_role(struct cil_symtab_datum *datum, ebitmap_t *new) |
| { |
| struct cil_tree_node *node = NODE(datum); |
| |
| if (node->flavor == CIL_ROLEATTRIBUTE) { |
| struct cil_roleattribute *attr = (struct cil_roleattribute *)datum; |
| if (ebitmap_cpy(new, attr->roles)) { |
| cil_log(CIL_ERR, "Failed to copy role bits\n"); |
| goto exit; |
| } |
| } else { |
| struct cil_role *role = (struct cil_role *)datum; |
| ebitmap_init(new); |
| if (ebitmap_set_bit(new, role->value, 1)) { |
| cil_log(CIL_ERR, "Failed to set role bit\n"); |
| ebitmap_destroy(new); |
| goto exit; |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return SEPOL_ERR; |
| } |
| |
| static int __cil_expand_type(struct cil_symtab_datum *datum, ebitmap_t *new) |
| { |
| struct cil_tree_node *node = NODE(datum); |
| |
| if (node->flavor == CIL_TYPEATTRIBUTE) { |
| struct cil_typeattribute *attr = (struct cil_typeattribute *)datum; |
| if (ebitmap_cpy(new, attr->types)) { |
| cil_log(CIL_ERR, "Failed to copy type bits\n"); |
| goto exit; |
| } |
| } else { |
| struct cil_type *type = (struct cil_type *)datum; |
| ebitmap_init(new); |
| if (ebitmap_set_bit(new, type->value, 1)) { |
| cil_log(CIL_ERR, "Failed to set type bit\n"); |
| ebitmap_destroy(new); |
| goto exit; |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return SEPOL_ERR; |
| } |
| |
| static ocontext_t *cil_add_ocontext(ocontext_t **head, ocontext_t **tail) |
| { |
| ocontext_t *new = cil_malloc(sizeof(ocontext_t)); |
| memset(new, 0, sizeof(ocontext_t)); |
| if (*tail) { |
| (*tail)->next = new; |
| } else { |
| *head = new; |
| } |
| *tail = new; |
| |
| return new; |
| } |
| |
| int cil_common_to_policydb(policydb_t *pdb, struct cil_class *cil_common, common_datum_t **common_out) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t value = 0; |
| char *key = NULL; |
| struct cil_tree_node *node = cil_common->datum.nodes->head->data; |
| struct cil_tree_node *cil_perm = node->cl_head; |
| common_datum_t *sepol_common = cil_malloc(sizeof(*sepol_common)); |
| memset(sepol_common, 0, sizeof(common_datum_t)); |
| |
| key = cil_strdup(cil_common->datum.fqn); |
| rc = symtab_insert(pdb, SYM_COMMONS, key, sepol_common, SCOPE_DECL, 0, &value); |
| if (rc != SEPOL_OK) { |
| free(sepol_common); |
| goto exit; |
| } |
| sepol_common->s.value = value; |
| |
| rc = symtab_init(&sepol_common->permissions, PERM_SYMTAB_SIZE); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| while (cil_perm != NULL) { |
| struct cil_perm *curr = cil_perm->data; |
| perm_datum_t *sepol_perm = cil_malloc(sizeof(*sepol_perm)); |
| memset(sepol_perm, 0, sizeof(perm_datum_t)); |
| |
| key = cil_strdup(curr->datum.fqn); |
| rc = hashtab_insert(sepol_common->permissions.table, key, sepol_perm); |
| if (rc != SEPOL_OK) { |
| free(sepol_perm); |
| goto exit; |
| } |
| sepol_perm->s.value = sepol_common->permissions.nprim + 1; |
| sepol_common->permissions.nprim++; |
| cil_perm = cil_perm->next; |
| } |
| |
| *common_out = sepol_common; |
| |
| return SEPOL_OK; |
| |
| exit: |
| free(key); |
| return rc; |
| } |
| |
| static int cil_classorder_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[]) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_list_item *curr_class; |
| |
| cil_list_for_each(curr_class, db->classorder) { |
| struct cil_class *cil_class = curr_class->data; |
| uint32_t value = 0; |
| char *key = NULL; |
| int class_index; |
| struct cil_tree_node *curr; |
| common_datum_t *sepol_common = NULL; |
| class_datum_t *sepol_class = cil_malloc(sizeof(*sepol_class)); |
| memset(sepol_class, 0, sizeof(class_datum_t)); |
| |
| key = cil_strdup(cil_class->datum.fqn); |
| rc = symtab_insert(pdb, SYM_CLASSES, key, sepol_class, SCOPE_DECL, 0, &value); |
| if (rc != SEPOL_OK) { |
| free(sepol_class); |
| free(key); |
| goto exit; |
| } |
| sepol_class->s.value = value; |
| class_index = value; |
| class_value_to_cil[class_index] = cil_class; |
| |
| rc = symtab_init(&sepol_class->permissions, PERM_SYMTAB_SIZE); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| if (cil_class->common != NULL) { |
| int i; |
| struct cil_class *cil_common = cil_class->common; |
| |
| key = cil_class->common->datum.fqn; |
| sepol_common = hashtab_search(pdb->p_commons.table, key); |
| if (sepol_common == NULL) { |
| rc = cil_common_to_policydb(pdb, cil_common, &sepol_common); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| sepol_class->comdatum = sepol_common; |
| sepol_class->comkey = cil_strdup(key); |
| sepol_class->permissions.nprim += sepol_common->permissions.nprim; |
| |
| for (curr = NODE(cil_class->common)->cl_head, i = 1; curr; curr = curr->next, i++) { |
| struct cil_perm *cil_perm = curr->data; |
| perm_value_to_cil[class_index][i] = cil_perm; |
| } |
| } |
| |
| for (curr = NODE(cil_class)->cl_head; curr; curr = curr->next) { |
| struct cil_perm *cil_perm = curr->data; |
| perm_datum_t *sepol_perm = cil_malloc(sizeof(*sepol_perm)); |
| memset(sepol_perm, 0, sizeof(perm_datum_t)); |
| |
| key = cil_strdup(cil_perm->datum.fqn); |
| rc = hashtab_insert(sepol_class->permissions.table, key, sepol_perm); |
| if (rc != SEPOL_OK) { |
| free(sepol_perm); |
| free(key); |
| goto exit; |
| } |
| sepol_perm->s.value = sepol_class->permissions.nprim + 1; |
| sepol_class->permissions.nprim++; |
| perm_value_to_cil[class_index][sepol_perm->s.value] = cil_perm; |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| int cil_role_to_policydb(policydb_t *pdb, struct cil_role *cil_role) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t value = 0; |
| char *key = NULL; |
| role_datum_t *sepol_role = cil_malloc(sizeof(*sepol_role)); |
| role_datum_init(sepol_role); |
| |
| if (cil_role->datum.fqn == CIL_KEY_OBJECT_R) { |
| /* special case |
| * object_r defaults to 1 in libsepol symtab */ |
| rc = SEPOL_OK; |
| goto exit; |
| } |
| |
| key = cil_strdup(cil_role->datum.fqn); |
| rc = symtab_insert(pdb, SYM_ROLES, (hashtab_key_t)key, sepol_role, SCOPE_DECL, 0, &value); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| if (ebitmap_set_bit(&sepol_role->dominates, value - 1, 1)) { |
| cil_log(CIL_INFO, "Failed to set dominates bit for role\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| sepol_role->s.value = value; |
| return SEPOL_OK; |
| |
| exit: |
| free(key); |
| role_datum_destroy(sepol_role); |
| free(sepol_role); |
| return rc; |
| } |
| |
| static int cil_role_bounds_to_policydb(policydb_t *pdb, struct cil_role *cil_role) |
| { |
| int rc = SEPOL_ERR; |
| role_datum_t *sepol_role = NULL; |
| role_datum_t *sepol_parent = NULL; |
| |
| if (cil_role->bounds) { |
| rc = __cil_get_sepol_role_datum(pdb, DATUM(cil_role), &sepol_role); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = __cil_get_sepol_role_datum(pdb, DATUM(cil_role->bounds), &sepol_parent); |
| if (rc != SEPOL_OK) goto exit; |
| |
| sepol_role->bounds = sepol_parent->s.value; |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| cil_log(CIL_ERR, "Failed to insert role bounds for role %s\n", cil_role->datum.fqn); |
| return SEPOL_ERR; |
| } |
| |
| int cil_roletype_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_role *role) |
| { |
| int rc = SEPOL_ERR; |
| |
| if (role->types) { |
| role_datum_t *sepol_role = NULL; |
| type_datum_t *sepol_type = NULL; |
| ebitmap_node_t *tnode; |
| unsigned int i; |
| |
| rc = __cil_get_sepol_role_datum(pdb, DATUM(role), &sepol_role); |
| if (rc != SEPOL_OK) goto exit; |
| |
| ebitmap_for_each_positive_bit(role->types, tnode, i) { |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_type); |
| if (rc != SEPOL_OK) goto exit; |
| |
| if (ebitmap_set_bit(&sepol_role->types.types, sepol_type->s.value - 1, 1)) { |
| cil_log(CIL_INFO, "Failed to set type bit for role\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| int cil_type_to_policydb(policydb_t *pdb, struct cil_type *cil_type, void *type_value_to_cil[]) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t value = 0; |
| char *key = NULL; |
| type_datum_t *sepol_type = cil_malloc(sizeof(*sepol_type)); |
| type_datum_init(sepol_type); |
| |
| sepol_type->flavor = TYPE_TYPE; |
| |
| key = cil_strdup(cil_type->datum.fqn); |
| rc = symtab_insert(pdb, SYM_TYPES, key, sepol_type, SCOPE_DECL, 0, &value); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| sepol_type->s.value = value; |
| sepol_type->primary = 1; |
| |
| type_value_to_cil[value] = cil_type; |
| |
| return SEPOL_OK; |
| |
| exit: |
| free(key); |
| type_datum_destroy(sepol_type); |
| free(sepol_type); |
| return rc; |
| } |
| |
| static int cil_type_bounds_to_policydb(policydb_t *pdb, struct cil_type *cil_type) |
| { |
| int rc = SEPOL_ERR; |
| type_datum_t *sepol_type = NULL; |
| type_datum_t *sepol_parent = NULL; |
| |
| if (cil_type->bounds) { |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_type), &sepol_type); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_type->bounds), &sepol_parent); |
| if (rc != SEPOL_OK) goto exit; |
| |
| sepol_type->bounds = sepol_parent->s.value; |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| cil_log(CIL_ERR, "Failed to insert type bounds for type %s\n", cil_type->datum.fqn); |
| return SEPOL_ERR; |
| } |
| |
| int cil_typealias_to_policydb(policydb_t *pdb, struct cil_alias *cil_alias) |
| { |
| int rc = SEPOL_ERR; |
| char *key = NULL; |
| type_datum_t *sepol_type = NULL; |
| type_datum_t *sepol_alias = cil_malloc(sizeof(*sepol_alias)); |
| type_datum_init(sepol_alias); |
| |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_alias->actual), &sepol_type); |
| if (rc != SEPOL_OK) goto exit; |
| |
| sepol_alias->flavor = TYPE_TYPE; |
| |
| key = cil_strdup(cil_alias->datum.fqn); |
| rc = symtab_insert(pdb, SYM_TYPES, key, sepol_alias, SCOPE_DECL, 0, NULL); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| sepol_alias->s.value = sepol_type->s.value; |
| sepol_alias->primary = 0; |
| |
| return SEPOL_OK; |
| |
| exit: |
| free(key); |
| type_datum_destroy(sepol_alias); |
| free(sepol_alias); |
| return rc; |
| } |
| |
| int cil_typepermissive_to_policydb(policydb_t *pdb, struct cil_typepermissive *cil_typeperm) |
| { |
| int rc = SEPOL_ERR; |
| type_datum_t *sepol_type = NULL; |
| |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_typeperm->type), &sepol_type); |
| if (rc != SEPOL_OK) goto exit; |
| |
| if (ebitmap_set_bit(&pdb->permissive_map, sepol_type->s.value, 1)) { |
| goto exit; |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| type_datum_destroy(sepol_type); |
| free(sepol_type); |
| return rc; |
| |
| } |
| |
| int cil_typeattribute_to_policydb(policydb_t *pdb, struct cil_typeattribute *cil_attr, void *type_value_to_cil[]) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t value = 0; |
| char *key = NULL; |
| type_datum_t *sepol_attr = NULL; |
| |
| if (!cil_attr->keep) { |
| return SEPOL_OK; |
| } |
| |
| sepol_attr = cil_malloc(sizeof(*sepol_attr)); |
| type_datum_init(sepol_attr); |
| |
| sepol_attr->flavor = TYPE_ATTRIB; |
| |
| key = cil_strdup(cil_attr->datum.fqn); |
| rc = symtab_insert(pdb, SYM_TYPES, key, sepol_attr, SCOPE_DECL, 0, &value); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| sepol_attr->s.value = value; |
| sepol_attr->primary = 1; |
| |
| type_value_to_cil[value] = cil_attr; |
| |
| return SEPOL_OK; |
| |
| exit: |
| type_datum_destroy(sepol_attr); |
| free(sepol_attr); |
| return rc; |
| } |
| |
| static int __cil_typeattr_bitmap_init(policydb_t *pdb) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t i; |
| |
| pdb->type_attr_map = cil_malloc(pdb->p_types.nprim * sizeof(ebitmap_t)); |
| pdb->attr_type_map = cil_malloc(pdb->p_types.nprim * sizeof(ebitmap_t)); |
| |
| for (i = 0; i < pdb->p_types.nprim; i++) { |
| ebitmap_init(&pdb->type_attr_map[i]); |
| ebitmap_init(&pdb->attr_type_map[i]); |
| if (ebitmap_set_bit(&pdb->type_attr_map[i], i, 1)) { |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| if (pdb->type_val_to_struct[i] && pdb->type_val_to_struct[i]->flavor != TYPE_ATTRIB) { |
| if (ebitmap_set_bit(&pdb->attr_type_map[i], i, 1)) { |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| } |
| |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| int cil_typeattribute_to_bitmap(policydb_t *pdb, const struct cil_db *db, struct cil_typeattribute *cil_attr) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t value = 0; |
| type_datum_t *sepol_type = NULL; |
| ebitmap_node_t *tnode; |
| unsigned int i; |
| |
| if (!cil_attr->keep) { |
| return SEPOL_OK; |
| } |
| |
| if (pdb->type_attr_map == NULL) { |
| rc = __cil_typeattr_bitmap_init(pdb); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_attr), &sepol_type); |
| if (rc != SEPOL_OK) goto exit; |
| |
| value = sepol_type->s.value; |
| |
| ebitmap_for_each_positive_bit(cil_attr->types, tnode, i) { |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_type); |
| if (rc != SEPOL_OK) goto exit; |
| |
| ebitmap_set_bit(&pdb->type_attr_map[sepol_type->s.value - 1], value - 1, 1); |
| ebitmap_set_bit(&pdb->attr_type_map[value - 1], sepol_type->s.value - 1, 1); |
| } |
| |
| rc = SEPOL_OK; |
| exit: |
| return rc; |
| } |
| |
| int cil_policycap_to_policydb(policydb_t *pdb, struct cil_policycap *cil_polcap) |
| { |
| int rc = SEPOL_ERR; |
| int capnum; |
| |
| capnum = sepol_polcap_getnum(cil_polcap->datum.fqn); |
| if (capnum == -1) { |
| goto exit; |
| } |
| |
| if (ebitmap_set_bit(&pdb->policycaps, capnum, 1)) { |
| goto exit; |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| int cil_user_to_policydb(policydb_t *pdb, struct cil_user *cil_user) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t value = 0; |
| char *key = NULL; |
| user_datum_t *sepol_user = cil_malloc(sizeof(*sepol_user)); |
| user_datum_init(sepol_user); |
| |
| key = cil_strdup(cil_user->datum.fqn); |
| rc = symtab_insert(pdb, SYM_USERS, key, sepol_user, SCOPE_DECL, 0, &value); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| sepol_user->s.value = value; |
| |
| return SEPOL_OK; |
| |
| exit: |
| free(key); |
| user_datum_destroy(sepol_user); |
| free(sepol_user); |
| return rc; |
| } |
| |
| static int cil_user_bounds_to_policydb(policydb_t *pdb, struct cil_user *cil_user) |
| { |
| int rc = SEPOL_ERR; |
| user_datum_t *sepol_user = NULL; |
| user_datum_t *sepol_parent = NULL; |
| |
| if (cil_user->bounds) { |
| rc = __cil_get_sepol_user_datum(pdb, DATUM(cil_user), &sepol_user); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = __cil_get_sepol_user_datum(pdb, DATUM(cil_user->bounds), &sepol_parent); |
| if (rc != SEPOL_OK) goto exit; |
| |
| sepol_user->bounds = sepol_parent->s.value; |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| cil_log(CIL_ERR, "Failed to insert user bounds for user %s\n", cil_user->datum.fqn); |
| return SEPOL_ERR; |
| } |
| |
| int cil_userrole_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_user *user) |
| { |
| int rc = SEPOL_ERR; |
| user_datum_t *sepol_user = NULL; |
| role_datum_t *sepol_role = NULL; |
| ebitmap_node_t *rnode = NULL; |
| unsigned int i; |
| |
| if (user->roles) { |
| rc = __cil_get_sepol_user_datum(pdb, DATUM(user), &sepol_user); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| ebitmap_for_each_positive_bit(user->roles, rnode, i) { |
| rc = __cil_get_sepol_role_datum(pdb, DATUM(db->val_to_role[i]), &sepol_role); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| if (sepol_role->s.value == 1) { |
| // role is object_r, ignore it since it is implicitly associated |
| // with all users |
| continue; |
| } |
| |
| if (ebitmap_set_bit(&sepol_user->roles.roles, sepol_role->s.value - 1, 1)) { |
| cil_log(CIL_INFO, "Failed to set role bit for user\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| } |
| } |
| |
| rc = SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| int cil_bool_to_policydb(policydb_t *pdb, struct cil_bool *cil_bool) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t value = 0; |
| char *key = NULL; |
| cond_bool_datum_t *sepol_bool = cil_malloc(sizeof(*sepol_bool)); |
| memset(sepol_bool, 0, sizeof(cond_bool_datum_t)); |
| |
| key = cil_strdup(cil_bool->datum.fqn); |
| rc = symtab_insert(pdb, SYM_BOOLS, key, sepol_bool, SCOPE_DECL, 0, &value); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| sepol_bool->s.value = value; |
| sepol_bool->state = cil_bool->value; |
| |
| return SEPOL_OK; |
| |
| exit: |
| free(key); |
| free(sepol_bool); |
| return rc; |
| } |
| |
| int cil_catorder_to_policydb(policydb_t *pdb, const struct cil_db *db) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t value = 0; |
| char *key = NULL; |
| struct cil_list_item *curr_cat; |
| struct cil_cat *cil_cat = NULL; |
| cat_datum_t *sepol_cat = NULL; |
| |
| cil_list_for_each(curr_cat, db->catorder) { |
| cil_cat = curr_cat->data; |
| sepol_cat = cil_malloc(sizeof(*sepol_cat)); |
| cat_datum_init(sepol_cat); |
| |
| key = cil_strdup(cil_cat->datum.fqn); |
| rc = symtab_insert(pdb, SYM_CATS, key, sepol_cat, SCOPE_DECL, 0, &value); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| sepol_cat->s.value = value; |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| free(key); |
| cat_datum_destroy(sepol_cat); |
| free(sepol_cat); |
| return rc; |
| } |
| |
| int cil_catalias_to_policydb(policydb_t *pdb, struct cil_alias *cil_alias) |
| { |
| int rc = SEPOL_ERR; |
| char *key = NULL; |
| cat_datum_t *sepol_cat; |
| cat_datum_t *sepol_alias = cil_malloc(sizeof(*sepol_cat)); |
| cat_datum_init(sepol_alias); |
| |
| rc = __cil_get_sepol_cat_datum(pdb, DATUM(cil_alias->actual), &sepol_cat); |
| if (rc != SEPOL_OK) goto exit; |
| |
| key = cil_strdup(cil_alias->datum.fqn); |
| rc = symtab_insert(pdb, SYM_CATS, key, sepol_alias, SCOPE_DECL, 0, NULL); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| sepol_alias->s.value = sepol_cat->s.value; |
| sepol_alias->isalias = 1; |
| |
| return SEPOL_OK; |
| |
| exit: |
| free(key); |
| cat_datum_destroy(sepol_alias); |
| free(sepol_alias); |
| return rc; |
| } |
| |
| int cil_sensitivityorder_to_policydb(policydb_t *pdb, const struct cil_db *db) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t value = 0; |
| char *key = NULL; |
| struct cil_list_item *curr; |
| struct cil_sens *cil_sens = NULL; |
| level_datum_t *sepol_level = NULL; |
| mls_level_t *mls_level = NULL; |
| |
| cil_list_for_each(curr, db->sensitivityorder) { |
| cil_sens = curr->data; |
| sepol_level = cil_malloc(sizeof(*sepol_level)); |
| mls_level = cil_malloc(sizeof(*mls_level)); |
| level_datum_init(sepol_level); |
| mls_level_init(mls_level); |
| |
| key = cil_strdup(cil_sens->datum.fqn); |
| rc = symtab_insert(pdb, SYM_LEVELS, key, sepol_level, SCOPE_DECL, 0, &value); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| mls_level->sens = value; |
| sepol_level->level = mls_level; |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| level_datum_destroy(sepol_level); |
| mls_level_destroy(mls_level); |
| free(sepol_level); |
| free(mls_level); |
| free(key); |
| return rc; |
| } |
| |
| static int cil_sensalias_to_policydb(policydb_t *pdb, struct cil_alias *cil_alias) |
| { |
| int rc = SEPOL_ERR; |
| char *key = NULL; |
| mls_level_t *mls_level = NULL; |
| level_datum_t *sepol_level = NULL; |
| level_datum_t *sepol_alias = cil_malloc(sizeof(*sepol_alias)); |
| level_datum_init(sepol_alias); |
| |
| rc = __cil_get_sepol_level_datum(pdb, DATUM(cil_alias->actual), &sepol_level); |
| if (rc != SEPOL_OK) goto exit; |
| |
| key = cil_strdup(cil_alias->datum.fqn); |
| rc = symtab_insert(pdb, SYM_LEVELS, key, sepol_alias, SCOPE_DECL, 0, NULL); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| mls_level = cil_malloc(sizeof(*mls_level)); |
| mls_level_init(mls_level); |
| |
| rc = mls_level_cpy(mls_level, sepol_level->level); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| sepol_alias->level = mls_level; |
| sepol_alias->defined = 1; |
| sepol_alias->isalias = 1; |
| |
| return SEPOL_OK; |
| |
| exit: |
| level_datum_destroy(sepol_alias); |
| free(sepol_alias); |
| free(key); |
| return rc; |
| } |
| |
| static int __cil_cond_insert_rule(avtab_t *avtab, avtab_key_t *avtab_key, avtab_datum_t *avtab_datum, cond_node_t *cond_node, enum cil_flavor cond_flavor) |
| { |
| int rc = SEPOL_OK; |
| avtab_ptr_t avtab_ptr = NULL; |
| cond_av_list_t *cond_list = NULL; |
| |
| avtab_ptr = avtab_insert_nonunique(avtab, avtab_key, avtab_datum); |
| if (!avtab_ptr) { |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| |
| // parse_context needs to be non-NULL for conditional rules to be |
| // written to the binary. it is normally used for finding duplicates, |
| // but cil checks that earlier, so we don't use it. it just needs to be |
| // set |
| avtab_ptr->parse_context = (void*)1; |
| |
| cond_list = cil_malloc(sizeof(cond_av_list_t)); |
| memset(cond_list, 0, sizeof(cond_av_list_t)); |
| |
| cond_list->node = avtab_ptr; |
| |
| if (cond_flavor == CIL_CONDTRUE) { |
| cond_list->next = cond_node->true_list; |
| cond_node->true_list = cond_list; |
| } else { |
| cond_list->next = cond_node->false_list; |
| cond_node->false_list = cond_list; |
| } |
| |
| exit: |
| return rc; |
| } |
| |
| static avtab_datum_t *cil_cond_av_list_search(avtab_key_t *key, cond_av_list_t *cond_list) |
| { |
| cond_av_list_t *cur_av; |
| |
| for (cur_av = cond_list; cur_av != NULL; cur_av = cur_av->next) { |
| if (cur_av->node->key.source_type == key->source_type && |
| cur_av->node->key.target_type == key->target_type && |
| cur_av->node->key.target_class == key->target_class && |
| (cur_av->node->key.specified & key->specified)) |
| |
| return &cur_av->node->datum; |
| |
| } |
| return NULL; |
| } |
| |
| static int __cil_insert_type_rule(policydb_t *pdb, uint32_t kind, uint32_t src, uint32_t tgt, uint32_t obj, uint32_t res, struct cil_type_rule *cil_rule, cond_node_t *cond_node, enum cil_flavor cond_flavor) |
| { |
| int rc = SEPOL_OK; |
| avtab_key_t avtab_key; |
| avtab_datum_t avtab_datum; |
| avtab_ptr_t existing; |
| |
| avtab_key.source_type = src; |
| avtab_key.target_type = tgt; |
| avtab_key.target_class = obj; |
| |
| switch (kind) { |
| case CIL_TYPE_TRANSITION: |
| avtab_key.specified = AVTAB_TRANSITION; |
| break; |
| case CIL_TYPE_CHANGE: |
| avtab_key.specified = AVTAB_CHANGE; |
| break; |
| case CIL_TYPE_MEMBER: |
| avtab_key.specified = AVTAB_MEMBER; |
| break; |
| default: |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| |
| avtab_datum.data = res; |
| |
| existing = avtab_search_node(&pdb->te_avtab, &avtab_key); |
| if (existing) { |
| /* Don't add duplicate type rule and warn if they conflict. |
| * A warning should have been previously given if there is a |
| * non-duplicate rule using the same key. |
| */ |
| if (existing->datum.data != res) { |
| cil_log(CIL_ERR, "Conflicting type rules (scontext=%s tcontext=%s tclass=%s result=%s), existing=%s\n", |
| pdb->p_type_val_to_name[src - 1], |
| pdb->p_type_val_to_name[tgt - 1], |
| pdb->p_class_val_to_name[obj - 1], |
| pdb->p_type_val_to_name[res - 1], |
| pdb->p_type_val_to_name[existing->datum.data - 1]); |
| cil_log(CIL_ERR, "Expanded from type rule (scontext=%s tcontext=%s tclass=%s result=%s)\n", |
| cil_rule->src_str, cil_rule->tgt_str, cil_rule->obj_str, cil_rule->result_str); |
| rc = SEPOL_ERR; |
| } |
| goto exit; |
| } |
| |
| if (!cond_node) { |
| rc = avtab_insert(&pdb->te_avtab, &avtab_key, &avtab_datum); |
| } else { |
| existing = avtab_search_node(&pdb->te_cond_avtab, &avtab_key); |
| if (existing) { |
| cond_av_list_t *this_list; |
| cond_av_list_t *other_list; |
| avtab_datum_t *search_datum; |
| |
| if (cond_flavor == CIL_CONDTRUE) { |
| this_list = cond_node->true_list; |
| other_list = cond_node->false_list; |
| } else { |
| this_list = cond_node->false_list; |
| other_list = cond_node->true_list; |
| } |
| |
| search_datum = cil_cond_av_list_search(&avtab_key, other_list); |
| if (search_datum == NULL) { |
| if (existing->datum.data != res) { |
| cil_log(CIL_ERR, "Conflicting type rules (scontext=%s tcontext=%s tclass=%s result=%s), existing=%s\n", |
| pdb->p_type_val_to_name[src - 1], |
| pdb->p_type_val_to_name[tgt - 1], |
| pdb->p_class_val_to_name[obj - 1], |
| pdb->p_type_val_to_name[res - 1], |
| pdb->p_type_val_to_name[existing->datum.data - 1]); |
| cil_log(CIL_ERR, "Expanded from type rule (scontext=%s tcontext=%s tclass=%s result=%s)\n", |
| cil_rule->src_str, cil_rule->tgt_str, cil_rule->obj_str, cil_rule->result_str); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| |
| search_datum = cil_cond_av_list_search(&avtab_key, this_list); |
| if (search_datum) { |
| goto exit; |
| } |
| } |
| } |
| rc = __cil_cond_insert_rule(&pdb->te_cond_avtab, &avtab_key, &avtab_datum, cond_node, cond_flavor); |
| } |
| |
| exit: |
| return rc; |
| } |
| |
| static int __cil_type_rule_to_avtab_helper(policydb_t *pdb, |
| type_datum_t *sepol_src, |
| type_datum_t *sepol_tgt, |
| struct cil_list *class_list, |
| type_datum_t *sepol_result, |
| struct cil_type_rule *cil_rule, |
| cond_node_t *cond_node, |
| enum cil_flavor cond_flavor) |
| { |
| int rc; |
| class_datum_t *sepol_obj = NULL; |
| struct cil_list_item *c; |
| |
| cil_list_for_each(c, class_list) { |
| rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj); |
| if (rc != SEPOL_OK) return rc; |
| |
| rc = __cil_insert_type_rule( |
| pdb, cil_rule->rule_kind, sepol_src->s.value, |
| sepol_tgt->s.value, sepol_obj->s.value, |
| sepol_result->s.value, cil_rule, cond_node, cond_flavor |
| ); |
| if (rc != SEPOL_OK) return rc; |
| } |
| return SEPOL_OK; |
| } |
| |
| static int __cil_type_rule_to_avtab(policydb_t *pdb, const struct cil_db *db, struct cil_type_rule *cil_rule, cond_node_t *cond_node, enum cil_flavor cond_flavor) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_symtab_datum *src = NULL; |
| struct cil_symtab_datum *tgt = NULL; |
| type_datum_t *sepol_src = NULL; |
| type_datum_t *sepol_tgt = NULL; |
| struct cil_list *class_list = NULL; |
| type_datum_t *sepol_result = NULL; |
| ebitmap_t src_bitmap, tgt_bitmap; |
| ebitmap_node_t *node1, *node2; |
| unsigned int i, j; |
| |
| ebitmap_init(&src_bitmap); |
| ebitmap_init(&tgt_bitmap); |
| |
| src = cil_rule->src; |
| tgt = cil_rule->tgt; |
| |
| rc = __cil_expand_type(src, &src_bitmap); |
| if (rc != SEPOL_OK) goto exit; |
| |
| class_list = cil_expand_class(cil_rule->obj); |
| |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_rule->result), &sepol_result); |
| if (rc != SEPOL_OK) goto exit; |
| |
| if (tgt->fqn == CIL_KEY_SELF) { |
| ebitmap_for_each_positive_bit(&src_bitmap, node1, i) { |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_src); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = __cil_type_rule_to_avtab_helper( |
| pdb, sepol_src, sepol_src, class_list, |
| sepol_result, cil_rule, cond_node, cond_flavor |
| ); |
| if (rc != SEPOL_OK) goto exit; |
| } |
| } else { |
| rc = __cil_expand_type(tgt, &tgt_bitmap); |
| if (rc != SEPOL_OK) goto exit; |
| |
| ebitmap_for_each_positive_bit(&src_bitmap, node1, i) { |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_src); |
| if (rc != SEPOL_OK) goto exit; |
| |
| ebitmap_for_each_positive_bit(&tgt_bitmap, node2, j) { |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[j]), &sepol_tgt); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = __cil_type_rule_to_avtab_helper( |
| pdb, sepol_src, sepol_tgt, class_list, |
| sepol_result, cil_rule, cond_node, |
| cond_flavor |
| ); |
| if (rc != SEPOL_OK) goto exit; |
| } |
| } |
| } |
| |
| rc = SEPOL_OK; |
| |
| exit: |
| ebitmap_destroy(&src_bitmap); |
| ebitmap_destroy(&tgt_bitmap); |
| cil_list_destroy(&class_list, CIL_FALSE); |
| return rc; |
| } |
| |
| int cil_type_rule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_type_rule *cil_rule) |
| { |
| return __cil_type_rule_to_avtab(pdb, db, cil_rule, NULL, CIL_FALSE); |
| } |
| |
| static int __cil_typetransition_to_avtab_helper(policydb_t *pdb, |
| type_datum_t *sepol_src, |
| type_datum_t *sepol_tgt, |
| struct cil_list *class_list, |
| char *name, |
| type_datum_t *sepol_result) |
| { |
| int rc; |
| class_datum_t *sepol_obj = NULL; |
| uint32_t otype; |
| struct cil_list_item *c; |
| |
| cil_list_for_each(c, class_list) { |
| rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj); |
| if (rc != SEPOL_OK) return rc; |
| |
| rc = policydb_filetrans_insert( |
| pdb, sepol_src->s.value, sepol_tgt->s.value, |
| sepol_obj->s.value, name, NULL, |
| sepol_result->s.value, &otype |
| ); |
| if (rc != SEPOL_OK) { |
| if (rc == SEPOL_EEXIST) { |
| if (sepol_result->s.value!= otype) { |
| cil_log(CIL_ERR, "Conflicting name type transition rules\n"); |
| } else { |
| rc = SEPOL_OK; |
| } |
| } else { |
| cil_log(CIL_ERR, "Out of memory\n"); |
| } |
| if (rc != SEPOL_OK) { |
| return rc; |
| } |
| } |
| } |
| return SEPOL_OK; |
| } |
| |
| static int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *db, struct cil_nametypetransition *typetrans, cond_node_t *cond_node, enum cil_flavor cond_flavor) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_symtab_datum *src = NULL; |
| struct cil_symtab_datum *tgt = NULL; |
| type_datum_t *sepol_src = NULL; |
| type_datum_t *sepol_tgt = NULL; |
| struct cil_list *class_list = NULL; |
| type_datum_t *sepol_result = NULL; |
| ebitmap_t src_bitmap, tgt_bitmap; |
| ebitmap_node_t *node1, *node2; |
| unsigned int i, j; |
| char *name = DATUM(typetrans->name)->name; |
| |
| if (name == CIL_KEY_STAR) { |
| struct cil_type_rule trans; |
| trans.rule_kind = CIL_TYPE_TRANSITION; |
| trans.src = typetrans->src; |
| trans.tgt = typetrans->tgt; |
| trans.obj = typetrans->obj; |
| trans.result = typetrans->result; |
| trans.src_str = typetrans->src_str; |
| trans.tgt_str = typetrans->tgt_str; |
| trans.obj_str = typetrans->obj_str; |
| trans.result_str = typetrans->result_str; |
| return __cil_type_rule_to_avtab(pdb, db, &trans, cond_node, cond_flavor); |
| } |
| |
| ebitmap_init(&src_bitmap); |
| ebitmap_init(&tgt_bitmap); |
| |
| src = typetrans->src; |
| tgt = typetrans->tgt; |
| |
| rc = __cil_expand_type(src, &src_bitmap); |
| if (rc != SEPOL_OK) goto exit; |
| |
| class_list = cil_expand_class(typetrans->obj); |
| |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(typetrans->result), &sepol_result); |
| if (rc != SEPOL_OK) goto exit; |
| |
| if (tgt->fqn == CIL_KEY_SELF) { |
| ebitmap_for_each_positive_bit(&src_bitmap, node1, i) { |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_src); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = __cil_typetransition_to_avtab_helper( |
| pdb, sepol_src, sepol_src, class_list, |
| name, sepol_result |
| ); |
| if (rc != SEPOL_OK) goto exit; |
| } |
| } else { |
| rc = __cil_expand_type(tgt, &tgt_bitmap); |
| if (rc != SEPOL_OK) goto exit; |
| |
| ebitmap_for_each_positive_bit(&src_bitmap, node1, i) { |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_src); |
| if (rc != SEPOL_OK) goto exit; |
| |
| ebitmap_for_each_positive_bit(&tgt_bitmap, node2, j) { |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[j]), &sepol_tgt); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = __cil_typetransition_to_avtab_helper( |
| pdb, sepol_src, sepol_tgt, class_list, |
| name, sepol_result |
| ); |
| if (rc != SEPOL_OK) goto exit; |
| } |
| } |
| } |
| |
| rc = SEPOL_OK; |
| |
| exit: |
| ebitmap_destroy(&src_bitmap); |
| ebitmap_destroy(&tgt_bitmap); |
| cil_list_destroy(&class_list, CIL_FALSE); |
| return rc; |
| } |
| |
| int cil_typetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_nametypetransition *typetrans) |
| { |
| return __cil_typetransition_to_avtab(pdb, db, typetrans, NULL, CIL_FALSE); |
| } |
| |
| static int __perm_str_to_datum(char *perm_str, class_datum_t *sepol_class, uint32_t *datum) |
| { |
| int rc; |
| perm_datum_t *sepol_perm; |
| common_datum_t *sepol_common; |
| |
| sepol_perm = hashtab_search(sepol_class->permissions.table, perm_str); |
| if (sepol_perm == NULL) { |
| sepol_common = sepol_class->comdatum; |
| sepol_perm = hashtab_search(sepol_common->permissions.table, perm_str); |
| if (sepol_perm == NULL) { |
| cil_log(CIL_ERR, "Failed to find datum for perm %s\n", perm_str); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| } |
| *datum |= UINT32_C(1) << (sepol_perm->s.value - 1); |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| static int __cil_perms_to_datum(struct cil_list *perms, class_datum_t *sepol_class, uint32_t *datum) |
| { |
| int rc = SEPOL_ERR; |
| char *key = NULL; |
| struct cil_list_item *curr_perm; |
| struct cil_perm *cil_perm; |
| uint32_t data = 0; |
| |
| cil_list_for_each(curr_perm, perms) { |
| cil_perm = curr_perm->data; |
| key = cil_perm->datum.fqn; |
| |
| rc = __perm_str_to_datum(key, sepol_class, &data); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| |
| *datum = data; |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| static int __cil_insert_avrule(policydb_t *pdb, uint32_t kind, uint32_t src, uint32_t tgt, uint32_t obj, uint32_t data, cond_node_t *cond_node, enum cil_flavor cond_flavor) |
| { |
| int rc = SEPOL_OK; |
| avtab_key_t avtab_key; |
| avtab_datum_t avtab_datum; |
| avtab_datum_t *avtab_dup = NULL; |
| |
| avtab_key.source_type = src; |
| avtab_key.target_type = tgt; |
| avtab_key.target_class = obj; |
| |
| switch (kind) { |
| case CIL_AVRULE_ALLOWED: |
| avtab_key.specified = AVTAB_ALLOWED; |
| break; |
| case CIL_AVRULE_AUDITALLOW: |
| avtab_key.specified = AVTAB_AUDITALLOW; |
| break; |
| case CIL_AVRULE_DONTAUDIT: |
| avtab_key.specified = AVTAB_AUDITDENY; |
| break; |
| default: |
| rc = SEPOL_ERR; |
| goto exit; |
| break; |
| } |
| |
| if (!cond_node) { |
| avtab_dup = avtab_search(&pdb->te_avtab, &avtab_key); |
| if (!avtab_dup) { |
| avtab_datum.data = data; |
| rc = avtab_insert(&pdb->te_avtab, &avtab_key, &avtab_datum); |
| } else { |
| if (kind == CIL_AVRULE_DONTAUDIT) |
| avtab_dup->data &= data; |
| else |
| avtab_dup->data |= data; |
| } |
| } else { |
| avtab_datum.data = data; |
| rc = __cil_cond_insert_rule(&pdb->te_cond_avtab, &avtab_key, &avtab_datum, cond_node, cond_flavor); |
| } |
| |
| exit: |
| return rc; |
| } |
| |
| static int __cil_avrule_expand_helper(policydb_t *pdb, uint16_t kind, struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_classperms *cp, cond_node_t *cond_node, enum cil_flavor cond_flavor) |
| { |
| int rc = SEPOL_ERR; |
| type_datum_t *sepol_src = NULL; |
| type_datum_t *sepol_tgt = NULL; |
| class_datum_t *sepol_class = NULL; |
| uint32_t data = 0; |
| |
| rc = __cil_get_sepol_class_datum(pdb, DATUM(cp->class), &sepol_class); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = __cil_perms_to_datum(cp->perms, sepol_class, &data); |
| if (rc != SEPOL_OK) goto exit; |
| |
| if (data == 0) { |
| /* No permissions, so don't insert rule. Maybe should return an error? */ |
| return SEPOL_OK; |
| } |
| |
| if (kind == CIL_AVRULE_DONTAUDIT) { |
| data = ~data; |
| } |
| |
| rc = __cil_get_sepol_type_datum(pdb, src, &sepol_src); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = __cil_get_sepol_type_datum(pdb, tgt, &sepol_tgt); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = __cil_insert_avrule(pdb, kind, sepol_src->s.value, sepol_tgt->s.value, sepol_class->s.value, data, cond_node, cond_flavor); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| |
| static int __cil_avrule_expand(policydb_t *pdb, uint16_t kind, struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_list *classperms, cond_node_t *cond_node, enum cil_flavor cond_flavor) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_list_item *curr; |
| |
| cil_list_for_each(curr, classperms) { |
| if (curr->flavor == CIL_CLASSPERMS) { |
| struct cil_classperms *cp = curr->data; |
| if (FLAVOR(cp->class) == CIL_CLASS) { |
| rc = __cil_avrule_expand_helper(pdb, kind, src, tgt, cp, cond_node, cond_flavor); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } else { /* MAP */ |
| struct cil_list_item *i = NULL; |
| cil_list_for_each(i, cp->perms) { |
| struct cil_perm *cmp = i->data; |
| rc = __cil_avrule_expand(pdb, kind, src, tgt, cmp->classperms, cond_node, cond_flavor); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| } |
| } else { /* SET */ |
| struct cil_classperms_set *cp_set = curr->data; |
| struct cil_classpermission *cp = cp_set->set; |
| rc = __cil_avrule_expand(pdb, kind, src, tgt, cp->classperms, cond_node, cond_flavor); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| static int __cil_should_expand_attribute( const struct cil_db *db, struct cil_symtab_datum *datum) |
| { |
| struct cil_tree_node *node; |
| struct cil_typeattribute *attr; |
| |
| node = NODE(datum); |
| |
| if (node->flavor != CIL_TYPEATTRIBUTE) { |
| return CIL_FALSE; |
| } |
| |
| attr = (struct cil_typeattribute *)datum; |
| |
| return !attr->keep || (ebitmap_cardinality(attr->types) < db->attrs_expand_size); |
| } |
| |
| static int __cil_avrule_to_avtab(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrule, cond_node_t *cond_node, enum cil_flavor cond_flavor) |
| { |
| int rc = SEPOL_ERR; |
| uint16_t kind = cil_avrule->rule_kind; |
| struct cil_symtab_datum *src = NULL; |
| struct cil_symtab_datum *tgt = NULL; |
| struct cil_list *classperms = cil_avrule->perms.classperms; |
| ebitmap_t src_bitmap, tgt_bitmap; |
| ebitmap_node_t *snode, *tnode; |
| unsigned int s,t; |
| |
| if (cil_avrule->rule_kind == CIL_AVRULE_DONTAUDIT && db->disable_dontaudit == CIL_TRUE) { |
| // Do not add dontaudit rules to binary |
| rc = SEPOL_OK; |
| goto exit; |
| } |
| |
| src = cil_avrule->src; |
| tgt = cil_avrule->tgt; |
| |
| if (tgt->fqn == CIL_KEY_SELF) { |
| rc = __cil_expand_type(src, &src_bitmap); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| ebitmap_for_each_positive_bit(&src_bitmap, snode, s) { |
| src = DATUM(db->val_to_type[s]); |
| rc = __cil_avrule_expand(pdb, kind, src, src, classperms, cond_node, cond_flavor); |
| if (rc != SEPOL_OK) { |
| ebitmap_destroy(&src_bitmap); |
| goto exit; |
| } |
| } |
| ebitmap_destroy(&src_bitmap); |
| } else { |
| int expand_src = __cil_should_expand_attribute(db, src); |
| int expand_tgt = __cil_should_expand_attribute(db, tgt); |
| if (!expand_src && !expand_tgt) { |
| rc = __cil_avrule_expand(pdb, kind, src, tgt, classperms, cond_node, cond_flavor); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } else if (expand_src && expand_tgt) { |
| rc = __cil_expand_type(src, &src_bitmap); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = __cil_expand_type(tgt, &tgt_bitmap); |
| if (rc != SEPOL_OK) { |
| ebitmap_destroy(&src_bitmap); |
| goto exit; |
| } |
| |
| ebitmap_for_each_positive_bit(&src_bitmap, snode, s) { |
| src = DATUM(db->val_to_type[s]); |
| ebitmap_for_each_positive_bit(&tgt_bitmap, tnode, t) { |
| tgt = DATUM(db->val_to_type[t]); |
| |
| rc = __cil_avrule_expand(pdb, kind, src, tgt, classperms, cond_node, cond_flavor); |
| if (rc != SEPOL_OK) { |
| ebitmap_destroy(&src_bitmap); |
| ebitmap_destroy(&tgt_bitmap); |
| goto exit; |
| } |
| } |
| } |
| ebitmap_destroy(&src_bitmap); |
| ebitmap_destroy(&tgt_bitmap); |
| } else if (expand_src) { |
| rc = __cil_expand_type(src, &src_bitmap); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| ebitmap_for_each_positive_bit(&src_bitmap, snode, s) { |
| src = DATUM(db->val_to_type[s]); |
| |
| rc = __cil_avrule_expand(pdb, kind, src, tgt, classperms, cond_node, cond_flavor); |
| if (rc != SEPOL_OK) { |
| ebitmap_destroy(&src_bitmap); |
| goto exit; |
| } |
| } |
| ebitmap_destroy(&src_bitmap); |
| } else { /* expand_tgt */ |
| rc = __cil_expand_type(tgt, &tgt_bitmap); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| ebitmap_for_each_positive_bit(&tgt_bitmap, tnode, t) { |
| tgt = DATUM(db->val_to_type[t]); |
| |
| rc = __cil_avrule_expand(pdb, kind, src, tgt, classperms, cond_node, cond_flavor); |
| if (rc != SEPOL_OK) { |
| ebitmap_destroy(&tgt_bitmap); |
| goto exit; |
| } |
| } |
| ebitmap_destroy(&tgt_bitmap); |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| int cil_avrule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrule) |
| { |
| return __cil_avrule_to_avtab(pdb, db, cil_avrule, NULL, CIL_FALSE); |
| } |
| |
| // Copied from checkpolicy/policy_define.c |
| |
| /* index of the u32 containing the permission */ |
| #define XPERM_IDX(x) (x >> 5) |
| /* set bits 0 through x-1 within the u32 */ |
| #define XPERM_SETBITS(x) ((UINT32_C(1) << (x & 0x1f)) - 1) |
| /* low value for this u32 */ |
| #define XPERM_LOW(x) (x << 5) |
| /* high value for this u32 */ |
| #define XPERM_HIGH(x) (((x + 1) << 5) - 1) |
| static void __avrule_xperm_setrangebits(uint16_t low, uint16_t high, struct avtab_extended_perms *xperms) |
| { |
| unsigned int i; |
| uint16_t h = high + 1; |
| /* for each u32 that this low-high range touches, set driver permissions */ |
| for (i = XPERM_IDX(low); i <= XPERM_IDX(high); i++) { |
| /* set all bits in u32 */ |
| if ((low <= XPERM_LOW(i)) && (high >= XPERM_HIGH(i))) |
| xperms->perms[i] |= ~0U; |
| /* set low bits */ |
| else if ((low <= XPERM_LOW(i)) && (high < XPERM_HIGH(i))) |
| xperms->perms[i] |= XPERM_SETBITS(h); |
| /* set high bits */ |
| else if ((low > XPERM_LOW(i)) && (high >= XPERM_HIGH(i))) |
| xperms->perms[i] |= ~0U - XPERM_SETBITS(low); |
| /* set middle bits */ |
| else if ((low > XPERM_LOW(i)) && (high <= XPERM_HIGH(i))) |
| xperms->perms[i] |= XPERM_SETBITS(h) - XPERM_SETBITS(low); |
| } |
| } |
| |
| |
| #define IOC_DRIV(x) (x >> 8) |
| #define IOC_FUNC(x) (x & 0xff) |
| |
| static int __cil_permx_bitmap_to_sepol_xperms_list(ebitmap_t *xperms, struct cil_list **xperms_list) |
| { |
| ebitmap_node_t *node; |
| unsigned int i; |
| uint16_t low = 0, high = 0; |
| struct avtab_extended_perms *partial = NULL; |
| struct avtab_extended_perms *complete = NULL; |
| int start_new_range; |
| |
| cil_list_init(xperms_list, CIL_NONE); |
| |
| start_new_range = 1; |
| |
| ebitmap_for_each_positive_bit(xperms, node, i) { |
| if (start_new_range) { |
| low = i; |
| start_new_range = 0; |
| } |
| |
| // continue if the current bit isn't the end of the driver function or the next bit is set |
| if (IOC_FUNC(i) != 0xff && ebitmap_get_bit(xperms, i + 1)) { |
| continue; |
| } |
| |
| // if we got here, i is the end of this range (either because the func |
| // is 0xff or the next bit isn't set). The next time around we are |
| // going to need a start a new range |
| high = i; |
| start_new_range = 1; |
| |
| if (IOC_FUNC(low) == 0x00 && IOC_FUNC(high) == 0xff) { |
| if (!complete) { |
| complete = cil_calloc(1, sizeof(*complete)); |
| complete->driver = 0x0; |
| complete->specified = AVTAB_XPERMS_IOCTLDRIVER; |
| } |
| |
| __avrule_xperm_setrangebits(IOC_DRIV(low), IOC_DRIV(low), complete); |
| } else { |
| if (partial && partial->driver != IOC_DRIV(low)) { |
| cil_list_append(*xperms_list, CIL_NONE, partial); |
| partial = NULL; |
| } |
| |
| if (!partial) { |
| partial = cil_calloc(1, sizeof(*partial)); |
| partial->driver = IOC_DRIV(low); |
| partial->specified = AVTAB_XPERMS_IOCTLFUNCTION; |
| } |
| |
| __avrule_xperm_setrangebits(IOC_FUNC(low), IOC_FUNC(high), partial); |
| } |
| } |
| |
| if (partial) { |
| cil_list_append(*xperms_list, CIL_NONE, partial); |
| } |
| |
| if (complete) { |
| cil_list_append(*xperms_list, CIL_NONE, complete); |
| } |
| |
| return SEPOL_OK; |
| } |
| |
| static int __cil_avrulex_ioctl_to_policydb(hashtab_key_t k, hashtab_datum_t datum, void *args) |
| { |
| int rc = SEPOL_OK; |
| struct policydb *pdb; |
| avtab_key_t *avtab_key; |
| avtab_datum_t avtab_datum; |
| struct cil_list *xperms_list = NULL; |
| struct cil_list_item *item; |
| class_datum_t *sepol_obj; |
| uint32_t data = 0; |
| |
| avtab_key = (avtab_key_t *)k; |
| pdb = args; |
| |
| sepol_obj = pdb->class_val_to_struct[avtab_key->target_class - 1]; |
| |
| // setting the data for an extended avtab isn't really necessary because |
| // it is ignored by the kernel. However, neverallow checking requires that |
| // the data value be set, so set it for that to work. |
| rc = __perm_str_to_datum(CIL_KEY_IOCTL, sepol_obj, &data); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| avtab_datum.data = data; |
| |
| rc = __cil_permx_bitmap_to_sepol_xperms_list(datum, &xperms_list); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| cil_list_for_each(item, xperms_list) { |
| avtab_datum.xperms = item->data; |
| rc = avtab_insert(&pdb->te_avtab, avtab_key, &avtab_datum); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| |
| rc = SEPOL_OK; |
| |
| exit: |
| if (xperms_list != NULL) { |
| cil_list_for_each(item, xperms_list) { |
| free(item->data); |
| } |
| cil_list_destroy(&xperms_list, CIL_FALSE); |
| } |
| return rc; |
| } |
| |
| static int __cil_avrulex_ioctl_to_hashtable(hashtab_t h, uint16_t kind, uint32_t src, uint32_t tgt, uint32_t obj, ebitmap_t *xperms) |
| { |
| uint16_t specified; |
| avtab_key_t *avtab_key; |
| ebitmap_t *hashtab_xperms; |
| int rc = SEPOL_ERR; |
| |
| switch (kind) { |
| case CIL_AVRULE_ALLOWED: |
| specified = AVTAB_XPERMS_ALLOWED; |
| break; |
| case CIL_AVRULE_AUDITALLOW: |
| specified = AVTAB_XPERMS_AUDITALLOW; |
| break; |
| case CIL_AVRULE_DONTAUDIT: |
| specified = AVTAB_XPERMS_DONTAUDIT; |
| break; |
| default: |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| |
| avtab_key = cil_malloc(sizeof(*avtab_key)); |
| avtab_key->source_type = src; |
| avtab_key->target_type = tgt; |
| avtab_key->target_class = obj; |
| avtab_key->specified = specified; |
| |
| hashtab_xperms = (ebitmap_t *)hashtab_search(h, (hashtab_key_t)avtab_key); |
| if (!hashtab_xperms) { |
| hashtab_xperms = cil_malloc(sizeof(*hashtab_xperms)); |
| rc = ebitmap_cpy(hashtab_xperms, xperms); |
| if (rc != SEPOL_OK) { |
| free(hashtab_xperms); |
| free(avtab_key); |
| goto exit; |
| } |
| rc = hashtab_insert(h, (hashtab_key_t)avtab_key, hashtab_xperms); |
| if (rc != SEPOL_OK) { |
| free(hashtab_xperms); |
| free(avtab_key); |
| goto exit; |
| } |
| } else { |
| free(avtab_key); |
| rc = ebitmap_union(hashtab_xperms, xperms); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| static int __cil_avrulex_to_hashtable_helper(policydb_t *pdb, uint16_t kind, struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_permissionx *permx, struct cil_args_binary *args) |
| { |
| int rc = SEPOL_ERR; |
| type_datum_t *sepol_src = NULL; |
| type_datum_t *sepol_tgt = NULL; |
| class_datum_t *sepol_obj = NULL; |
| struct cil_list *class_list = NULL; |
| struct cil_list_item *c; |
| |
| rc = __cil_get_sepol_type_datum(pdb, src, &sepol_src); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = __cil_get_sepol_type_datum(pdb, tgt, &sepol_tgt); |
| if (rc != SEPOL_OK) goto exit; |
| |
| class_list = cil_expand_class(permx->obj); |
| |
| cil_list_for_each(c, class_list) { |
| rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj); |
| if (rc != SEPOL_OK) goto exit; |
| |
| switch (permx->kind) { |
| case CIL_PERMX_KIND_IOCTL: |
| rc = __cil_avrulex_ioctl_to_hashtable(args->avrulex_ioctl_table, kind, sepol_src->s.value, sepol_tgt->s.value, sepol_obj->s.value, permx->perms); |
| if (rc != SEPOL_OK) goto exit; |
| break; |
| default: |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| } |
| |
| rc = SEPOL_OK; |
| |
| exit: |
| cil_list_destroy(&class_list, CIL_FALSE); |
| |
| return rc; |
| } |
| |
| static int cil_avrulex_to_hashtable(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrulex, struct cil_args_binary *args) |
| { |
| int rc = SEPOL_ERR; |
| uint16_t kind; |
| struct cil_symtab_datum *src = NULL; |
| struct cil_symtab_datum *tgt = NULL; |
| ebitmap_t src_bitmap, tgt_bitmap; |
| ebitmap_node_t *snode, *tnode; |
| unsigned int s,t; |
| |
| if (cil_avrulex->rule_kind == CIL_AVRULE_DONTAUDIT && db->disable_dontaudit == CIL_TRUE) { |
| // Do not add dontaudit rules to binary |
| rc = SEPOL_OK; |
| goto exit; |
| } |
| |
| kind = cil_avrulex->rule_kind; |
| src = cil_avrulex->src; |
| tgt = cil_avrulex->tgt; |
| |
| if (tgt->fqn == CIL_KEY_SELF) { |
| rc = __cil_expand_type(src, &src_bitmap); |
| if (rc != SEPOL_OK) goto exit; |
| |
| ebitmap_for_each_positive_bit(&src_bitmap, snode, s) { |
| src = DATUM(db->val_to_type[s]); |
| rc = __cil_avrulex_to_hashtable_helper(pdb, kind, src, src, cil_avrulex->perms.x.permx, args); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| ebitmap_destroy(&src_bitmap); |
| } else { |
| int expand_src = __cil_should_expand_attribute(db, src); |
| int expand_tgt = __cil_should_expand_attribute(db, tgt); |
| |
| if (!expand_src && !expand_tgt) { |
| rc = __cil_avrulex_to_hashtable_helper(pdb, kind, src, tgt, cil_avrulex->perms.x.permx, args); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } else if (expand_src && expand_tgt) { |
| rc = __cil_expand_type(src, &src_bitmap); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = __cil_expand_type(tgt, &tgt_bitmap); |
| if (rc != SEPOL_OK) { |
| ebitmap_destroy(&src_bitmap); |
| goto exit; |
| } |
| |
| ebitmap_for_each_positive_bit(&src_bitmap, snode, s) { |
| src = DATUM(db->val_to_type[s]); |
| ebitmap_for_each_positive_bit(&tgt_bitmap, tnode, t) { |
| tgt = DATUM(db->val_to_type[t]); |
| |
| rc = __cil_avrulex_to_hashtable_helper(pdb, kind, src, tgt, cil_avrulex->perms.x.permx, args); |
| if (rc != SEPOL_OK) { |
| ebitmap_destroy(&src_bitmap); |
| ebitmap_destroy(&tgt_bitmap); |
| goto exit; |
| } |
| } |
| } |
| ebitmap_destroy(&src_bitmap); |
| ebitmap_destroy(&tgt_bitmap); |
| } else if (expand_src) { |
| rc = __cil_expand_type(src, &src_bitmap); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| ebitmap_for_each_positive_bit(&src_bitmap, snode, s) { |
| src = DATUM(db->val_to_type[s]); |
| |
| rc = __cil_avrulex_to_hashtable_helper(pdb, kind, src, tgt, cil_avrulex->perms.x.permx, args); |
| if (rc != SEPOL_OK) { |
| ebitmap_destroy(&src_bitmap); |
| goto exit; |
| } |
| } |
| ebitmap_destroy(&src_bitmap); |
| } else { /* expand_tgt */ |
| rc = __cil_expand_type(tgt, &tgt_bitmap); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| ebitmap_for_each_positive_bit(&tgt_bitmap, tnode, t) { |
| tgt = DATUM(db->val_to_type[t]); |
| |
| rc = __cil_avrulex_to_hashtable_helper(pdb, kind, src, tgt, cil_avrulex->perms.x.permx, args); |
| if (rc != SEPOL_OK) { |
| ebitmap_destroy(&tgt_bitmap); |
| goto exit; |
| } |
| } |
| ebitmap_destroy(&tgt_bitmap); |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| static int __cil_avrulex_ioctl_destroy(hashtab_key_t k, hashtab_datum_t datum, __attribute__((unused)) void *args) |
| { |
| free(k); |
| ebitmap_destroy(datum); |
| free(datum); |
| |
| return SEPOL_OK; |
| } |
| |
| static int __cil_cond_to_policydb_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args) |
| { |
| int rc; |
| enum cil_flavor flavor; |
| struct cil_args_booleanif *args = extra_args; |
| const struct cil_db *db = args->db; |
| policydb_t *pdb = args->pdb; |
| cond_node_t *cond_node = args->cond_node; |
| enum cil_flavor cond_flavor = args->cond_flavor; |
| struct cil_type_rule *cil_type_rule; |
| struct cil_avrule *cil_avrule; |
| struct cil_nametypetransition *cil_typetrans; |
| |
| flavor = node->flavor; |
| switch (flavor) { |
| case CIL_NAMETYPETRANSITION: |
| cil_typetrans = (struct cil_nametypetransition*)node->data; |
| if (DATUM(cil_typetrans->name)->fqn != CIL_KEY_STAR) { |
| cil_log(CIL_ERR, "typetransition with file name not allowed within a booleanif block.\n"); |
| cil_tree_log(node, CIL_ERR,"Invalid typetransition statement"); |
| goto exit; |
| } |
| rc = __cil_typetransition_to_avtab(pdb, db, cil_typetrans, cond_node, cond_flavor); |
| if (rc != SEPOL_OK) { |
| cil_tree_log(node, CIL_ERR, "Failed to insert type transition into avtab"); |
| goto exit; |
| } |
| break; |
| case CIL_TYPE_RULE: |
| cil_type_rule = node->data; |
| rc = __cil_type_rule_to_avtab(pdb, db, cil_type_rule, cond_node, cond_flavor); |
| if (rc != SEPOL_OK) { |
| cil_tree_log(node, CIL_ERR, "Failed to insert typerule into avtab"); |
| goto exit; |
| } |
| break; |
| case CIL_AVRULE: |
| cil_avrule = node->data; |
| rc = __cil_avrule_to_avtab(pdb, db, cil_avrule, cond_node, cond_flavor); |
| if (rc != SEPOL_OK) { |
| cil_tree_log(node, CIL_ERR, "Failed to insert avrule into avtab"); |
| goto exit; |
| } |
| break; |
| case CIL_CALL: |
| case CIL_TUNABLEIF: |
| break; |
| default: |
| cil_tree_log(node, CIL_ERR, "Invalid statement within booleanif"); |
| goto exit; |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return SEPOL_ERR; |
| } |
| |
| static void __cil_expr_to_string(struct cil_list *expr, enum cil_flavor flavor, char **out); |
| |
| static void __cil_expr_to_string_helper(struct cil_list_item *curr, enum cil_flavor flavor, char **out) |
| { |
| char *c; |
| |
| if (curr->flavor == CIL_DATUM) { |
| *out = cil_strdup(DATUM(curr->data)->fqn); |
| } else if (curr->flavor == CIL_LIST) { |
| __cil_expr_to_string(curr->data, flavor, &c); |
| cil_asprintf(out, "(%s)", c); |
| free(c); |
| } else if (flavor == CIL_PERMISSIONX) { |
| // permissionx expressions aren't resolved into anything, so curr->flavor |
| // is just a CIL_STRING, not a CIL_DATUM, so just check on flavor for those |
| *out = cil_strdup(curr->data); |
| } |
| } |
| |
| static void __cil_expr_to_string(struct cil_list *expr, enum cil_flavor flavor, char **out) |
| { |
| struct cil_list_item *curr; |
| char *s1 = NULL; |
| char *s2 = NULL; |
| enum cil_flavor op; |
| |
| if (expr == NULL || expr->head == NULL) { |
| *out = cil_strdup(""); |
| return; |
| } |
| |
| curr = expr->head; |
| |
| if (curr->flavor == CIL_OP) { |
| op = (enum cil_flavor)(uintptr_t)curr->data; |
| |
| if (op == CIL_ALL) { |
| *out = cil_strdup(CIL_KEY_ALL); |
| } else if (op == CIL_RANGE) { |
| __cil_expr_to_string_helper(curr->next, flavor, &s1); |
| __cil_expr_to_string_helper(curr->next->next, flavor, &s2); |
| cil_asprintf(out, "%s %s %s", CIL_KEY_RANGE, s1, s2); |
| free(s1); |
| free(s2); |
| } else { |
| __cil_expr_to_string_helper(curr->next, flavor, &s1); |
| |
| if (op == CIL_NOT) { |
| cil_asprintf(out, "%s %s", CIL_KEY_NOT, s1); |
| free(s1); |
| } else { |
| const char *opstr = ""; |
| |
| __cil_expr_to_string_helper(curr->next->next, flavor, &s2); |
| |
| if (op == CIL_OR) { |
| opstr = CIL_KEY_OR; |
| } else if (op == CIL_AND) { |
| opstr = CIL_KEY_AND; |
| } else if (op == CIL_XOR) { |
| opstr = CIL_KEY_XOR; |
| } |
| |
| cil_asprintf(out, "%s %s %s", opstr, s1, s2); |
| free(s1); |
| free(s2); |
| } |
| } |
| } else { |
| char *c1 = NULL; |
| char *c2 = NULL; |
| __cil_expr_to_string_helper(curr, flavor, &c1); |
| for (curr = curr->next; curr; curr = curr->next) { |
| s1 = NULL; |
| __cil_expr_to_string_helper(curr, flavor, &s1); |
| cil_asprintf(&c2, "%s %s", c1, s1); |
| free(c1); |
| free(s1); |
| c1 = c2; |
| } |
| *out = c1; |
| } |
| } |
| |
| static int __cil_cond_expr_to_sepol_expr_helper(policydb_t *pdb, struct cil_list *cil_expr, cond_expr_t **head, cond_expr_t **tail); |
| |
| static int __cil_cond_item_to_sepol_expr(policydb_t *pdb, struct cil_list_item *item, cond_expr_t **head, cond_expr_t **tail) |
| { |
| if (item == NULL) { |
| goto exit; |
| } else if (item->flavor == CIL_DATUM) { |
| char *key = DATUM(item->data)->fqn; |
| cond_bool_datum_t *sepol_bool = hashtab_search(pdb->p_bools.table, key); |
| if (sepol_bool == NULL) { |
| cil_log(CIL_INFO, "Failed to find boolean\n"); |
| goto exit; |
| } |
| *head = cil_malloc(sizeof(cond_expr_t)); |
| (*head)->next = NULL; |
| (*head)->expr_type = COND_BOOL; |
| (*head)->bool = sepol_bool->s.value; |
| *tail = *head; |
| } else if (item->flavor == CIL_LIST) { |
| struct cil_list *l = item->data; |
| int rc = __cil_cond_expr_to_sepol_expr_helper(pdb, l, head, tail); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } else { |
| goto exit; |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return SEPOL_ERR; |
| } |
| |
| static int __cil_cond_expr_to_sepol_expr_helper(policydb_t *pdb, struct cil_list *cil_expr, cond_expr_t **head, cond_expr_t **tail) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_list_item *item = cil_expr->head; |
| enum cil_flavor flavor = cil_expr->flavor; |
| cond_expr_t *op, *h1, *h2, *t1, *t2; |
| |
| if (flavor != CIL_BOOL) { |
| cil_log(CIL_INFO, "Expected boolean expression\n"); |
| goto exit; |
| } |
| |
| if (item == NULL) { |
| goto exit; |
| } else if (item->flavor == CIL_OP) { |
| enum cil_flavor cil_op = (enum cil_flavor)(uintptr_t)item->data; |
| |
| op = cil_malloc(sizeof(*op)); |
| op->bool = 0; |
| op->next = NULL; |
| |
| switch (cil_op) { |
| case CIL_NOT: |
| op->expr_type = COND_NOT; |
| break; |
| case CIL_OR: |
| op->expr_type = COND_OR; |
| break; |
| case CIL_AND: |
| op->expr_type = COND_AND; |
| break; |
| case CIL_XOR: |
| op->expr_type = COND_XOR; |
| break; |
| case CIL_EQ: |
| op->expr_type = COND_EQ; |
| break; |
| case CIL_NEQ: |
| op->expr_type = COND_NEQ; |
| break; |
| default: |
| free(op); |
| goto exit; |
| } |
| |
| rc = __cil_cond_item_to_sepol_expr(pdb, item->next, &h1, &t1); |
| if (rc != SEPOL_OK) { |
| cil_log(CIL_INFO, "Failed to get first operand of conditional expression\n"); |
| free(op); |
| goto exit; |
| } |
| |
| if (cil_op == CIL_NOT) { |
| *head = h1; |
| t1->next = op; |
| *tail = op; |
| } else { |
| rc = __cil_cond_item_to_sepol_expr(pdb, item->next->next, &h2, &t2); |
| if (rc != SEPOL_OK) { |
| cil_log(CIL_INFO, "Failed to get second operand of conditional expression\n"); |
| free(op); |
| cond_expr_destroy(h1); |
| goto exit; |
| } |
| |
| *head = h1; |
| t1->next = h2; |
| t2->next = op; |
| *tail = op; |
| } |
| } else { |
| rc = __cil_cond_item_to_sepol_expr(pdb, item, &h1, &t1); |
| if (rc != SEPOL_OK) { |
| cil_log(CIL_INFO, "Failed to get initial item in conditional list\n"); |
| goto exit; |
| } |
| *head = h1; |
| for (item = item->next; item; item = item->next) { |
| rc = __cil_cond_item_to_sepol_expr(pdb, item, &h2, &t2); |
| if (rc != SEPOL_OK) { |
| cil_log(CIL_INFO, "Failed to get item in conditional list\n"); |
| cond_expr_destroy(*head); |
| goto exit; |
| } |
| op = cil_malloc(sizeof(*op)); |
| op->bool = 0; |
| op->next = NULL; |
| op->expr_type = COND_OR; |
| t1->next = h2; |
| t2->next = op; |
| t1 = op; |
| } |
| *tail = t1; |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return SEPOL_ERR; |
| } |
| |
| static int __cil_cond_expr_to_sepol_expr(policydb_t *pdb, struct cil_list *cil_expr, cond_expr_t **sepol_expr) |
| { |
| int rc; |
| cond_expr_t *head, *tail; |
| |
| rc = __cil_cond_expr_to_sepol_expr_helper(pdb, cil_expr, &head, &tail); |
| if (rc != SEPOL_OK) { |
| return SEPOL_ERR; |
| } |
| *sepol_expr = head; |
| |
| return SEPOL_OK; |
| } |
| |
| static int __cil_validate_cond_expr(cond_expr_t *cond_expr) |
| { |
| cond_expr_t *e; |
| int depth = -1; |
| |
| for (e = cond_expr; e != NULL; e = e->next) { |
| switch (e->expr_type) { |
| case COND_BOOL: |
| if (depth == (COND_EXPR_MAXDEPTH - 1)) { |
| cil_log(CIL_ERR,"Conditional expression exceeded max allowable depth\n"); |
| return SEPOL_ERR; |
| } |
| depth++; |
| break; |
| case COND_NOT: |
| if (depth < 0) { |
| cil_log(CIL_ERR,"Invalid conditional expression\n"); |
| return SEPOL_ERR; |
| } |
| break; |
| case COND_OR: |
| case COND_AND: |
| case COND_XOR: |
| case COND_EQ: |
| case COND_NEQ: |
| if (depth < 1) { |
| cil_log(CIL_ERR,"Invalid conditional expression\n"); |
| return SEPOL_ERR; |
| } |
| depth--; |
| break; |
| default: |
| cil_log(CIL_ERR,"Invalid conditional expression\n"); |
| return SEPOL_ERR; |
| } |
| } |
| |
| if (depth != 0) { |
| cil_log(CIL_ERR,"Invalid conditional expression\n"); |
| return SEPOL_ERR; |
| } |
| |
| return SEPOL_OK; |
| } |
| |
| int cil_booleanif_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_tree_node *node) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_args_booleanif bool_args; |
| struct cil_booleanif *cil_boolif = (struct cil_booleanif*)node->data; |
| struct cil_tree_node *cb_node; |
| struct cil_tree_node *true_node = NULL; |
| struct cil_tree_node *false_node = NULL; |
| struct cil_tree_node *tmp_node = NULL; |
| cond_node_t *tmp_cond = NULL; |
| cond_node_t *cond_node = NULL; |
| int was_created; |
| int swapped = CIL_FALSE; |
| cond_av_list_t tmp_cl; |
| |
| tmp_cond = cond_node_create(pdb, NULL); |
| if (tmp_cond == NULL) { |
| rc = SEPOL_ERR; |
| cil_tree_log(node, CIL_INFO, "Failed to create sepol conditional node"); |
| goto exit; |
| } |
| |
| rc = __cil_cond_expr_to_sepol_expr(pdb, cil_boolif->datum_expr, &tmp_cond->expr); |
| if (rc != SEPOL_OK) { |
| cil_tree_log(node, CIL_INFO, "Failed to convert CIL conditional expression to sepol expression"); |
| goto exit; |
| } |
| |
| rc = __cil_validate_cond_expr(tmp_cond->expr); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| tmp_cond->true_list = &tmp_cl; |
| |
| rc = cond_normalize_expr(pdb, tmp_cond); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| if (tmp_cond->false_list != NULL) { |
| tmp_cond->true_list = NULL; |
| swapped = CIL_TRUE; |
| } |
| |
| cond_node = cond_node_find(pdb, tmp_cond, pdb->cond_list, &was_created); |
| if (cond_node == NULL) { |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| |
| if (was_created) { |
| cond_node->next = pdb->cond_list; |
| pdb->cond_list = cond_node; |
| } |
| |
| cond_expr_destroy(tmp_cond->expr); |
| free(tmp_cond); |
| tmp_cond = NULL; |
| |
| for (cb_node = node->cl_head; cb_node != NULL; cb_node = cb_node->next) { |
| if (cb_node->flavor == CIL_CONDBLOCK) { |
| struct cil_condblock *cb = cb_node->data; |
| if (cb->flavor == CIL_CONDTRUE) { |
| true_node = cb_node; |
| } else if (cb->flavor == CIL_CONDFALSE) { |
| false_node = cb_node; |
| } |
| } |
| } |
| |
| if (swapped) { |
| tmp_node = true_node; |
| true_node = false_node; |
| false_node = tmp_node; |
| } |
| |
| bool_args.db = db; |
| bool_args.pdb = pdb; |
| bool_args.cond_node = cond_node; |
| |
| if (true_node != NULL) { |
| bool_args.cond_flavor = CIL_CONDTRUE; |
| rc = cil_tree_walk(true_node, __cil_cond_to_policydb_helper, NULL, NULL, &bool_args); |
| if (rc != SEPOL_OK) { |
| cil_tree_log(true_node, CIL_ERR, "Failure while walking true conditional block"); |
| goto exit; |
| } |
| } |
| |
| if (false_node != NULL) { |
| bool_args.cond_flavor = CIL_CONDFALSE; |
| rc = cil_tree_walk(false_node, __cil_cond_to_policydb_helper, NULL, NULL, &bool_args); |
| if (rc != SEPOL_OK) { |
| cil_tree_log(false_node, CIL_ERR, "Failure while walking false conditional block"); |
| goto exit; |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| if (tmp_cond) { |
| if (tmp_cond->expr) |
| cond_expr_destroy(tmp_cond->expr); |
| free(tmp_cond); |
| } |
| return rc; |
| } |
| |
| int cil_roletrans_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_roletransition *roletrans, hashtab_t role_trans_table) |
| { |
| int rc = SEPOL_ERR; |
| role_datum_t *sepol_src = NULL; |
| type_datum_t *sepol_tgt = NULL; |
| class_datum_t *sepol_obj = NULL; |
| struct cil_list *class_list = NULL; |
| role_datum_t *sepol_result = NULL; |
| role_trans_t *new = NULL; |
| uint32_t *new_role = NULL; |
| ebitmap_t role_bitmap, type_bitmap; |
| ebitmap_node_t *rnode, *tnode; |
| unsigned int i, j; |
| struct cil_list_item *c; |
| |
| rc = __cil_expand_role(DATUM(roletrans->src), &role_bitmap); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = __cil_expand_type(roletrans->tgt, &type_bitmap); |
| if (rc != SEPOL_OK) goto exit; |
| |
| class_list = cil_expand_class(roletrans->obj); |
| |
| rc = __cil_get_sepol_role_datum(pdb, DATUM(roletrans->result), &sepol_result); |
| if (rc != SEPOL_OK) goto exit; |
| |
| ebitmap_for_each_positive_bit(&role_bitmap, rnode, i) { |
| rc = __cil_get_sepol_role_datum(pdb, DATUM(db->val_to_role[i]), &sepol_src); |
| if (rc != SEPOL_OK) goto exit; |
| |
| ebitmap_for_each_positive_bit(&type_bitmap, tnode, j) { |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[j]), &sepol_tgt); |
| if (rc != SEPOL_OK) goto exit; |
| |
| cil_list_for_each(c, class_list) { |
| int add = CIL_TRUE; |
| rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj); |
| if (rc != SEPOL_OK) goto exit; |
| |
| new = cil_malloc(sizeof(*new)); |
| memset(new, 0, sizeof(*new)); |
| new->role = sepol_src->s.value; |
| new->type = sepol_tgt->s.value; |
| new->tclass = sepol_obj->s.value; |
| new->new_role = sepol_result->s.value; |
| |
| rc = hashtab_insert(role_trans_table, (hashtab_key_t)new, &(new->new_role)); |
| if (rc != SEPOL_OK) { |
| if (rc == SEPOL_EEXIST) { |
| add = CIL_FALSE; |
| new_role = hashtab_search(role_trans_table, (hashtab_key_t)new); |
| if (new->new_role != *new_role) { |
| cil_log(CIL_ERR, "Conflicting role transition rules\n"); |
| } else { |
| rc = SEPOL_OK; |
| } |
| } else { |
| cil_log(CIL_ERR, "Out of memory\n"); |
| } |
| } |
| |
| if (add == CIL_TRUE) { |
| new->next = pdb->role_tr; |
| pdb->role_tr = new; |
| } else { |
| free(new); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| } |
| } |
| } |
| |
| rc = SEPOL_OK; |
| |
| exit: |
| ebitmap_destroy(&role_bitmap); |
| ebitmap_destroy(&type_bitmap); |
| cil_list_destroy(&class_list, CIL_FALSE); |
| return rc; |
| } |
| |
| int cil_roleallow_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_roleallow *roleallow) |
| { |
| int rc = SEPOL_ERR; |
| role_datum_t *sepol_src = NULL; |
| role_datum_t *sepol_tgt = NULL; |
| role_allow_t *sepol_roleallow = NULL; |
| ebitmap_t src_bitmap, tgt_bitmap; |
| ebitmap_node_t *node1, *node2; |
| unsigned int i, j; |
| |
| rc = __cil_expand_role(roleallow->src, &src_bitmap); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = __cil_expand_role(roleallow->tgt, &tgt_bitmap); |
| if (rc != SEPOL_OK) goto exit; |
| |
| ebitmap_for_each_positive_bit(&src_bitmap, node1, i) { |
| rc = __cil_get_sepol_role_datum(pdb, DATUM(db->val_to_role[i]), &sepol_src); |
| if (rc != SEPOL_OK) goto exit; |
| |
| ebitmap_for_each_positive_bit(&tgt_bitmap, node2, j) { |
| rc = __cil_get_sepol_role_datum(pdb, DATUM(db->val_to_role[j]), &sepol_tgt); |
| if (rc != SEPOL_OK) goto exit; |
| |
| sepol_roleallow = cil_malloc(sizeof(*sepol_roleallow)); |
| memset(sepol_roleallow, 0, sizeof(role_allow_t)); |
| sepol_roleallow->role = sepol_src->s.value; |
| sepol_roleallow->new_role = sepol_tgt->s.value; |
| |
| sepol_roleallow->next = pdb->role_allow; |
| pdb->role_allow = sepol_roleallow; |
| } |
| } |
| |
| rc = SEPOL_OK; |
| |
| exit: |
| ebitmap_destroy(&src_bitmap); |
| ebitmap_destroy(&tgt_bitmap); |
| return rc; |
| } |
| |
| static int __cil_constrain_expr_datum_to_sepol_expr(policydb_t *pdb, const struct cil_db *db, struct cil_list_item *item, enum cil_flavor expr_flavor, constraint_expr_t *expr) |
| { |
| int rc = SEPOL_ERR; |
| |
| if (expr_flavor == CIL_USER) { |
| user_datum_t *sepol_user = NULL; |
| ebitmap_t user_bitmap; |
| ebitmap_node_t *unode; |
| unsigned int i; |
| |
| rc = __cil_expand_user(item->data, &user_bitmap); |
| if (rc != SEPOL_OK) goto exit; |
| |
| ebitmap_for_each_positive_bit(&user_bitmap, unode, i) { |
| rc = __cil_get_sepol_user_datum(pdb, DATUM(db->val_to_user[i]), &sepol_user); |
| if (rc != SEPOL_OK) { |
| ebitmap_destroy(&user_bitmap); |
| goto exit; |
| } |
| |
| if (ebitmap_set_bit(&expr->names, sepol_user->s.value - 1, 1)) { |
| ebitmap_destroy(&user_bitmap); |
| goto exit; |
| } |
| } |
| ebitmap_destroy(&user_bitmap); |
| } else if (expr_flavor == CIL_ROLE) { |
| role_datum_t *sepol_role = NULL; |
| ebitmap_t role_bitmap; |
| ebitmap_node_t *rnode; |
| unsigned int i; |
| |
| rc = __cil_expand_role(item->data, &role_bitmap); |
| if (rc != SEPOL_OK) goto exit; |
| |
| ebitmap_for_each_positive_bit(&role_bitmap, rnode, i) { |
| rc = __cil_get_sepol_role_datum(pdb, DATUM(db->val_to_role[i]), &sepol_role); |
| if (rc != SEPOL_OK) { |
| ebitmap_destroy(&role_bitmap); |
| goto exit; |
| } |
| |
| if (ebitmap_set_bit(&expr->names, sepol_role->s.value - 1, 1)) { |
| ebitmap_destroy(&role_bitmap); |
| goto exit; |
| } |
| } |
| ebitmap_destroy(&role_bitmap); |
| } else if (expr_flavor == CIL_TYPE) { |
| type_datum_t *sepol_type = NULL; |
| ebitmap_t type_bitmap; |
| ebitmap_node_t *tnode; |
| unsigned int i; |
| |
| if (pdb->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES) { |
| rc = __cil_get_sepol_type_datum(pdb, item->data, &sepol_type); |
| if (rc != SEPOL_OK) { |
| if (FLAVOR(item->data) == CIL_TYPEATTRIBUTE) { |
| struct cil_typeattribute *attr = item->data; |
| if (!attr->keep) { |
| rc = 0; |
| } |
| } |
| } |
| |
| if (sepol_type) { |
| rc = ebitmap_set_bit(&expr->type_names->types, sepol_type->s.value - 1, 1); |
| } |
| |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| |
| rc = __cil_expand_type(item->data, &type_bitmap); |
| if (rc != SEPOL_OK) goto exit; |
| |
| ebitmap_for_each_positive_bit(&type_bitmap, tnode, i) { |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_type); |
| if (rc != SEPOL_OK) { |
| ebitmap_destroy(&type_bitmap); |
| goto exit; |
| } |
| |
| if (ebitmap_set_bit(&expr->names, sepol_type->s.value - 1, 1)) { |
| ebitmap_destroy(&type_bitmap); |
| goto exit; |
| } |
| } |
| ebitmap_destroy(&type_bitmap); |
| } else { |
| goto exit; |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return SEPOL_ERR; |
| } |
| |
| static int __cil_constrain_expr_leaf_to_sepol_expr(policydb_t *pdb, const struct cil_db *db, struct cil_list_item *op_item, enum cil_flavor expr_flavor, constraint_expr_t *expr) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_list_item *l_item = op_item->next; |
| struct cil_list_item *r_item = op_item->next->next; |
| |
| enum cil_flavor l_operand = (enum cil_flavor)(uintptr_t)l_item->data; |
| |
| switch (l_operand) { |
| case CIL_CONS_U1: |
| expr->attr = CEXPR_USER; |
| break; |
| case CIL_CONS_U2: |
| expr->attr = CEXPR_USER | CEXPR_TARGET; |
| break; |
| case CIL_CONS_U3: |
| expr->attr = CEXPR_USER | CEXPR_XTARGET; |
| break; |
| case CIL_CONS_R1: |
| expr->attr = CEXPR_ROLE; |
| break; |
| case CIL_CONS_R2: |
| expr->attr = CEXPR_ROLE | CEXPR_TARGET; |
| break; |
| case CIL_CONS_R3: |
| expr->attr = CEXPR_ROLE | CEXPR_XTARGET; |
| break; |
| case CIL_CONS_T1: |
| expr->attr = CEXPR_TYPE; |
| break; |
| case CIL_CONS_T2: |
| expr->attr = CEXPR_TYPE | CEXPR_TARGET; |
| break; |
| case CIL_CONS_T3: |
| expr->attr = CEXPR_TYPE | CEXPR_XTARGET; |
| break; |
| case CIL_CONS_L1: { |
| enum cil_flavor r_operand = (enum cil_flavor)(uintptr_t)r_item->data; |
| |
| if (r_operand == CIL_CONS_L2) { |
| expr->attr = CEXPR_L1L2; |
| } else if (r_operand == CIL_CONS_H1) { |
| expr->attr = CEXPR_L1H1; |
| } else { |
| expr->attr = CEXPR_L1H2; |
| } |
| break; |
| } |
| case CIL_CONS_L2: |
| expr->attr = CEXPR_L2H2; |
| break; |
| case CIL_CONS_H1: { |
| enum cil_flavor r_operand = (enum cil_flavor)(uintptr_t)r_item->data; |
| if (r_operand == CIL_CONS_L2) { |
| expr->attr = CEXPR_H1L2; |
| } else { |
| expr->attr = CEXPR_H1H2; |
| } |
| break; |
| } |
| default: |
| goto exit; |
| break; |
| } |
| |
| if (r_item->flavor == CIL_CONS_OPERAND) { |
| expr->expr_type = CEXPR_ATTR; |
| } else { |
| expr->expr_type = CEXPR_NAMES; |
| if (r_item->flavor == CIL_DATUM) { |
| rc = __cil_constrain_expr_datum_to_sepol_expr(pdb, db, r_item, expr_flavor, expr); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } else if (r_item->flavor == CIL_LIST) { |
| struct cil_list *r_expr = r_item->data; |
| struct cil_list_item *curr; |
| cil_list_for_each(curr, r_expr) { |
| rc = __cil_constrain_expr_datum_to_sepol_expr(pdb, db, curr, expr_flavor, expr); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| } else { |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| static int __cil_constrain_expr_to_sepol_expr_helper(policydb_t *pdb, const struct cil_db *db, const struct cil_list *cil_expr, constraint_expr_t **head, constraint_expr_t **tail) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_list_item *item; |
| enum cil_flavor flavor; |
| enum cil_flavor cil_op; |
| constraint_expr_t *op, *h1, *h2, *t1, *t2; |
| int is_leaf = CIL_FALSE; |
| |
| if (cil_expr == NULL) { |
| return SEPOL_ERR; |
| } |
| |
| item = cil_expr->head; |
| flavor = cil_expr->flavor; |
| |
| op = cil_malloc(sizeof(constraint_expr_t)); |
| rc = constraint_expr_init(op); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| cil_op = (enum cil_flavor)(uintptr_t)item->data; |
| switch (cil_op) { |
| case CIL_NOT: |
| op->expr_type = CEXPR_NOT; |
| break; |
| case CIL_AND: |
| op->expr_type = CEXPR_AND; |
| break; |
| case CIL_OR: |
| op->expr_type = CEXPR_OR; |
| break; |
| case CIL_EQ: |
| op->op = CEXPR_EQ; |
| is_leaf = CIL_TRUE; |
| break; |
| case CIL_NEQ: |
| op->op = CEXPR_NEQ; |
| is_leaf = CIL_TRUE; |
| break; |
| case CIL_CONS_DOM: |
| op->op = CEXPR_DOM; |
| is_leaf = CIL_TRUE; |
| break; |
| case CIL_CONS_DOMBY: |
| op->op = CEXPR_DOMBY; |
| is_leaf = CIL_TRUE; |
| break; |
| case CIL_CONS_INCOMP: |
| op->op = CEXPR_INCOMP; |
| is_leaf = CIL_TRUE; |
| break; |
| default: |
| goto exit; |
| } |
| |
| if (is_leaf == CIL_TRUE) { |
| rc = __cil_constrain_expr_leaf_to_sepol_expr(pdb, db, item, flavor, op); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| *head = op; |
| *tail = op; |
| } else if (cil_op == CIL_NOT) { |
| struct cil_list *l_expr = item->next->data; |
| rc = __cil_constrain_expr_to_sepol_expr_helper(pdb, db, l_expr, &h1, &t1); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| t1->next = op; |
| *head = h1; |
| *tail = op; |
| } else { |
| struct cil_list *l_expr = item->next->data; |
| struct cil_list *r_expr = item->next->next->data; |
| rc = __cil_constrain_expr_to_sepol_expr_helper(pdb, db, l_expr, &h1, &t1); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| rc = __cil_constrain_expr_to_sepol_expr_helper(pdb, db, r_expr, &h2, &t2); |
| if (rc != SEPOL_OK) { |
| constraint_expr_destroy(h1); |
| goto exit; |
| } |
| t1->next = h2; |
| t2->next = op; |
| *head = h1; |
| *tail = op; |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| constraint_expr_destroy(op); |
| return SEPOL_ERR; |
| } |
| |
| static int __cil_constrain_expr_to_sepol_expr(policydb_t *pdb, const struct cil_db *db, const struct cil_list *cil_expr, constraint_expr_t **sepol_expr) |
| { |
| int rc; |
| constraint_expr_t *head, *tail; |
| |
| rc = __cil_constrain_expr_to_sepol_expr_helper(pdb, db, cil_expr, &head, &tail); |
| if (rc != SEPOL_OK) { |
| return SEPOL_ERR; |
| } |
| |
| *sepol_expr = head; |
| |
| return SEPOL_OK; |
| } |
| |
| static int __cil_validate_constrain_expr(constraint_expr_t *sepol_expr) |
| { |
| constraint_expr_t *e; |
| int depth = -1; |
| |
| for (e = sepol_expr; e != NULL; e = e->next) { |
| switch (e->expr_type) { |
| case CEXPR_NOT: |
| if (depth < 0) { |
| cil_log(CIL_ERR,"Invalid constraint expression\n"); |
| return SEPOL_ERR; |
| } |
| break; |
| case CEXPR_AND: |
| case CEXPR_OR: |
| if (depth < 1) { |
| cil_log(CIL_ERR,"Invalid constraint expression\n"); |
| return SEPOL_ERR; |
| } |
| depth--; |
| break; |
| case CEXPR_ATTR: |
| case CEXPR_NAMES: |
| if (depth == (CEXPR_MAXDEPTH - 1)) { |
| cil_log(CIL_ERR,"Constraint expression exceeded max allowable depth\n"); |
| return SEPOL_ERR; |
| } |
| depth++; |
| break; |
| default: |
| cil_log(CIL_ERR,"Invalid constraint expression\n"); |
| return SEPOL_ERR; |
| } |
| } |
| |
| if (depth != 0) { |
| cil_log(CIL_ERR,"Invalid constraint expression\n"); |
| return SEPOL_ERR; |
| } |
| |
| return SEPOL_OK; |
| } |
| |
| static int cil_constrain_to_policydb_helper(policydb_t *pdb, const struct cil_db *db, struct cil_symtab_datum *class, struct cil_list *perms, struct cil_list *expr) |
| { |
| int rc = SEPOL_ERR; |
| constraint_node_t *sepol_constrain = NULL; |
| constraint_expr_t *sepol_expr = NULL; |
| class_datum_t *sepol_class = NULL; |
| |
| sepol_constrain = cil_malloc(sizeof(*sepol_constrain)); |
| memset(sepol_constrain, 0, sizeof(constraint_node_t)); |
| |
| rc = __cil_get_sepol_class_datum(pdb, class, &sepol_class); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = __cil_perms_to_datum(perms, sepol_class, &sepol_constrain->permissions); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| if (sepol_constrain->permissions == 0) { |
| /* No permissions, so don't insert rule. */ |
| free(sepol_constrain); |
| return SEPOL_OK; |
| } |
| |
| rc = __cil_constrain_expr_to_sepol_expr(pdb, db, expr, &sepol_expr); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = __cil_validate_constrain_expr(sepol_expr); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| sepol_constrain->expr = sepol_expr; |
| sepol_constrain->next = sepol_class->constraints; |
| sepol_class->constraints = sepol_constrain; |
| |
| return SEPOL_OK; |
| |
| exit: |
| constraint_expr_destroy(sepol_expr); |
| free(sepol_constrain); |
| return rc; |
| } |
| |
| static int cil_constrain_expand(policydb_t *pdb, const struct cil_db *db, struct cil_list *classperms, struct cil_list *expr) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_list_item *curr; |
| |
| cil_list_for_each(curr, classperms) { |
| if (curr->flavor == CIL_CLASSPERMS) { |
| struct cil_classperms *cp = curr->data; |
| if (FLAVOR(cp->class) == CIL_CLASS) { |
| rc = cil_constrain_to_policydb_helper(pdb, db, DATUM(cp->class), cp->perms, expr); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } else { /* MAP */ |
| struct cil_list_item *i = NULL; |
| cil_list_for_each(i, cp->perms) { |
| struct cil_perm *cmp = i->data; |
| rc = cil_constrain_expand(pdb, db, cmp->classperms, expr); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| } |
| } else { /* SET */ |
| struct cil_classperms_set *cp_set = curr->data; |
| struct cil_classpermission *cp = cp_set->set; |
| rc = cil_constrain_expand(pdb, db, cp->classperms, expr); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| int cil_constrain_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_constrain *cil_constrain) |
| { |
| int rc = SEPOL_ERR; |
| rc = cil_constrain_expand(pdb, db, cil_constrain->classperms, cil_constrain->datum_expr); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| cil_log(CIL_ERR, "Failed to insert constraint into policydb\n"); |
| return rc; |
| } |
| |
| static int cil_validatetrans_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_validatetrans *cil_validatetrans) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_list *expr = cil_validatetrans->datum_expr; |
| class_datum_t *sepol_class = NULL; |
| struct cil_list *class_list; |
| constraint_node_t *sepol_validatetrans = NULL; |
| constraint_expr_t *sepol_expr = NULL; |
| struct cil_list_item *c; |
| |
| class_list = cil_expand_class(cil_validatetrans->class); |
| |
| cil_list_for_each(c, class_list) { |
| rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_class); |
| if (rc != SEPOL_OK) goto exit; |
| |
| sepol_validatetrans = cil_malloc(sizeof(*sepol_validatetrans)); |
| memset(sepol_validatetrans, 0, sizeof(constraint_node_t)); |
| |
| rc = __cil_constrain_expr_to_sepol_expr(pdb, db, expr, &sepol_expr); |
| if (rc != SEPOL_OK) { |
| free(sepol_validatetrans); |
| goto exit; |
| } |
| sepol_validatetrans->expr = sepol_expr; |
| |
| sepol_validatetrans->next = sepol_class->validatetrans; |
| sepol_class->validatetrans = sepol_validatetrans; |
| } |
| |
| rc = SEPOL_OK; |
| |
| exit: |
| cil_list_destroy(&class_list, CIL_FALSE); |
| return rc; |
| } |
| |
| static int __cil_cats_to_mls_level(policydb_t *pdb, struct cil_cats *cats, mls_level_t *mls_level) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_list_item *i; |
| cat_datum_t *sepol_cat = NULL; |
| |
| cil_list_for_each(i, cats->datum_expr) { |
| struct cil_tree_node *node = NODE(i->data); |
| if (node->flavor == CIL_CATSET) { |
| struct cil_list_item *j; |
| struct cil_catset *cs = i->data; |
| cil_list_for_each(j, cs->cats->datum_expr) { |
| rc = __cil_get_sepol_cat_datum(pdb, j->data, &sepol_cat); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = ebitmap_set_bit(&mls_level->cat, sepol_cat->s.value - 1, 1); |
| if (rc != SEPOL_OK) goto exit; |
| } |
| } else { |
| rc = __cil_get_sepol_cat_datum(pdb, i->data, &sepol_cat); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = ebitmap_set_bit(&mls_level->cat, sepol_cat->s.value - 1, 1); |
| if (rc != SEPOL_OK) goto exit; |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return SEPOL_ERR; |
| } |
| |
| int cil_sepol_level_define(policydb_t *pdb, struct cil_sens *cil_sens) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_list_item *curr; |
| level_datum_t *sepol_level = NULL; |
| mls_level_t *mls_level = NULL; |
| |
| rc = __cil_get_sepol_level_datum(pdb, DATUM(cil_sens), &sepol_level); |
| if (rc != SEPOL_OK) goto exit; |
| |
| mls_level = sepol_level->level; |
| |
| ebitmap_init(&mls_level->cat); |
| |
| if (cil_sens->cats_list) { |
| cil_list_for_each(curr, cil_sens->cats_list) { |
| struct cil_cats *cats = curr->data; |
| rc = __cil_cats_to_mls_level(pdb, cats, mls_level); |
| if (rc != SEPOL_OK) { |
| cil_log(CIL_INFO, "Failed to insert category set into sepol mls level\n"); |
| goto exit; |
| } |
| } |
| } |
| |
| sepol_level->defined = 1; |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| int cil_level_to_mls_level(policydb_t *pdb, struct cil_level *cil_level, mls_level_t *mls_level) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_sens *cil_sens = cil_level->sens; |
| struct cil_cats *cats = cil_level->cats; |
| level_datum_t *sepol_level = NULL; |
| |
| rc = __cil_get_sepol_level_datum(pdb, DATUM(cil_sens), &sepol_level); |
| if (rc != SEPOL_OK) goto exit; |
| |
| mls_level->sens = sepol_level->level->sens; |
| |
| ebitmap_init(&mls_level->cat); |
| |
| if (cats != NULL) { |
| rc = __cil_cats_to_mls_level(pdb, cats, mls_level); |
| if (rc != SEPOL_OK) { |
| cil_log(CIL_INFO, "Failed to insert category set into sepol mls level\n"); |
| goto exit; |
| } |
| } |
| |
| rc = SEPOL_OK; |
| exit: |
| return rc; |
| } |
| |
| static int __cil_levelrange_to_mls_range(policydb_t *pdb, struct cil_levelrange *cil_lvlrange, mls_range_t *mls_range) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_level *low = cil_lvlrange->low; |
| struct cil_level *high = cil_lvlrange->high; |
| mls_level_t *mls_level = NULL; |
| |
| mls_level = &mls_range->level[0]; |
| |
| rc = cil_level_to_mls_level(pdb, low, mls_level); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| mls_level = &mls_range->level[1]; |
| |
| rc = cil_level_to_mls_level(pdb, high, mls_level); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| static int cil_userlevel_userrange_to_policydb(policydb_t *pdb, struct cil_user *cil_user) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_level *cil_level = cil_user->dftlevel; |
| struct cil_levelrange *cil_levelrange = cil_user->range; |
| user_datum_t *sepol_user = NULL; |
| |
| rc = __cil_get_sepol_user_datum(pdb, DATUM(cil_user), &sepol_user); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = cil_level_to_mls_level(pdb, cil_level, &sepol_user->exp_dfltlevel); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = __cil_levelrange_to_mls_range(pdb, cil_levelrange, &sepol_user->exp_range); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| static int __cil_context_to_sepol_context(policydb_t *pdb, struct cil_context *cil_context, context_struct_t *sepol_context) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_levelrange *cil_lvlrange = cil_context->range; |
| user_datum_t *sepol_user = NULL; |
| role_datum_t *sepol_role = NULL; |
| type_datum_t *sepol_type = NULL; |
| |
| rc = __cil_get_sepol_user_datum(pdb, DATUM(cil_context->user), &sepol_user); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = __cil_get_sepol_role_datum(pdb, DATUM(cil_context->role), &sepol_role); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(cil_context->type), &sepol_type); |
| if (rc != SEPOL_OK) goto exit; |
| |
| sepol_context->user = sepol_user->s.value; |
| sepol_context->role = sepol_role->s.value; |
| sepol_context->type = sepol_type->s.value; |
| |
| if (pdb->mls == CIL_TRUE) { |
| mls_context_init(sepol_context); |
| |
| rc = __cil_levelrange_to_mls_range(pdb, cil_lvlrange, &sepol_context->range); |
| if (rc != SEPOL_OK) { |
| cil_log(CIL_ERR,"Problem with MLS\n"); |
| mls_context_destroy(sepol_context); |
| goto exit; |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| static int cil_sidorder_to_policydb(policydb_t *pdb, const struct cil_db *db) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_list_item *curr; |
| unsigned count = 0; |
| ocontext_t *tail = NULL; |
| |
| if (db->sidorder == NULL || db->sidorder->head == NULL) { |
| cil_log(CIL_WARN, "No sidorder statement in policy\n"); |
| return SEPOL_OK; |
| } |
| |
| cil_list_for_each(curr, db->sidorder) { |
| struct cil_sid *cil_sid = (struct cil_sid*)curr->data; |
| struct cil_context *cil_context = cil_sid->context; |
| |
| /* even if no context, we must preserve initial SID values */ |
| count++; |
| |
| if (cil_context != NULL) { |
| ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_ISID], &tail); |
| new_ocon->sid[0] = count; |
| new_ocon->u.name = cil_strdup(cil_sid->datum.fqn); |
| rc = __cil_context_to_sepol_context(pdb, cil_context, &new_ocon->context[0]); |
| if (rc != SEPOL_OK) { |
| cil_log(CIL_ERR,"Problem with context for SID %s\n",cil_sid->datum.fqn); |
| goto exit; |
| } |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| int cil_rangetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_rangetransition *rangetrans) |
| { |
| int rc = SEPOL_ERR; |
| type_datum_t *sepol_src = NULL; |
| type_datum_t *sepol_tgt = NULL; |
| class_datum_t *sepol_class = NULL; |
| struct cil_list *class_list = NULL; |
| range_trans_t *newkey = NULL; |
| struct mls_range *newdatum = NULL; |
| ebitmap_t src_bitmap, tgt_bitmap; |
| ebitmap_node_t *node1, *node2; |
| unsigned int i, j; |
| struct cil_list_item *c; |
| struct mls_range *o_range = NULL; |
| |
| rc = __cil_expand_type(rangetrans->src, &src_bitmap); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = __cil_expand_type(rangetrans->exec, &tgt_bitmap); |
| if (rc != SEPOL_OK) goto exit; |
| |
| class_list = cil_expand_class(rangetrans->obj); |
| |
| ebitmap_for_each_positive_bit(&src_bitmap, node1, i) { |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[i]), &sepol_src); |
| if (rc != SEPOL_OK) goto exit; |
| |
| ebitmap_for_each_positive_bit(&tgt_bitmap, node2, j) { |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(db->val_to_type[j]), &sepol_tgt); |
| if (rc != SEPOL_OK) goto exit; |
| |
| cil_list_for_each(c, class_list) { |
| rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_class); |
| if (rc != SEPOL_OK) goto exit; |
| |
| newkey = cil_calloc(1, sizeof(*newkey)); |
| newdatum = cil_calloc(1, sizeof(*newdatum)); |
| newkey->source_type = sepol_src->s.value; |
| newkey->target_type = sepol_tgt->s.value; |
| newkey->target_class = sepol_class->s.value; |
| rc = __cil_levelrange_to_mls_range(pdb, rangetrans->range, newdatum); |
| if (rc != SEPOL_OK) { |
| free(newkey); |
| free(newdatum); |
| goto exit; |
| } |
| |
| rc = hashtab_insert(pdb->range_tr, (hashtab_key_t)newkey, newdatum); |
| if (rc != SEPOL_OK) { |
| if (rc == SEPOL_EEXIST) { |
| o_range = hashtab_search(pdb->range_tr, (hashtab_key_t)newkey); |
| if (!mls_range_eq(newdatum, o_range)) { |
| cil_log(CIL_ERR, "Conflicting Range transition rules\n"); |
| } else { |
| rc = SEPOL_OK; |
| } |
| } else { |
| cil_log(CIL_ERR, "Out of memory\n"); |
| } |
| // TODO: add upper version bound once fixed in upstream GCC |
| #if defined(__GNUC__) && (__GNUC__ >= 12) |
| # pragma GCC diagnostic push |
| # pragma GCC diagnostic ignored "-Warray-bounds" |
| # pragma GCC diagnostic ignored "-Wstringop-overflow" |
| #endif |
| mls_range_destroy(newdatum); |
| #if defined(__GNUC__) && (__GNUC__ >= 12) |
| # pragma GCC diagnostic pop |
| #endif |
| free(newdatum); |
| free(newkey); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| } |
| } |
| } |
| |
| rc = SEPOL_OK; |
| |
| exit: |
| ebitmap_destroy(&src_bitmap); |
| ebitmap_destroy(&tgt_bitmap); |
| cil_list_destroy(&class_list, CIL_FALSE); |
| return rc; |
| } |
| |
| int cil_ibpkeycon_to_policydb(policydb_t *pdb, struct cil_sort *ibpkeycons) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t i = 0; |
| ocontext_t *tail = NULL; |
| struct in6_addr subnet_prefix; |
| |
| for (i = 0; i < ibpkeycons->count; i++) { |
| struct cil_ibpkeycon *cil_ibpkeycon = ibpkeycons->array[i]; |
| ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_IBPKEY], &tail); |
| |
| rc = inet_pton(AF_INET6, cil_ibpkeycon->subnet_prefix_str, &subnet_prefix); |
| if (rc != 1) { |
| cil_log(CIL_ERR, "ibpkeycon subnet prefix not in valid IPV6 format\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| |
| memcpy(&new_ocon->u.ibpkey.subnet_prefix, &subnet_prefix.s6_addr[0], |
| sizeof(new_ocon->u.ibpkey.subnet_prefix)); |
| new_ocon->u.ibpkey.low_pkey = cil_ibpkeycon->pkey_low; |
| new_ocon->u.ibpkey.high_pkey = cil_ibpkeycon->pkey_high; |
| |
| rc = __cil_context_to_sepol_context(pdb, cil_ibpkeycon->context, &new_ocon->context[0]); |
| if (rc != SEPOL_OK) |
| goto exit; |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| int cil_portcon_to_policydb(policydb_t *pdb, struct cil_sort *portcons) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t i = 0; |
| ocontext_t *tail = NULL; |
| |
| for (i = 0; i < portcons->count; i++) { |
| struct cil_portcon *cil_portcon = portcons->array[i]; |
| ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_PORT], &tail); |
| |
| switch (cil_portcon->proto) { |
| case CIL_PROTOCOL_UDP: |
| new_ocon->u.port.protocol = IPPROTO_UDP; |
| break; |
| case CIL_PROTOCOL_TCP: |
| new_ocon->u.port.protocol = IPPROTO_TCP; |
| break; |
| case CIL_PROTOCOL_DCCP: |
| new_ocon->u.port.protocol = IPPROTO_DCCP; |
| break; |
| case CIL_PROTOCOL_SCTP: |
| new_ocon->u.port.protocol = IPPROTO_SCTP; |
| break; |
| default: |
| /* should not get here */ |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| |
| new_ocon->u.port.low_port = cil_portcon->port_low; |
| new_ocon->u.port.high_port = cil_portcon->port_high; |
| |
| rc = __cil_context_to_sepol_context(pdb, cil_portcon->context, &new_ocon->context[0]); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| int cil_netifcon_to_policydb(policydb_t *pdb, struct cil_sort *netifcons) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t i = 0; |
| ocontext_t *tail = NULL; |
| |
| for (i = 0; i < netifcons->count; i++) { |
| ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_NETIF], &tail); |
| struct cil_netifcon *cil_netifcon = netifcons->array[i]; |
| |
| new_ocon->u.name = cil_strdup(cil_netifcon->interface_str); |
| |
| rc = __cil_context_to_sepol_context(pdb, cil_netifcon->if_context, &new_ocon->context[0]); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = __cil_context_to_sepol_context(pdb, cil_netifcon->packet_context, &new_ocon->context[1]); |
| if (rc != SEPOL_OK) { |
| context_destroy(&new_ocon->context[0]); |
| goto exit; |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| int cil_ibendportcon_to_policydb(policydb_t *pdb, struct cil_sort *ibendportcons) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t i; |
| ocontext_t *tail = NULL; |
| |
| for (i = 0; i < ibendportcons->count; i++) { |
| ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_IBENDPORT], &tail); |
| struct cil_ibendportcon *cil_ibendportcon = ibendportcons->array[i]; |
| |
| new_ocon->u.ibendport.dev_name = cil_strdup(cil_ibendportcon->dev_name_str); |
| new_ocon->u.ibendport.port = cil_ibendportcon->port; |
| |
| rc = __cil_context_to_sepol_context(pdb, cil_ibendportcon->context, &new_ocon->context[0]); |
| if (rc != SEPOL_OK) |
| goto exit; |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| int cil_nodecon_to_policydb(policydb_t *pdb, struct cil_sort *nodecons) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t i = 0; |
| ocontext_t *tail = NULL; |
| ocontext_t *tail6 = NULL; |
| |
| for (i = 0; i < nodecons->count; i++) { |
| ocontext_t *new_ocon = NULL; |
| struct cil_nodecon *cil_nodecon = nodecons->array[i]; |
| |
| if (cil_nodecon->addr->family == AF_INET) { |
| new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_NODE], &tail); |
| new_ocon->u.node.addr = cil_nodecon->addr->ip.v4.s_addr; |
| new_ocon->u.node.mask = cil_nodecon->mask->ip.v4.s_addr; |
| } else if (cil_nodecon->addr->family == AF_INET6) { |
| new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_NODE6], &tail6); |
| memcpy(new_ocon->u.node6.addr, &cil_nodecon->addr->ip.v6.s6_addr[0], 16); |
| memcpy(new_ocon->u.node6.mask, &cil_nodecon->mask->ip.v6.s6_addr[0], 16); |
| } else { |
| /* should not get here */ |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| |
| rc = __cil_context_to_sepol_context(pdb, cil_nodecon->context, &new_ocon->context[0]); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| int cil_fsuse_to_policydb(policydb_t *pdb, struct cil_sort *fsuses) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t i = 0; |
| ocontext_t *tail = NULL; |
| |
| for (i = 0; i < fsuses->count; i++) { |
| ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_FSUSE], &tail); |
| struct cil_fsuse *cil_fsuse = fsuses->array[i]; |
| |
| new_ocon->u.name = cil_strdup(cil_fsuse->fs_str); |
| new_ocon->v.behavior = cil_fsuse->type; |
| |
| rc = __cil_context_to_sepol_context(pdb, cil_fsuse->context, &new_ocon->context[0]); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| int cil_genfscon_to_policydb(policydb_t *pdb, struct cil_sort *genfscons) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t i = 0; |
| genfs_t *genfs_tail = NULL; |
| ocontext_t *ocon_tail = NULL; |
| |
| for (i = 0; i < genfscons->count; i++) { |
| struct cil_genfscon *cil_genfscon = genfscons->array[i]; |
| ocontext_t *new_ocon = cil_malloc(sizeof(ocontext_t)); |
| memset(new_ocon, 0, sizeof(ocontext_t)); |
| |
| if (genfs_tail && strcmp(genfs_tail->fstype, cil_genfscon->fs_str) == 0) { |
| ocon_tail->next = new_ocon; |
| } else { |
| genfs_t *new_genfs = cil_malloc(sizeof(genfs_t)); |
| memset(new_genfs, 0, sizeof(genfs_t)); |
| new_genfs->fstype = cil_strdup(cil_genfscon->fs_str); |
| new_genfs->head = new_ocon; |
| |
| if (genfs_tail) { |
| genfs_tail->next = new_genfs; |
| } else { |
| pdb->genfs = new_genfs; |
| } |
| genfs_tail = new_genfs; |
| } |
| |
| ocon_tail = new_ocon; |
| |
| new_ocon->u.name = cil_strdup(cil_genfscon->path_str); |
| |
| if (cil_genfscon->file_type != CIL_FILECON_ANY) { |
| class_datum_t *class_datum; |
| const char *class_name; |
| switch (cil_genfscon->file_type) { |
| case CIL_FILECON_FILE: |
| class_name = "file"; |
| break; |
| case CIL_FILECON_DIR: |
| class_name = "dir"; |
| break; |
| case CIL_FILECON_CHAR: |
| class_name = "chr_file"; |
| break; |
| case CIL_FILECON_BLOCK: |
| class_name = "blk_file"; |
| break; |
| case CIL_FILECON_SOCKET: |
| class_name = "sock_file"; |
| break; |
| case CIL_FILECON_PIPE: |
| class_name = "fifo_file"; |
| break; |
| case CIL_FILECON_SYMLINK: |
| class_name = "lnk_file"; |
| break; |
| default: |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| class_datum = hashtab_search(pdb->p_classes.table, class_name); |
| if (!class_datum) { |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| new_ocon->v.sclass = class_datum->s.value; |
| } |
| |
| rc = __cil_context_to_sepol_context(pdb, cil_genfscon->context, &new_ocon->context[0]); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| int cil_pirqcon_to_policydb(policydb_t *pdb, struct cil_sort *pirqcons) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t i = 0; |
| ocontext_t *tail = NULL; |
| |
| for (i = 0; i < pirqcons->count; i++) { |
| ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_XEN_PIRQ], &tail); |
| struct cil_pirqcon *cil_pirqcon = pirqcons->array[i]; |
| |
| new_ocon->u.pirq = cil_pirqcon->pirq; |
| |
| rc = __cil_context_to_sepol_context(pdb, cil_pirqcon->context, &new_ocon->context[0]); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| int cil_iomemcon_to_policydb(policydb_t *pdb, struct cil_sort *iomemcons) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t i = 0; |
| ocontext_t *tail = NULL; |
| |
| for (i = 0; i < iomemcons->count; i++) { |
| ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_XEN_IOMEM], &tail); |
| struct cil_iomemcon *cil_iomemcon = iomemcons->array[i]; |
| |
| new_ocon->u.iomem.low_iomem = cil_iomemcon->iomem_low; |
| new_ocon->u.iomem.high_iomem = cil_iomemcon->iomem_high; |
| |
| rc = __cil_context_to_sepol_context(pdb, cil_iomemcon->context, &new_ocon->context[0]); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| int cil_ioportcon_to_policydb(policydb_t *pdb, struct cil_sort *ioportcons) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t i = 0; |
| ocontext_t *tail = NULL; |
| |
| for (i = 0; i < ioportcons->count; i++) { |
| ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_XEN_IOPORT], &tail); |
| struct cil_ioportcon *cil_ioportcon = ioportcons->array[i]; |
| |
| new_ocon->u.ioport.low_ioport = cil_ioportcon->ioport_low; |
| new_ocon->u.ioport.high_ioport = cil_ioportcon->ioport_high; |
| |
| rc = __cil_context_to_sepol_context(pdb, cil_ioportcon->context, &new_ocon->context[0]); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| int cil_pcidevicecon_to_policydb(policydb_t *pdb, struct cil_sort *pcidevicecons) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t i = 0; |
| ocontext_t *tail = NULL; |
| |
| for (i = 0; i < pcidevicecons->count; i++) { |
| ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_XEN_PCIDEVICE], &tail); |
| struct cil_pcidevicecon *cil_pcidevicecon = pcidevicecons->array[i]; |
| |
| new_ocon->u.device = cil_pcidevicecon->dev; |
| |
| rc = __cil_context_to_sepol_context(pdb, cil_pcidevicecon->context, &new_ocon->context[0]); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| static int cil_devicetreecon_to_policydb(policydb_t *pdb, struct cil_sort *devicetreecons) |
| { |
| int rc = SEPOL_ERR; |
| uint32_t i = 0; |
| ocontext_t *tail = NULL; |
| |
| for (i = 0; i < devicetreecons->count; i++) { |
| ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_XEN_DEVICETREE], &tail); |
| struct cil_devicetreecon *cil_devicetreecon = devicetreecons->array[i]; |
| |
| new_ocon->u.name = cil_strdup(cil_devicetreecon->path); |
| |
| rc = __cil_context_to_sepol_context(pdb, cil_devicetreecon->context, &new_ocon->context[0]); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| static int cil_default_to_policydb(policydb_t *pdb, struct cil_default *def) |
| { |
| struct cil_list_item *curr; |
| class_datum_t *sepol_class; |
| struct cil_list *class_list = NULL; |
| |
| cil_list_for_each(curr, def->class_datums) { |
| struct cil_list_item *c; |
| |
| class_list = cil_expand_class(curr->data); |
| |
| cil_list_for_each(c, class_list) { |
| int rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_class); |
| if (rc != SEPOL_OK) goto exit; |
| |
| switch (def->flavor) { |
| case CIL_DEFAULTUSER: |
| if (!sepol_class->default_user) { |
| sepol_class->default_user = def->object; |
| } else if (sepol_class->default_user != (char)def->object) { |
| cil_log(CIL_ERR,"User default labeling for class %s already specified\n",DATUM(c->data)->fqn); |
| goto exit; |
| } |
| break; |
| case CIL_DEFAULTROLE: |
| if (!sepol_class->default_role) { |
| sepol_class->default_role = def->object; |
| } else if (sepol_class->default_role != (char)def->object) { |
| cil_log(CIL_ERR,"Role default labeling for class %s already specified\n",DATUM(c->data)->fqn); |
| goto exit; |
| } |
| break; |
| case CIL_DEFAULTTYPE: |
| if (!sepol_class->default_type) { |
| sepol_class->default_type = def->object; |
| } else if (sepol_class->default_type != (char)def->object) { |
| cil_log(CIL_ERR,"Type default labeling for class %s already specified\n",DATUM(c->data)->fqn); |
| goto exit; |
| } |
| break; |
| default: |
| goto exit; |
| } |
| } |
| |
| cil_list_destroy(&class_list, CIL_FALSE); |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| cil_list_destroy(&class_list, CIL_FALSE); |
| return SEPOL_ERR; |
| } |
| |
| static int cil_defaultrange_to_policydb(policydb_t *pdb, struct cil_defaultrange *def) |
| { |
| struct cil_list_item *curr; |
| class_datum_t *sepol_class; |
| struct cil_list *class_list = NULL; |
| |
| cil_list_for_each(curr, def->class_datums) { |
| struct cil_list_item *c; |
| |
| class_list = cil_expand_class(curr->data); |
| |
| cil_list_for_each(c, class_list) { |
| int rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_class); |
| if (rc != SEPOL_OK) goto exit; |
| |
| if (!sepol_class->default_range) { |
| sepol_class->default_range = def->object_range; |
| } else if (sepol_class->default_range != (char)def->object_range) { |
| cil_log(CIL_ERR,"Range default labeling for class %s already specified\n", DATUM(curr->data)->fqn); |
| goto exit; |
| } |
| } |
| |
| cil_list_destroy(&class_list, CIL_FALSE); |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| cil_list_destroy(&class_list, CIL_FALSE); |
| return SEPOL_ERR; |
| } |
| |
| static int __cil_node_to_policydb(struct cil_tree_node *node, void *extra_args) |
| { |
| int rc = SEPOL_OK; |
| int pass; |
| struct cil_args_binary *args = extra_args; |
| const struct cil_db *db; |
| policydb_t *pdb; |
| hashtab_t role_trans_table; |
| void **type_value_to_cil; |
| |
| db = args->db; |
| pdb = args->pdb; |
| pass = args->pass; |
| role_trans_table = args->role_trans_table; |
| type_value_to_cil = args->type_value_to_cil; |
| |
| if (node->flavor >= CIL_MIN_DECLARATIVE) { |
| if (node != NODE(node->data)) { |
| goto exit; |
| } |
| } |
| |
| switch (pass) { |
| case 1: |
| switch (node->flavor) { |
| case CIL_ROLE: |
| rc = cil_role_to_policydb(pdb, node->data); |
| break; |
| case CIL_TYPE: |
| rc = cil_type_to_policydb(pdb, node->data, type_value_to_cil); |
| break; |
| case CIL_TYPEATTRIBUTE: |
| rc = cil_typeattribute_to_policydb(pdb, node->data, type_value_to_cil); |
| break; |
| case CIL_POLICYCAP: |
| rc = cil_policycap_to_policydb(pdb, node->data); |
| break; |
| case CIL_USER: |
| rc = cil_user_to_policydb(pdb, node->data); |
| break; |
| case CIL_BOOL: |
| rc = cil_bool_to_policydb(pdb, node->data); |
| break; |
| case CIL_CATALIAS: |
| if (pdb->mls == CIL_TRUE) { |
| rc = cil_catalias_to_policydb(pdb, node->data); |
| } |
| break; |
| case CIL_SENS: |
| if (pdb->mls == CIL_TRUE) { |
| rc = cil_sepol_level_define(pdb, node->data); |
| } |
| break; |
| default: |
| break; |
| } |
| break; |
| case 2: |
| switch (node->flavor) { |
| case CIL_TYPE: |
| rc = cil_type_bounds_to_policydb(pdb, node->data); |
| break; |
| case CIL_TYPEALIAS: |
| rc = cil_typealias_to_policydb(pdb, node->data); |
| break; |
| case CIL_TYPEPERMISSIVE: |
| rc = cil_typepermissive_to_policydb(pdb, node->data); |
| break; |
| case CIL_TYPEATTRIBUTE: |
| rc = cil_typeattribute_to_bitmap(pdb, db, node->data); |
| break; |
| case CIL_SENSALIAS: |
| if (pdb->mls == CIL_TRUE) { |
| rc = cil_sensalias_to_policydb(pdb, node->data); |
| } |
| break; |
| case CIL_ROLE: |
| rc = cil_role_bounds_to_policydb(pdb, node->data); |
| if (rc != SEPOL_OK) goto exit; |
| rc = cil_roletype_to_policydb(pdb, db, node->data); |
| break; |
| case CIL_USER: |
| rc = cil_user_bounds_to_policydb(pdb, node->data); |
| if (rc != SEPOL_OK) goto exit; |
| if (pdb->mls == CIL_TRUE) { |
| rc = cil_userlevel_userrange_to_policydb(pdb, node->data); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| rc = cil_userrole_to_policydb(pdb, db, node->data); |
| break; |
| case CIL_TYPE_RULE: |
| rc = cil_type_rule_to_policydb(pdb, db, node->data); |
| break; |
| case CIL_AVRULE: |
| case CIL_AVRULEX: { |
| struct cil_avrule *rule = node->data; |
| if (db->disable_neverallow != CIL_TRUE && rule->rule_kind == CIL_AVRULE_NEVERALLOW) { |
| struct cil_list *neverallows = args->neverallows; |
| cil_list_prepend(neverallows, CIL_LIST_ITEM, node); |
| } |
| break; |
| } |
| case CIL_ROLETRANSITION: |
| rc = cil_roletrans_to_policydb(pdb, db, node->data, role_trans_table); |
| break; |
| case CIL_ROLEATTRIBUTESET: |
| /*rc = cil_roleattributeset_to_policydb(pdb, node->data);*/ |
| break; |
| case CIL_NAMETYPETRANSITION: |
| rc = cil_typetransition_to_policydb(pdb, db, node->data); |
| break; |
| case CIL_CONSTRAIN: |
| rc = cil_constrain_to_policydb(pdb, db, node->data); |
| break; |
| case CIL_MLSCONSTRAIN: |
| if (pdb->mls == CIL_TRUE) { |
| rc = cil_constrain_to_policydb(pdb, db, node->data); |
| } |
| break; |
| case CIL_VALIDATETRANS: |
| rc = cil_validatetrans_to_policydb(pdb, db, node->data); |
| break; |
| case CIL_MLSVALIDATETRANS: |
| if (pdb->mls == CIL_TRUE) { |
| rc = cil_validatetrans_to_policydb(pdb, db, node->data); |
| } |
| break; |
| case CIL_RANGETRANSITION: |
| if (pdb->mls == CIL_TRUE) { |
| rc = cil_rangetransition_to_policydb(pdb, db, node->data); |
| } |
| break; |
| case CIL_DEFAULTUSER: |
| case CIL_DEFAULTROLE: |
| case CIL_DEFAULTTYPE: |
| rc = cil_default_to_policydb(pdb, node->data); |
| break; |
| case CIL_DEFAULTRANGE: |
| rc = cil_defaultrange_to_policydb(pdb, node->data); |
| break; |
| default: |
| break; |
| } |
| break; |
| case 3: |
| switch (node->flavor) { |
| case CIL_BOOLEANIF: |
| rc = cil_booleanif_to_policydb(pdb, db, node); |
| break; |
| case CIL_AVRULE: { |
| struct cil_avrule *rule = node->data; |
| if (rule->rule_kind != CIL_AVRULE_NEVERALLOW) { |
| rc = cil_avrule_to_policydb(pdb, db, node->data); |
| } |
| } |
| break; |
| case CIL_AVRULEX: { |
| struct cil_avrule *rule = node->data; |
| if (rule->rule_kind != CIL_AVRULE_NEVERALLOW) { |
| rc = cil_avrulex_to_hashtable(pdb, db, node->data, args); |
| } |
| } |
| break; |
| case CIL_ROLEALLOW: |
| rc = cil_roleallow_to_policydb(pdb, db, node->data); |
| break; |
| default: |
| break; |
| } |
| default: |
| break; |
| } |
| |
| exit: |
| if (rc != SEPOL_OK) { |
| cil_tree_log(node, CIL_ERR, "Binary policy creation failed"); |
| } |
| return rc; |
| } |
| |
| static int __cil_binary_create_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args) |
| { |
| int rc = SEPOL_ERR; |
| |
| if (node->flavor == CIL_BLOCK) { |
| struct cil_block *blk = node->data; |
| if (blk->is_abstract == CIL_TRUE) { |
| *finished = CIL_TREE_SKIP_HEAD; |
| rc = SEPOL_OK; |
| goto exit; |
| } |
| } else if (node->flavor == CIL_MACRO) { |
| *finished = CIL_TREE_SKIP_HEAD; |
| rc = SEPOL_OK; |
| goto exit; |
| } else if (node->flavor == CIL_BOOLEANIF) { |
| *finished = CIL_TREE_SKIP_HEAD; |
| } |
| |
| rc = __cil_node_to_policydb(node, extra_args); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| exit: |
| return rc; |
| } |
| |
| static int __cil_contexts_to_policydb(policydb_t *pdb, const struct cil_db *db) |
| { |
| int rc = SEPOL_ERR; |
| |
| rc = cil_portcon_to_policydb(pdb, db->portcon); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = cil_netifcon_to_policydb(pdb, db->netifcon); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = cil_nodecon_to_policydb(pdb, db->nodecon); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = cil_fsuse_to_policydb(pdb, db->fsuse); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = cil_genfscon_to_policydb(pdb, db->genfscon); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = cil_ibpkeycon_to_policydb(pdb, db->ibpkeycon); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = cil_ibendportcon_to_policydb(pdb, db->ibendportcon); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| if (db->target_platform == SEPOL_TARGET_XEN) { |
| rc = cil_pirqcon_to_policydb(pdb, db->pirqcon); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = cil_iomemcon_to_policydb(pdb, db->iomemcon); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = cil_ioportcon_to_policydb(pdb, db->ioportcon); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = cil_pcidevicecon_to_policydb(pdb, db->pcidevicecon); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = cil_devicetreecon_to_policydb(pdb, db->devicetreecon); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| return SEPOL_OK; |
| exit: |
| return rc; |
| } |
| |
| static int __cil_common_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) |
| { |
| policydb_t *pdb = data; |
| common_datum_t *common = (common_datum_t *)datum; |
| |
| if (common->s.value < 1 || common->s.value > pdb->p_commons.nprim) { |
| return -EINVAL; |
| } |
| pdb->p_common_val_to_name[common->s.value - 1] = (char *)key; |
| |
| return 0; |
| } |
| |
| static int __cil_class_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) |
| { |
| policydb_t *pdb = data; |
| class_datum_t *class = (class_datum_t *)datum; |
| |
| if (class->s.value < 1 || class->s.value > pdb->p_classes.nprim) { |
| return -EINVAL; |
| } |
| pdb->p_class_val_to_name[class->s.value - 1] = (char *)key; |
| pdb->class_val_to_struct[class->s.value - 1] = class; |
| |
| return 0; |
| } |
| |
| static int __cil_role_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) |
| { |
| policydb_t *pdb = data; |
| role_datum_t *role = (role_datum_t *)datum; |
| |
| if (role->s.value < 1 || role->s.value > pdb->p_roles.nprim) { |
| return -EINVAL; |
| } |
| pdb->p_role_val_to_name[role->s.value - 1] = (char *)key; |
| pdb->role_val_to_struct[role->s.value - 1] = role; |
| |
| return 0; |
| } |
| |
| static int __cil_type_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) |
| { |
| policydb_t *pdb = data; |
| type_datum_t *type = (type_datum_t *)datum; |
| |
| if (type->s.value < 1 || type->s.value > pdb->p_types.nprim) { |
| return -EINVAL; |
| } |
| pdb->p_type_val_to_name[type->s.value - 1] = (char *)key; |
| pdb->type_val_to_struct[type->s.value - 1] = type; |
| |
| return 0; |
| } |
| |
| static int __cil_user_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) |
| { |
| policydb_t *pdb = data; |
| user_datum_t *user = (user_datum_t *)datum; |
| |
| if (user->s.value < 1 || user->s.value > pdb->p_users.nprim) { |
| return -EINVAL; |
| } |
| pdb->p_user_val_to_name[user->s.value - 1] = (char *)key; |
| pdb->user_val_to_struct[user->s.value - 1] = user; |
| |
| return 0; |
| } |
| |
| static int __cil_bool_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) |
| { |
| policydb_t *pdb = data; |
| cond_bool_datum_t *bool = (cond_bool_datum_t *)datum; |
| |
| if (bool->s.value < 1 || bool->s.value > pdb->p_bools.nprim) { |
| return -EINVAL; |
| } |
| pdb->p_bool_val_to_name[bool->s.value - 1] = (char *)key; |
| pdb->bool_val_to_struct[bool->s.value - 1] = bool; |
| |
| return 0; |
| } |
| |
| static int __cil_level_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) |
| { |
| policydb_t *pdb = data; |
| level_datum_t *level = (level_datum_t *)datum; |
| |
| if (level->level->sens < 1 || level->level->sens > pdb->p_levels.nprim) { |
| return -EINVAL; |
| } |
| pdb->p_sens_val_to_name[level->level->sens - 1] = (char *)key; |
| |
| return 0; |
| } |
| |
| static int __cil_cat_val_array_insert(hashtab_key_t key, hashtab_datum_t datum, void *data) |
| { |
| policydb_t *pdb = data; |
| cat_datum_t *cat = (cat_datum_t *)datum; |
| |
| if (cat->s.value < 1 || cat->s.value > pdb->p_cats.nprim) { |
| return -EINVAL; |
| } |
| pdb->p_cat_val_to_name[cat->s.value - 1] = (char *)key; |
| |
| return 0; |
| } |
| |
| static int __cil_policydb_val_arrays_create(policydb_t *policydb) |
| { |
| int rc = SEPOL_ERR; |
| |
| policydb->p_common_val_to_name = cil_malloc(sizeof(char *) * policydb->p_commons.nprim); |
| rc = hashtab_map(policydb->p_commons.table, &__cil_common_val_array_insert, policydb); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| policydb->p_class_val_to_name = cil_malloc(sizeof(char *) * policydb->p_classes.nprim); |
| policydb->class_val_to_struct = cil_malloc(sizeof(class_datum_t *) * policydb->p_classes.nprim); |
| rc = hashtab_map(policydb->p_classes.table, &__cil_class_val_array_insert, policydb); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| policydb->p_role_val_to_name = cil_malloc(sizeof(char *) * policydb->p_roles.nprim); |
| policydb->role_val_to_struct = cil_malloc(sizeof(role_datum_t *) * policydb->p_roles.nprim); |
| rc = hashtab_map(policydb->p_roles.table, &__cil_role_val_array_insert, policydb); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| policydb->p_type_val_to_name = cil_malloc(sizeof(char *) * policydb->p_types.nprim); |
| policydb->type_val_to_struct = cil_malloc(sizeof(type_datum_t *) * policydb->p_types.nprim); |
| rc = hashtab_map(policydb->p_types.table, &__cil_type_val_array_insert, policydb); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| policydb->p_user_val_to_name = cil_malloc(sizeof(char *) * policydb->p_users.nprim); |
| policydb->user_val_to_struct = cil_malloc(sizeof(user_datum_t *) * policydb->p_users.nprim); |
| rc = hashtab_map(policydb->p_users.table, &__cil_user_val_array_insert, policydb); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| policydb->p_bool_val_to_name = cil_malloc(sizeof(char *) * policydb->p_bools.nprim); |
| policydb->bool_val_to_struct = cil_malloc(sizeof(cond_bool_datum_t *) * policydb->p_bools.nprim); |
| rc = hashtab_map(policydb->p_bools.table, &__cil_bool_val_array_insert, policydb); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| policydb->p_sens_val_to_name = cil_malloc(sizeof(char *) * policydb->p_levels.nprim); |
| rc = hashtab_map(policydb->p_levels.table, &__cil_level_val_array_insert, policydb); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| policydb->p_cat_val_to_name = cil_malloc(sizeof(char *) * policydb->p_cats.nprim); |
| rc = hashtab_map(policydb->p_cats.table, &__cil_cat_val_array_insert, policydb); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| exit: |
| return rc; |
| } |
| |
| static void __cil_set_conditional_state_and_flags(policydb_t *pdb) |
| { |
| cond_node_t *cur; |
| |
| for (cur = pdb->cond_list; cur != NULL; cur = cur->next) { |
| int new_state; |
| cond_av_list_t *c; |
| |
| new_state = cond_evaluate_expr(pdb, cur->expr); |
| |
| cur->cur_state = new_state; |
| |
| if (new_state == -1) { |
| cil_log(CIL_WARN, "Expression result was undefined - disabling all rules\n"); |
| } |
| |
| for (c = cur->true_list; c != NULL; c = c->next) { |
| if (new_state <= 0) { |
| c->node->key.specified &= ~AVTAB_ENABLED; |
| } else { |
| c->node->key.specified |= AVTAB_ENABLED; |
| } |
| } |
| |
| for (c = cur->false_list; c != NULL; c = c->next) { |
| if (new_state) { /* -1 or 1 */ |
| c->node->key.specified &= ~AVTAB_ENABLED; |
| } else { |
| c->node->key.specified |= AVTAB_ENABLED; |
| } |
| } |
| } |
| } |
| |
| static int __cil_policydb_create(const struct cil_db *db, struct sepol_policydb **spdb) |
| { |
| int rc; |
| struct policydb *pdb = NULL; |
| |
| rc = sepol_policydb_create(spdb); |
| if (rc < 0) { |
| cil_log(CIL_ERR, "Failed to create policy db\n"); |
| // spdb could be a dangling pointer at this point, so reset it so |
| // callers of this function don't need to worry about freeing garbage |
| *spdb = NULL; |
| goto exit; |
| } |
| |
| pdb = &(*spdb)->p; |
| |
| pdb->policy_type = POLICY_KERN; |
| pdb->target_platform = db->target_platform; |
| pdb->policyvers = db->policy_version; |
| pdb->handle_unknown = db->handle_unknown; |
| pdb->mls = db->mls; |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| |
| static int __cil_policydb_init(policydb_t *pdb, const struct cil_db *db, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[]) |
| { |
| int rc = SEPOL_ERR; |
| |
| // these flags should get set in __cil_policydb_create. However, for |
| // backwards compatibility, it is possible that __cil_policydb_create is |
| // never called. So, they must also be set here. |
| pdb->handle_unknown = db->handle_unknown; |
| pdb->mls = db->mls; |
| |
| rc = cil_classorder_to_policydb(pdb, db, class_value_to_cil, perm_value_to_cil); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| if (pdb->mls == CIL_TRUE) { |
| rc = cil_catorder_to_policydb(pdb, db); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = cil_sensitivityorder_to_policydb(pdb, db); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| |
| rc = avtab_alloc(&pdb->te_avtab, MAX_AVTAB_SIZE); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = avtab_alloc(&pdb->te_cond_avtab, MAX_AVTAB_SIZE); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| |
| return rc; |
| } |
| |
| static unsigned int role_trans_hash(hashtab_t h, const_hashtab_key_t key) |
| { |
| const role_trans_t *k = (const role_trans_t *)key; |
| return ((k->role + (k->type << 2) + |
| (k->tclass << 5)) & (h->size - 1)); |
| } |
| |
| static int role_trans_compare(hashtab_t h |
| __attribute__ ((unused)), const_hashtab_key_t key1, |
| const_hashtab_key_t key2) |
| { |
| const role_trans_t *a = (const role_trans_t *)key1; |
| const role_trans_t *b = (const role_trans_t *)key2; |
| |
| return a->role != b->role || a->type != b->type || a->tclass != b->tclass; |
| } |
| |
| /* Based on MurmurHash3, written by Austin Appleby and placed in the |
| * public domain. |
| */ |
| static unsigned int avrulex_hash(__attribute__((unused)) hashtab_t h, const_hashtab_key_t key) |
| { |
| const avtab_key_t *k = (const avtab_key_t *)key; |
| |
| static const uint32_t c1 = 0xcc9e2d51; |
| static const uint32_t c2 = 0x1b873593; |
| static const uint32_t r1 = 15; |
| static const uint32_t r2 = 13; |
| static const uint32_t m = 5; |
| static const uint32_t n = 0xe6546b64; |
| |
| uint32_t hash = 0; |
| |
| #define mix(input) do { \ |
| uint32_t v = input; \ |
| v *= c1; \ |
| v = (v << r1) | (v >> (32 - r1)); \ |
| v *= c2; \ |
| hash ^= v; \ |
| hash = (hash << r2) | (hash >> (32 - r2)); \ |
| hash = hash * m + n; \ |
| } while (0) |
| |
| mix(k->target_class); |
| mix(k->target_type); |
| mix(k->source_type); |
| mix(k->specified); |
| |
| #undef mix |
| |
| hash ^= hash >> 16; |
| hash *= 0x85ebca6b; |
| hash ^= hash >> 13; |
| hash *= 0xc2b2ae35; |
| hash ^= hash >> 16; |
| |
| return hash & (AVRULEX_TABLE_SIZE - 1); |
| } |
| |
| static int avrulex_compare(hashtab_t h |
| __attribute__ ((unused)), const_hashtab_key_t key1, |
| const_hashtab_key_t key2) |
| { |
| const avtab_key_t *a = (const avtab_key_t *)key1; |
| const avtab_key_t *b = (const avtab_key_t *)key2; |
| |
| return a->source_type != b->source_type || a->target_type != b->target_type || a->target_class != b->target_class || a->specified != b->specified; |
| } |
| |
| int cil_binary_create(const struct cil_db *db, sepol_policydb_t **policydb) |
| { |
| int rc = SEPOL_ERR; |
| struct sepol_policydb *pdb = NULL; |
| |
| rc = __cil_policydb_create(db, &pdb); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = cil_binary_create_allocated_pdb(db, pdb); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| *policydb = pdb; |
| |
| return SEPOL_OK; |
| |
| exit: |
| sepol_policydb_free(pdb); |
| |
| return rc; |
| } |
| |
| static void __cil_destroy_sepol_class_perms(class_perm_node_t *curr) |
| { |
| class_perm_node_t *next; |
| |
| while (curr) { |
| next = curr->next; |
| free(curr); |
| curr = next; |
| } |
| } |
| |
| static int __cil_rule_to_sepol_class_perms(policydb_t *pdb, struct cil_list *classperms, class_perm_node_t **sepol_class_perms) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_list_item *i; |
| cil_list_for_each(i, classperms) { |
| if (i->flavor == CIL_CLASSPERMS) { |
| struct cil_classperms *cp = i->data; |
| if (FLAVOR(cp->class) == CIL_CLASS) { |
| class_perm_node_t *cpn = NULL; |
| class_datum_t *sepol_class = NULL; |
| uint32_t data = 0; |
| |
| rc = __cil_get_sepol_class_datum(pdb, DATUM(cp->class), &sepol_class); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = __cil_perms_to_datum(cp->perms, sepol_class, &data); |
| if (rc != SEPOL_OK) goto exit; |
| if (data != 0) { /* Only add if there are permissions */ |
| cpn = cil_malloc(sizeof(class_perm_node_t)); |
| cpn->tclass = sepol_class->s.value; |
| cpn->data = data; |
| cpn->next = *sepol_class_perms; |
| *sepol_class_perms = cpn; |
| } |
| } else { /* MAP */ |
| struct cil_list_item *j = NULL; |
| cil_list_for_each(j, cp->perms) { |
| struct cil_perm *cmp = j->data; |
| rc = __cil_rule_to_sepol_class_perms(pdb, cmp->classperms, sepol_class_perms); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| } |
| } else { /* SET */ |
| struct cil_classperms_set *cp_set = i->data; |
| struct cil_classpermission *cp = cp_set->set; |
| rc = __cil_rule_to_sepol_class_perms(pdb, cp->classperms, sepol_class_perms); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| } |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| static int __cil_permx_to_sepol_class_perms(policydb_t *pdb, struct cil_permissionx *permx, class_perm_node_t **sepol_class_perms) |
| { |
| int rc = SEPOL_OK; |
| struct cil_list *class_list = NULL; |
| struct cil_list_item *c; |
| class_datum_t *sepol_obj = NULL; |
| class_perm_node_t *cpn; |
| uint32_t data = 0; |
| char *perm_str = NULL; |
| |
| class_list = cil_expand_class(permx->obj); |
| |
| cil_list_for_each(c, class_list) { |
| rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| switch (permx->kind) { |
| case CIL_PERMX_KIND_IOCTL: |
| perm_str = CIL_KEY_IOCTL; |
| break; |
| default: |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| |
| rc = __perm_str_to_datum(perm_str, sepol_obj, &data); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| cpn = cil_malloc(sizeof(*cpn)); |
| cpn->tclass = sepol_obj->s.value; |
| cpn->data = data; |
| cpn->next = *sepol_class_perms; |
| *sepol_class_perms = cpn; |
| } |
| |
| exit: |
| cil_list_destroy(&class_list, CIL_FALSE); |
| |
| return rc; |
| } |
| |
| static void __cil_init_sepol_type_set(type_set_t *t) |
| { |
| ebitmap_init(&t->types); |
| ebitmap_init(&t->negset); |
| t->flags = 0; |
| } |
| |
| static int __cil_add_sepol_type(policydb_t *pdb, const struct cil_db *db, struct cil_symtab_datum *datum, ebitmap_t *map) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_tree_node *n = NODE(datum); |
| type_datum_t *sepol_datum = NULL; |
| |
| if (n->flavor == CIL_TYPEATTRIBUTE) { |
| ebitmap_node_t *tnode; |
| unsigned int i; |
| struct cil_typeattribute *attr = (struct cil_typeattribute *)datum; |
| ebitmap_for_each_positive_bit(attr->types, tnode, i) { |
| datum = DATUM(db->val_to_type[i]); |
| rc = __cil_get_sepol_type_datum(pdb, datum, &sepol_datum); |
| if (rc != SEPOL_OK) goto exit; |
| ebitmap_set_bit(map, sepol_datum->s.value - 1, 1); |
| } |
| } else { |
| rc = __cil_get_sepol_type_datum(pdb, datum, &sepol_datum); |
| if (rc != SEPOL_OK) goto exit; |
| ebitmap_set_bit(map, sepol_datum->s.value - 1, 1); |
| } |
| |
| return SEPOL_OK; |
| |
| exit: |
| return rc; |
| } |
| |
| static avrule_t *__cil_init_sepol_avrule(uint32_t kind, struct cil_tree_node *node) |
| { |
| avrule_t *avrule; |
| struct cil_tree_node *source_node; |
| char *source_path; |
| char *lm_kind; |
| uint32_t hll_line; |
| |
| avrule = cil_malloc(sizeof(avrule_t)); |
| avrule->specified = kind; |
| avrule->flags = 0; |
| __cil_init_sepol_type_set(&avrule->stypes); |
| __cil_init_sepol_type_set(&avrule->ttypes); |
| avrule->perms = NULL; |
| avrule->line = node->line; |
| |
| avrule->source_filename = NULL; |
| avrule->source_line = node->line; |
| source_node = cil_tree_get_next_path(node, &lm_kind, &hll_line, &source_path); |
| if (source_node) { |
| avrule->source_filename = source_path; |
| if (lm_kind != CIL_KEY_SRC_CIL) { |
| avrule->source_line = hll_line + node->hll_offset - source_node->hll_offset - 1; |
| } |
| } |
| |
| avrule->next = NULL; |
| return avrule; |
| } |
| |
| static void __cil_destroy_sepol_avrules(avrule_t *curr) |
| { |
| avrule_t *next; |
| |
| while (curr) { |
| next = curr->next; |
| ebitmap_destroy(&curr->stypes.types); |
| ebitmap_destroy(&curr->stypes.negset); |
| ebitmap_destroy(&curr->ttypes.types); |
| ebitmap_destroy(&curr->ttypes.negset); |
| __cil_destroy_sepol_class_perms(curr->perms); |
| free(curr); |
| curr = next; |
| } |
| } |
| |
| static void __cil_print_parents(const char *pad, struct cil_tree_node *n) |
| { |
| if (!n) return; |
| |
| __cil_print_parents(pad, n->parent); |
| |
| if (n->flavor != CIL_SRC_INFO) { |
| cil_tree_log(n, CIL_ERR,"%s%s", pad, cil_node_to_string(n)); |
| } |
| } |
| |
| static void __cil_print_classperm(struct cil_list *cp_list) |
| { |
| struct cil_list_item *i1, *i2; |
| |
| i1 = cp_list->head; |
| if (i1->flavor == CIL_CLASSPERMS) { |
| struct cil_classperms *cp = i1->data; |
| cil_log(CIL_ERR,"(%s (", DATUM(cp->class)->fqn); |
| cil_list_for_each(i2, cp->perms) { |
| cil_log(CIL_ERR,"%s",DATUM(i2->data)->fqn); |
| if (i2 != cp->perms->tail) { |
| cil_log(CIL_ERR," "); |
| } else { |
| cil_log(CIL_ERR,"))"); |
| } |
| } |
| } else { |
| struct cil_classperms_set *cp_set = i1->data; |
| cil_log(CIL_ERR,"%s", DATUM(cp_set->set)->fqn); |
| } |
| } |
| |
| static void __cil_print_permissionx(struct cil_permissionx *px) |
| { |
| const char *kind_str = ""; |
| char *expr_str; |
| |
| switch (px->kind) { |
| case CIL_PERMX_KIND_IOCTL: |
| kind_str = CIL_KEY_IOCTL; |
| break; |
| default: |
| kind_str = "unknown"; |
| break; |
| } |
| |
| __cil_expr_to_string(px->expr_str, CIL_PERMISSIONX, &expr_str); |
| |
| cil_log(CIL_ERR, "%s %s (%s)", kind_str, DATUM(px->obj)->fqn, expr_str); |
| |
| free(expr_str); |
| } |
| |
| static void __cil_print_rule(const char *pad, const char *kind, struct cil_avrule *avrule) |
| { |
| cil_log(CIL_ERR,"%s(%s ", pad, kind); |
| cil_log(CIL_ERR,"%s %s ", DATUM(avrule->src)->fqn, DATUM(avrule->tgt)->fqn); |
| |
| if (!avrule->is_extended) { |
| __cil_print_classperm(avrule->perms.classperms); |
| } else { |
| cil_log(CIL_ERR, "("); |
| __cil_print_permissionx(avrule->perms.x.permx); |
| cil_log(CIL_ERR, ")"); |
| } |
| |
| cil_log(CIL_ERR,")\n"); |
| } |
| |
| static int __cil_print_neverallow_failure(const struct cil_db *db, struct cil_tree_node *node) |
| { |
| int rc; |
| struct cil_list_item *i2; |
| struct cil_list *matching; |
| struct cil_avrule *cil_rule = node->data; |
| struct cil_avrule target; |
| struct cil_tree_node *n2; |
| struct cil_avrule *r2; |
| char *neverallow_str; |
| char *allow_str; |
| enum cil_flavor avrule_flavor; |
| int num_matching = 0; |
| int count_matching = 0; |
| enum cil_log_level log_level = cil_get_log_level(); |
| |
| target.rule_kind = CIL_AVRULE_ALLOWED; |
| target.is_extended = cil_rule->is_extended; |
| target.src = cil_rule->src; |
| target.tgt = cil_rule->tgt; |
| target.perms = cil_rule->perms; |
| |
| if (!cil_rule->is_extended) { |
| neverallow_str = CIL_KEY_NEVERALLOW; |
| allow_str = CIL_KEY_ALLOW; |
| avrule_flavor = CIL_AVRULE; |
| } else { |
| neverallow_str = CIL_KEY_NEVERALLOWX; |
| allow_str = CIL_KEY_ALLOWX; |
| avrule_flavor = CIL_AVRULEX; |
| } |
| cil_tree_log(node, CIL_ERR, "%s check failed", neverallow_str); |
| __cil_print_rule(" ", neverallow_str, cil_rule); |
| cil_list_init(&matching, CIL_NODE); |
| rc = cil_find_matching_avrule_in_ast(db->ast->root, avrule_flavor, &target, matching, CIL_FALSE); |
| if (rc) { |
| cil_log(CIL_ERR, "Error occurred while checking %s rules\n", neverallow_str); |
| cil_list_destroy(&matching, CIL_FALSE); |
| goto exit; |
| } |
| |
| cil_list_for_each(i2, matching) { |
| num_matching++; |
| } |
| cil_list_for_each(i2, matching) { |
| n2 = i2->data; |
| r2 = n2->data; |
| __cil_print_parents(" ", n2); |
| __cil_print_rule(" ", allow_str, r2); |
| count_matching++; |
| if (count_matching >= 4 && num_matching > 4 && log_level == CIL_ERR) { |
| cil_log(CIL_ERR, " Only first 4 of %d matching rules shown (use \"-v\" to show all)\n", num_matching); |
| break; |
| } |
| } |
| cil_log(CIL_ERR,"\n"); |
| cil_list_destroy(&matching, CIL_FALSE); |
| |
| exit: |
| return rc; |
| } |
| |
| static int cil_check_neverallow(const struct cil_db *db, policydb_t *pdb, struct cil_tree_node *node, int *violation) |
| { |
| int rc = SEPOL_OK; |
| struct cil_avrule *cil_rule = node->data; |
| struct cil_symtab_datum *tgt = cil_rule->tgt; |
| uint32_t kind; |
| avrule_t *rule; |
| struct cil_list *xperms = NULL; |
| struct cil_list_item *item; |
| |
| if (!cil_rule->is_extended) { |
| kind = AVRULE_NEVERALLOW; |
| } else { |
| kind = AVRULE_XPERMS_NEVERALLOW; |
| } |
| |
| rule = __cil_init_sepol_avrule(kind, node); |
| rule->next = NULL; |
| |
| rc = __cil_add_sepol_type(pdb, db, cil_rule->src, &rule->stypes.types); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| if (tgt->fqn == CIL_KEY_SELF) { |
| rule->flags = RULE_SELF; |
| } else { |
| rc = __cil_add_sepol_type(pdb, db, cil_rule->tgt, &rule->ttypes.types); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| |
| if (!cil_rule->is_extended) { |
| rc = __cil_rule_to_sepol_class_perms(pdb, cil_rule->perms.classperms, &rule->perms); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = check_assertion(pdb, rule); |
| if (rc == CIL_TRUE) { |
| *violation = CIL_TRUE; |
| rc = __cil_print_neverallow_failure(db, node); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| |
| } else { |
| rc = __cil_permx_to_sepol_class_perms(pdb, cil_rule->perms.x.permx, &rule->perms); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = __cil_permx_bitmap_to_sepol_xperms_list(cil_rule->perms.x.permx->perms, &xperms); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| cil_list_for_each(item, xperms) { |
| rule->xperms = item->data; |
| rc = check_assertion(pdb, rule); |
| if (rc == CIL_TRUE) { |
| *violation = CIL_TRUE; |
| rc = __cil_print_neverallow_failure(db, node); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| } |
| } |
| |
| exit: |
| if (xperms != NULL) { |
| cil_list_for_each(item, xperms) { |
| free(item->data); |
| item->data = NULL; |
| } |
| cil_list_destroy(&xperms, CIL_FALSE); |
| } |
| |
| rule->xperms = NULL; |
| __cil_destroy_sepol_avrules(rule); |
| |
| return rc; |
| } |
| |
| static int cil_check_neverallows(const struct cil_db *db, policydb_t *pdb, struct cil_list *neverallows, int *violation) |
| { |
| int rc = SEPOL_OK; |
| struct cil_list_item *item; |
| |
| cil_list_for_each(item, neverallows) { |
| rc = cil_check_neverallow(db, pdb, item->data, violation); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| } |
| |
| exit: |
| return rc; |
| } |
| |
| static struct cil_list *cil_classperms_from_sepol(policydb_t *pdb, uint16_t class, uint32_t data, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[]) |
| { |
| struct cil_classperms *cp; |
| struct cil_list *cp_list; |
| class_datum_t *sepol_class = pdb->class_val_to_struct[class - 1]; |
| unsigned i; |
| |
| cil_classperms_init(&cp); |
| |
| cp->class = class_value_to_cil[class]; |
| if (!cp->class) goto exit; |
| |
| cil_list_init(&cp->perms, CIL_PERM); |
| for (i = 0; i < sepol_class->permissions.nprim; i++) { |
| struct cil_perm *perm; |
| if ((data & (UINT32_C(1) << i)) == 0) continue; |
| perm = perm_value_to_cil[class][i+1]; |
| if (!perm) goto exit; |
| cil_list_append(cp->perms, CIL_PERM, perm); |
| } |
| |
| cil_list_init(&cp_list, CIL_CLASSPERMS); |
| cil_list_append(cp_list, CIL_CLASSPERMS, cp); |
| |
| return cp_list; |
| |
| exit: |
| cil_destroy_classperms(cp); |
| cil_log(CIL_ERR,"Failed to create CIL class-permissions from sepol values\n"); |
| return NULL; |
| } |
| |
| static int cil_avrule_from_sepol(policydb_t *pdb, avtab_ptr_t sepol_rule, struct cil_avrule *cil_rule, void *type_value_to_cil[], struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[]) |
| { |
| int rc = SEPOL_ERR; |
| avtab_key_t *k = &sepol_rule->key; |
| avtab_datum_t *d = &sepol_rule->datum; |
| cil_rule->src = type_value_to_cil[k->source_type]; |
| if (!cil_rule->src) goto exit; |
| |
| cil_rule->tgt = type_value_to_cil[k->target_type]; |
| if (!cil_rule->tgt) goto exit; |
| |
| cil_rule->perms.classperms = cil_classperms_from_sepol(pdb, k->target_class, d->data, class_value_to_cil, perm_value_to_cil); |
| if (!cil_rule->perms.classperms) goto exit; |
| |
| return SEPOL_OK; |
| |
| exit: |
| cil_log(CIL_ERR,"Failed to create CIL AV rule from sepol values\n"); |
| return rc; |
| } |
| |
| static int cil_check_type_bounds(const struct cil_db *db, policydb_t *pdb, void *type_value_to_cil, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[], int *violation) |
| { |
| int rc = SEPOL_OK; |
| int i; |
| |
| for (i = 0; i < db->num_types; i++) { |
| type_datum_t *child; |
| type_datum_t *parent; |
| avtab_ptr_t bad = NULL; |
| int numbad = 0; |
| struct cil_type *t = db->val_to_type[i]; |
| |
| if (!t->bounds) continue; |
| |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(t), &child); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = __cil_get_sepol_type_datum(pdb, DATUM(t->bounds), &parent); |
| if (rc != SEPOL_OK) goto exit; |
| |
| rc = bounds_check_type(NULL, pdb, child->s.value, parent->s.value, &bad, &numbad); |
| if (rc != SEPOL_OK) goto exit; |
| |
| if (bad) { |
| avtab_ptr_t cur; |
| struct cil_avrule target; |
| struct cil_tree_node *n1 = NULL; |
| int count_bad = 0; |
| enum cil_log_level log_level = cil_get_log_level(); |
| |
| *violation = CIL_TRUE; |
| |
| target.is_extended = 0; |
| target.rule_kind = CIL_AVRULE_ALLOWED; |
| target.src_str = NULL; |
| target.tgt_str = NULL; |
| |
| cil_log(CIL_ERR, "Child type %s exceeds bounds of parent %s\n", |
| t->datum.fqn, t->bounds->datum.fqn); |
| for (cur = bad; cur; cur = cur->next) { |
| struct cil_list_item *i2; |
| struct cil_list *matching; |
| int num_matching = 0; |
| int count_matching = 0; |
| |
| rc = cil_avrule_from_sepol(pdb, cur, &target, type_value_to_cil, class_value_to_cil, perm_value_to_cil); |
| if (rc != SEPOL_OK) { |
| cil_log(CIL_ERR, "Failed to convert sepol avrule to CIL\n"); |
| bounds_destroy_bad(bad); |
| goto exit; |
| } |
| __cil_print_rule(" ", "allow", &target); |
| cil_list_init(&matching, CIL_NODE); |
| rc = cil_find_matching_avrule_in_ast(db->ast->root, CIL_AVRULE, &target, matching, CIL_TRUE); |
| if (rc) { |
| cil_log(CIL_ERR, "Error occurred while checking type bounds\n"); |
| cil_list_destroy(&matching, CIL_FALSE); |
| cil_list_destroy(&target.perms.classperms, CIL_TRUE); |
| bounds_destroy_bad(bad); |
| goto exit; |
| } |
| cil_list_for_each(i2, matching) { |
| num_matching++; |
| } |
| cil_list_for_each(i2, matching) { |
| struct cil_tree_node *n2 = i2->data; |
| struct cil_avrule *r2 = n2->data; |
| if (n1 == n2) { |
| cil_log(CIL_ERR, " <See previous>\n"); |
| } else { |
| n1 = n2; |
| __cil_print_parents(" ", n2); |
| __cil_print_rule(" ", "allow", r2); |
| } |
| count_matching++; |
| if (count_matching >= 2 && num_matching > 2 && log_level == CIL_ERR) { |
| cil_log(CIL_ERR, " Only first 2 of %d matching rules shown (use \"-v\" to show all)\n", num_matching); |
| break; |
| } |
| } |
| cil_list_destroy(&matching, CIL_FALSE); |
| cil_list_destroy(&target.perms.classperms, CIL_TRUE); |
| count_bad++; |
| if (count_bad >= 4 && numbad > 4 && log_level == CIL_ERR) { |
| cil_log(CIL_ERR, " Only first 4 of %d bad rules shown (use \"-v\" to show all)\n", numbad); |
| break; |
| } |
| } |
| bounds_destroy_bad(bad); |
| } |
| } |
| |
| exit: |
| return rc; |
| } |
| |
| // assumes policydb is already allocated and initialized properly with things |
| // like policy type set to kernel and version set appropriately |
| int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *policydb) |
| { |
| int rc = SEPOL_ERR; |
| int i; |
| struct cil_args_binary extra_args; |
| policydb_t *pdb = &policydb->p; |
| struct cil_list *neverallows = NULL; |
| hashtab_t role_trans_table = NULL; |
| hashtab_t avrulex_ioctl_table = NULL; |
| void **type_value_to_cil = NULL; |
| struct cil_class **class_value_to_cil = NULL; |
| struct cil_perm ***perm_value_to_cil = NULL; |
| |
| if (db == NULL || policydb == NULL) { |
| if (db == NULL) { |
| cil_log(CIL_ERR,"db == NULL\n"); |
| } else if (policydb == NULL) { |
| cil_log(CIL_ERR,"policydb == NULL\n"); |
| } |
| return SEPOL_ERR; |
| } |
| |
| /* libsepol values start at 1. Just allocate extra memory rather than |
| * subtract 1 from the sepol value. |
| */ |
| type_value_to_cil = calloc(db->num_types_and_attrs+1, sizeof(*type_value_to_cil)); |
| if (!type_value_to_cil) goto exit; |
| |
| class_value_to_cil = calloc(db->num_classes+1, sizeof(*class_value_to_cil)); |
| if (!class_value_to_cil) goto exit; |
| |
| perm_value_to_cil = calloc(db->num_classes+1, sizeof(*perm_value_to_cil)); |
| if (!perm_value_to_cil) goto exit; |
| for (i=1; i < db->num_classes+1; i++) { |
| perm_value_to_cil[i] = calloc(PERMS_PER_CLASS+1, sizeof(*perm_value_to_cil[i])); |
| if (!perm_value_to_cil[i]) goto exit; |
| } |
| |
| rc = __cil_policydb_init(pdb, db, class_value_to_cil, perm_value_to_cil); |
| if (rc != SEPOL_OK) { |
| cil_log(CIL_ERR,"Problem in policydb_init\n"); |
| goto exit; |
| } |
| |
| role_trans_table = hashtab_create(role_trans_hash, role_trans_compare, ROLE_TRANS_TABLE_SIZE); |
| if (!role_trans_table) { |
| cil_log(CIL_INFO, "Failure to create hashtab for role_trans\n"); |
| goto exit; |
| } |
| |
| avrulex_ioctl_table = hashtab_create(avrulex_hash, avrulex_compare, AVRULEX_TABLE_SIZE); |
| if (!avrulex_ioctl_table) { |
| cil_log(CIL_INFO, "Failure to create hashtab for avrulex\n"); |
| goto exit; |
| } |
| |
| cil_list_init(&neverallows, CIL_LIST_ITEM); |
| |
| extra_args.db = db; |
| extra_args.pdb = pdb; |
| extra_args.neverallows = neverallows; |
| extra_args.role_trans_table = role_trans_table; |
| extra_args.avrulex_ioctl_table = avrulex_ioctl_table; |
| extra_args.type_value_to_cil = type_value_to_cil; |
| |
| for (i = 1; i <= 3; i++) { |
| extra_args.pass = i; |
| |
| rc = cil_tree_walk(db->ast->root, __cil_binary_create_helper, NULL, NULL, &extra_args); |
| if (rc != SEPOL_OK) { |
| cil_log(CIL_INFO, "Failure while walking cil database\n"); |
| goto exit; |
| } |
| |
| if (i == 1) { |
| rc = __cil_policydb_val_arrays_create(pdb); |
| if (rc != SEPOL_OK) { |
| cil_log(CIL_INFO, "Failure creating val_to_{struct,name} arrays\n"); |
| goto exit; |
| } |
| } |
| |
| if (i == 3) { |
| rc = hashtab_map(avrulex_ioctl_table, __cil_avrulex_ioctl_to_policydb, pdb); |
| if (rc != SEPOL_OK) { |
| cil_log(CIL_INFO, "Failure creating avrulex rules\n"); |
| goto exit; |
| } |
| } |
| } |
| |
| rc = cil_sidorder_to_policydb(pdb, db); |
| if (rc != SEPOL_OK) { |
| goto exit; |
| } |
| |
| rc = __cil_contexts_to_policydb(pdb, db); |
| if (rc != SEPOL_OK) { |
| cil_log(CIL_INFO, "Failure while inserting cil contexts into sepol policydb\n"); |
| goto exit; |
| } |
| |
| if (pdb->type_attr_map == NULL) { |
| rc = __cil_typeattr_bitmap_init(pdb); |
| if (rc != SEPOL_OK) { |
| cil_log(CIL_INFO, "Failure while initializing typeattribute bitmap\n"); |
| goto exit; |
| } |
| } |
| |
| cond_optimize_lists(pdb->cond_list); |
| __cil_set_conditional_state_and_flags(pdb); |
| |
| if (db->disable_neverallow != CIL_TRUE) { |
| int violation = CIL_FALSE; |
| cil_log(CIL_INFO, "Checking Neverallows\n"); |
| rc = cil_check_neverallows(db, pdb, neverallows, &violation); |
| if (rc != SEPOL_OK) goto exit; |
| |
| cil_log(CIL_INFO, "Checking User Bounds\n"); |
| rc = bounds_check_users(NULL, pdb); |
| if (rc) { |
| violation = CIL_TRUE; |
| } |
| |
| cil_log(CIL_INFO, "Checking Role Bounds\n"); |
| rc = bounds_check_roles(NULL, pdb); |
| if (rc) { |
| violation = CIL_TRUE; |
| } |
| |
| cil_log(CIL_INFO, "Checking Type Bounds\n"); |
| rc = cil_check_type_bounds(db, pdb, type_value_to_cil, class_value_to_cil, perm_value_to_cil, &violation); |
| if (rc != SEPOL_OK) goto exit; |
| |
| if (violation == CIL_TRUE) { |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| |
| } |
| |
| /* This pre-expands the roles and users for context validity checking */ |
| if (hashtab_map(pdb->p_roles.table, policydb_role_cache, pdb)) { |
| cil_log(CIL_INFO, "Failure creating roles cache"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| |
| if (hashtab_map(pdb->p_users.table, policydb_user_cache, pdb)) { |
| cil_log(CIL_INFO, "Failure creating users cache"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| |
| rc = SEPOL_OK; |
| |
| exit: |
| hashtab_destroy(role_trans_table); |
| hashtab_map(avrulex_ioctl_table, __cil_avrulex_ioctl_destroy, NULL); |
| hashtab_destroy(avrulex_ioctl_table); |
| free(type_value_to_cil); |
| free(class_value_to_cil); |
| if (perm_value_to_cil != NULL) { |
| /* Range is because libsepol values start at 1. */ |
| for (i=1; i < db->num_classes+1; i++) { |
| free(perm_value_to_cil[i]); |
| } |
| free(perm_value_to_cil); |
| } |
| cil_list_destroy(&neverallows, CIL_FALSE); |
| |
| return rc; |
| } |