/* * 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 <string.h> #include <stdint.h> #include <unistd.h> #include <inttypes.h> #include <sepol/policydb/conditional.h> #include <sepol/errcodes.h> #include "cil_internal.h" #include "cil_flavor.h" #include "cil_log.h" #include "cil_mem.h" #include "cil_tree.h" #include "cil_list.h" #include "cil_policy.h" #include "cil_symtab.h" #include "cil_strpool.h" #define SEPOL_DONE 555 #define CLASS_DECL 0 #define ISIDS 1 #define COMMONS 2 #define CLASSES 3 #define INTERFACES 4 #define SENS 5 #define CATS 6 #define LEVELS 7 #define CONSTRAINS 8 #define TYPEATTRTYPES 9 #define ALIASES 10 #define ALLOWS 11 #define CONDS 12 #define USERROLES 13 #define SIDS 14 #define NETIFCONS 15 #define BUFFER 1024 #define NUM_POLICY_FILES 16 struct cil_args_genpolicy { struct cil_list *users; struct cil_list *sens; struct cil_list *cats; FILE **file_arr; }; struct cil_args_booleanif { FILE **file_arr; uint32_t *file_index; }; int cil_expr_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *expr); int cil_combine_policy(FILE **file_arr, FILE *policy_file) { char temp[BUFFER]; int i, rc, rc_read, rc_write; for(i=0; i<NUM_POLICY_FILES; i++) { fseek(file_arr[i], 0, SEEK_SET); while (!feof(file_arr[i])) { rc_read = fread(temp, 1, BUFFER, file_arr[i]); if (rc_read == 0 && ferror(file_arr[i])) { cil_log(CIL_ERR, "Error reading temp policy file\n"); return SEPOL_ERR; } rc_write = 0; while (rc_read > rc_write) { rc = fwrite(temp+rc_write, 1, rc_read-rc_write, policy_file); rc_write += rc; if (rc == 0 && ferror(file_arr[i])) { cil_log(CIL_ERR, "Error writing to policy.conf\n"); return SEPOL_ERR; } } } } return SEPOL_OK; } int cil_portcon_to_policy(FILE **file_arr, struct cil_sort *sort) { uint32_t i = 0; for (i=0; i<sort->count; i++) { struct cil_portcon *portcon = (struct cil_portcon*)sort->array[i]; fprintf(file_arr[NETIFCONS], "portcon "); if (portcon->proto == CIL_PROTOCOL_UDP) { fprintf(file_arr[NETIFCONS], "udp "); } else if (portcon->proto == CIL_PROTOCOL_TCP) { fprintf(file_arr[NETIFCONS], "tcp "); } fprintf(file_arr[NETIFCONS], "%d ", portcon->port_low); fprintf(file_arr[NETIFCONS], "%d ", portcon->port_high); cil_context_to_policy(file_arr, NETIFCONS, portcon->context); fprintf(file_arr[NETIFCONS], ";\n"); } return SEPOL_OK; } int cil_genfscon_to_policy(FILE **file_arr, struct cil_sort *sort) { uint32_t i = 0; for (i=0; i<sort->count; i++) { struct cil_genfscon *genfscon = (struct cil_genfscon*)sort->array[i]; fprintf(file_arr[NETIFCONS], "genfscon %s ", genfscon->fs_str); fprintf(file_arr[NETIFCONS], "%s ", genfscon->path_str); cil_context_to_policy(file_arr, NETIFCONS, genfscon->context); fprintf(file_arr[NETIFCONS], ";\n"); } return SEPOL_OK; } int cil_netifcon_to_policy(FILE **file_arr, struct cil_sort *sort) { uint32_t i = 0; for (i=0; i<sort->count; i++) { struct cil_netifcon *netifcon = (struct cil_netifcon*)sort->array[i]; fprintf(file_arr[NETIFCONS], "netifcon %s ", netifcon->interface_str); cil_context_to_policy(file_arr, NETIFCONS, netifcon->if_context); fprintf(file_arr[NETIFCONS], " "); cil_context_to_policy(file_arr, NETIFCONS, netifcon->packet_context); fprintf(file_arr[NETIFCONS], ";\n"); } return SEPOL_OK; } int cil_nodecon_to_policy(FILE **file_arr, struct cil_sort *sort) { uint32_t i = 0; int rc = SEPOL_ERR; for (i=0; i<sort->count; i++) { struct cil_nodecon *nodecon = (struct cil_nodecon*)sort->array[i]; char *buf = NULL; errno = 0; if (nodecon->addr->family == AF_INET) { buf = cil_malloc(INET_ADDRSTRLEN); inet_ntop(nodecon->addr->family, &nodecon->addr->ip.v4, buf, INET_ADDRSTRLEN); } else if (nodecon->addr->family == AF_INET6) { buf = cil_malloc(INET6_ADDRSTRLEN); inet_ntop(nodecon->addr->family, &nodecon->addr->ip.v6, buf, INET6_ADDRSTRLEN); } if (errno != 0) { cil_log(CIL_INFO, "Failed to convert ip address to string\n"); rc = SEPOL_ERR; goto exit; } fprintf(file_arr[NETIFCONS], "nodecon %s ", buf); free(buf); if (nodecon->mask->family == AF_INET) { buf = cil_malloc(INET_ADDRSTRLEN); inet_ntop(nodecon->mask->family, &nodecon->mask->ip.v4, buf, INET_ADDRSTRLEN); } else if (nodecon->mask->family == AF_INET6) { buf = cil_malloc(INET6_ADDRSTRLEN); inet_ntop(nodecon->mask->family, &nodecon->mask->ip.v6, buf, INET6_ADDRSTRLEN); } if (errno != 0) { cil_log(CIL_INFO, "Failed to convert mask to string\n"); rc = SEPOL_ERR; goto exit; } fprintf(file_arr[NETIFCONS], "%s ", buf); free(buf); cil_context_to_policy(file_arr, NETIFCONS, nodecon->context); fprintf(file_arr[NETIFCONS], ";\n"); } return SEPOL_OK; exit: return rc; } int cil_pirqcon_to_policy(FILE **file_arr, struct cil_sort *sort) { uint32_t i = 0; for (i = 0; i < sort->count; i++) { struct cil_pirqcon *pirqcon = (struct cil_pirqcon*)sort->array[i]; fprintf(file_arr[NETIFCONS], "pirqcon %d ", pirqcon->pirq); cil_context_to_policy(file_arr, NETIFCONS, pirqcon->context); fprintf(file_arr[NETIFCONS], ";\n"); } return SEPOL_OK; } int cil_iomemcon_to_policy(FILE **file_arr, struct cil_sort *sort) { uint32_t i = 0; for (i = 0; i < sort->count; i++) { struct cil_iomemcon *iomemcon = (struct cil_iomemcon*)sort->array[i]; fprintf(file_arr[NETIFCONS], "iomemcon %"PRId64"-%"PRId64" ", iomemcon->iomem_low, iomemcon->iomem_high); cil_context_to_policy(file_arr, NETIFCONS, iomemcon->context); fprintf(file_arr[NETIFCONS], ";\n"); } return SEPOL_OK; } int cil_ioportcon_to_policy(FILE **file_arr, struct cil_sort *sort) { uint32_t i = 0; for (i = 0; i < sort->count; i++) { struct cil_ioportcon *ioportcon = (struct cil_ioportcon*)sort->array[i]; fprintf(file_arr[NETIFCONS], "ioportcon %d-%d ", ioportcon->ioport_low, ioportcon->ioport_high); cil_context_to_policy(file_arr, NETIFCONS, ioportcon->context); fprintf(file_arr[NETIFCONS], ";\n"); } return SEPOL_OK; } int cil_pcidevicecon_to_policy(FILE **file_arr, struct cil_sort *sort) { uint32_t i = 0; for (i = 0; i < sort->count; i++) { struct cil_pcidevicecon *pcidevicecon = (struct cil_pcidevicecon*)sort->array[i]; fprintf(file_arr[NETIFCONS], "pcidevicecon %d ", pcidevicecon->dev); cil_context_to_policy(file_arr, NETIFCONS, pcidevicecon->context); fprintf(file_arr[NETIFCONS], ";\n"); } return SEPOL_OK; } int cil_fsuse_to_policy(FILE **file_arr, struct cil_sort *sort) { uint32_t i = 0; for (i=0; i<sort->count; i++) { struct cil_fsuse *fsuse = (struct cil_fsuse*)sort->array[i]; if (fsuse->type == CIL_FSUSE_XATTR) { fprintf(file_arr[NETIFCONS], "fs_use_xattr "); } else if (fsuse->type == CIL_FSUSE_TASK) { fprintf(file_arr[NETIFCONS], "fs_use_task "); } else if (fsuse->type == CIL_FSUSE_TRANS) { fprintf(file_arr[NETIFCONS], "fs_use_trans "); } else { return SEPOL_ERR; } fprintf(file_arr[NETIFCONS], "%s ", fsuse->fs_str); cil_context_to_policy(file_arr, NETIFCONS, fsuse->context); fprintf(file_arr[NETIFCONS], ";\n"); } return SEPOL_OK; } int cil_multimap_insert(struct cil_list *list, struct cil_symtab_datum *key, struct cil_symtab_datum *value, uint32_t key_flavor, uint32_t val_flavor) { struct cil_list_item *curr_key; struct cil_multimap_item *new_data; if (list == NULL || key == NULL) { return SEPOL_ERR; } cil_list_for_each(curr_key, list) { struct cil_multimap_item *curr_multimap_item = curr_key->data; if (curr_multimap_item != NULL) { if (curr_multimap_item->key != NULL && curr_multimap_item->key == key) { struct cil_list_item *curr_value; cil_list_for_each(curr_value, curr_multimap_item->values) { if (curr_value == (struct cil_list_item*)value) { return SEPOL_OK;; } } cil_list_append(curr_multimap_item->values, val_flavor, value); } } else { cil_log(CIL_INFO, "No data in list item\n"); return SEPOL_ERR; } } new_data = cil_malloc(sizeof(*new_data)); new_data->key = key; cil_list_init(&new_data->values, CIL_LIST_ITEM); if (value != NULL) { cil_list_append(new_data->values, val_flavor, value); } cil_list_append(list, key_flavor, new_data); return SEPOL_OK; } int cil_userrole_to_policy(FILE **file_arr, struct cil_list *userroles) { struct cil_list_item *current_user; if (userroles == NULL) { return SEPOL_OK; } cil_list_for_each(current_user, userroles) { struct cil_multimap_item *user_multimap_item = current_user->data; struct cil_list_item *current_role; if (user_multimap_item->values->head == NULL) { cil_log(CIL_INFO, "No roles associated with user %s\n", user_multimap_item->key->name); return SEPOL_ERR; } fprintf(file_arr[USERROLES], "user %s roles {", user_multimap_item->key->name); cil_list_for_each(current_role, user_multimap_item->values) { fprintf(file_arr[USERROLES], " %s", ((struct cil_role*)current_role->data)->datum.name); } fprintf(file_arr[USERROLES], " };\n"); } return SEPOL_OK; } int cil_cat_to_policy(FILE **file_arr, struct cil_list *cats) { struct cil_list_item *curr_cat; if (cats == NULL) { return SEPOL_OK; } cil_list_for_each(curr_cat, cats) { struct cil_multimap_item *cat_multimap_item = curr_cat->data; fprintf(file_arr[CATS], "category %s", cat_multimap_item->key->name); if (cat_multimap_item->values->head == NULL) { fprintf(file_arr[CATS], ";\n"); } else { struct cil_list_item *curr_catalias; fprintf(file_arr[CATS], " alias"); cil_list_for_each(curr_catalias, cat_multimap_item->values) { fprintf(file_arr[CATS], " %s", ((struct cil_cat*)curr_catalias->data)->datum.name); } fprintf(file_arr[CATS], ";\n"); } } return SEPOL_OK; } int cil_sens_to_policy(FILE **file_arr, struct cil_list *sens) { struct cil_list_item *curr_sens; if (sens == NULL) { return SEPOL_OK; } cil_list_for_each(curr_sens, sens) { struct cil_multimap_item *sens_multimap_item = curr_sens->data; fprintf(file_arr[SENS], "sensitivity %s", sens_multimap_item->key->name); if (sens_multimap_item->values->head == NULL) fprintf(file_arr[SENS], ";\n"); else { struct cil_list_item *curr_sensalias; fprintf(file_arr[SENS], " alias"); cil_list_for_each(curr_sensalias, sens_multimap_item->values) { fprintf(file_arr[SENS], " %s", ((struct cil_sens*)curr_sensalias->data)->datum.name); } fprintf(file_arr[SENS], ";\n"); } } return SEPOL_OK; } void cil_cats_to_policy(FILE **file_arr, uint32_t file_index, struct cil_cats *cats) { cil_expr_to_policy(file_arr, file_index, cats->datum_expr); } void cil_level_to_policy(FILE **file_arr, uint32_t file_index, struct cil_level *level) { char *sens_str = level->sens->datum.name; fprintf(file_arr[file_index], "%s", sens_str); if (level->cats != NULL) { fprintf(file_arr[file_index], ":"); cil_cats_to_policy(file_arr, file_index, level->cats); } } void cil_levelrange_to_policy(FILE **file_arr, uint32_t file_index, struct cil_levelrange *lvlrange) { struct cil_level *low = lvlrange->low; struct cil_level *high = lvlrange->high; cil_level_to_policy(file_arr, file_index, low); fprintf(file_arr[file_index], "-"); cil_level_to_policy(file_arr, file_index, high); } void cil_context_to_policy(FILE **file_arr, uint32_t file_index, struct cil_context *context) { char *user_str = ((struct cil_symtab_datum*)context->user)->name; char *role_str = ((struct cil_symtab_datum*)context->role)->name; char *type_str = ((struct cil_symtab_datum*)context->type)->name; struct cil_levelrange *lvlrange = context->range; fprintf(file_arr[file_index], "%s:%s:%s:", user_str, role_str, type_str); cil_levelrange_to_policy(file_arr, file_index, lvlrange); } void cil_perms_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *list) { struct cil_list_item *curr; fprintf(file_arr[file_index], " {"); cil_list_for_each(curr, list) { switch (curr->flavor) { case CIL_LIST: cil_perms_to_policy(file_arr, file_index, curr->data); break; case CIL_STRING: fprintf(file_arr[file_index], " %s", (char *)curr->data); break; case CIL_DATUM: fprintf(file_arr[file_index], " %s", ((struct cil_symtab_datum *)curr->data)->name); break; case CIL_OP: { enum cil_flavor op_flavor = *((enum cil_flavor *)curr->data); char *op_str = NULL; switch (op_flavor) { case CIL_AND: op_str = CIL_KEY_AND; break; case CIL_OR: op_str = CIL_KEY_OR; break; case CIL_NOT: op_str = CIL_KEY_NOT; break; case CIL_ALL: op_str = CIL_KEY_ALL; break; case CIL_XOR: op_str = CIL_KEY_XOR; break; default: cil_log(CIL_ERR, "Unknown operator in expression\n"); break; } fprintf(file_arr[file_index], " %s", op_str); break; } default: cil_log(CIL_ERR, "Unknown flavor in expression\n"); break; } } fprintf(file_arr[file_index], " }"); } void cil_constrain_to_policy_helper(FILE **file_arr, char *kind, struct cil_list *classperms, struct cil_list *expr) { 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) { fprintf(file_arr[CONSTRAINS], "%s %s", kind, cp->class->datum.name); cil_perms_to_policy(file_arr, CONSTRAINS, cp->perms); fprintf(file_arr[CONSTRAINS], "\n\t"); cil_expr_to_policy(file_arr, CONSTRAINS, expr); fprintf(file_arr[CONSTRAINS], ";\n"); } else { /* MAP */ struct cil_list_item *i = NULL; cil_list_for_each(i, cp->perms) { struct cil_perm *cmp = i->data; cil_constrain_to_policy_helper(file_arr, kind, cmp->classperms, expr); } } } else { /* SET */ struct cil_classperms_set *cp_set = curr->data; struct cil_classpermission *cp = cp_set->set; cil_constrain_to_policy_helper(file_arr, kind, cp->classperms, expr); } } } void cil_constrain_to_policy(FILE **file_arr, __attribute__((unused)) uint32_t file_index, struct cil_constrain *cons, enum cil_flavor flavor) { char *kind = NULL; if (flavor == CIL_CONSTRAIN) { kind = CIL_KEY_CONSTRAIN; } else if (flavor == CIL_MLSCONSTRAIN) { kind = CIL_KEY_MLSCONSTRAIN; } cil_constrain_to_policy_helper(file_arr, kind, cons->classperms, cons->datum_expr); } void cil_avrule_to_policy_helper(FILE **file_arr, uint32_t file_index, const char *kind, const char *src, const char *tgt, struct cil_list *classperms) { 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) { fprintf(file_arr[file_index], "%s %s %s: %s", kind, src, tgt, cp->class->datum.name); cil_perms_to_policy(file_arr, file_index, cp->perms); fprintf(file_arr[file_index], ";\n"); } else { /* MAP */ struct cil_list_item *j = NULL; cil_list_for_each(j, cp->perms) { struct cil_perm *cmp = j->data; cil_avrule_to_policy_helper(file_arr, file_index, kind, src, tgt, cmp->classperms); } } } else { /* SET */ struct cil_list_item *j; struct cil_classperms_set *cp_set = i->data; struct cil_classpermission *cp = cp_set->set; cil_list_for_each(j, cp->classperms) { cil_avrule_to_policy_helper(file_arr, file_index, kind, src, tgt, j->data); } } } } int cil_avrule_to_policy(FILE **file_arr, uint32_t file_index, struct cil_avrule *rule) { const char *kind_str = NULL; const char *src_str = DATUM(rule->src)->name; const char *tgt_str = DATUM(rule->tgt)->name; switch (rule->rule_kind) { case CIL_AVRULE_ALLOWED: kind_str = "allow"; break; case CIL_AVRULE_AUDITALLOW: kind_str = "auditallow"; break; case CIL_AVRULE_DONTAUDIT: kind_str = "dontaudit"; break; case CIL_AVRULE_NEVERALLOW: kind_str = "neverallow"; break; default : cil_log(CIL_INFO, "Unknown avrule with kind=%d src=%s tgt=%s\n", rule->rule_kind, src_str, tgt_str); return SEPOL_ERR; } cil_avrule_to_policy_helper(file_arr, file_index, kind_str, src_str, tgt_str, rule->classperms); return SEPOL_OK; } int cil_typerule_to_policy(FILE **file_arr, __attribute__((unused)) uint32_t file_index, struct cil_type_rule *rule) { char *src_str = ((struct cil_symtab_datum*)rule->src)->name; char *tgt_str = ((struct cil_symtab_datum*)rule->tgt)->name; char *obj_str = ((struct cil_symtab_datum*)rule->obj)->name; char *result_str = ((struct cil_symtab_datum*)rule->result)->name; switch (rule->rule_kind) { case CIL_TYPE_TRANSITION: fprintf(file_arr[ALLOWS], "type_transition %s %s : %s %s;\n", src_str, tgt_str, obj_str, result_str); break; case CIL_TYPE_CHANGE: fprintf(file_arr[ALLOWS], "type_change %s %s : %s %s\n;", src_str, tgt_str, obj_str, result_str); break; case CIL_TYPE_MEMBER: fprintf(file_arr[ALLOWS], "type_member %s %s : %s %s;\n", src_str, tgt_str, obj_str, result_str); break; default: cil_log(CIL_INFO, "Unknown type_rule\n"); return SEPOL_ERR; } return SEPOL_OK; } int cil_nametypetransition_to_policy(FILE **file_arr, uint32_t file_index, struct cil_nametypetransition *nametypetrans) { char *src_str = ((struct cil_symtab_datum*)nametypetrans->src)->name; char *tgt_str = ((struct cil_symtab_datum*)nametypetrans->tgt)->name; char *obj_str = ((struct cil_symtab_datum*)nametypetrans->obj)->name; char *result_str = ((struct cil_symtab_datum*)nametypetrans->result)->name; fprintf(file_arr[file_index], "type_transition %s %s : %s %s %s;\n", src_str, tgt_str, obj_str, result_str, nametypetrans->name_str); return SEPOL_OK; } static int cil_expr_to_string(struct cil_list *expr, char **out) { int rc = SEPOL_ERR; struct cil_list_item *curr; char *stack[COND_EXPR_MAXDEPTH] = {}; int pos = 0; int i; cil_list_for_each(curr, expr) { if (pos > COND_EXPR_MAXDEPTH) { rc = SEPOL_ERR; goto exit; } switch (curr->flavor) { case CIL_LIST: rc = cil_expr_to_string(curr->data, &stack[pos]); if (rc != SEPOL_OK) { goto exit; } pos++; break; case CIL_STRING: stack[pos] = curr->data; pos++; break; case CIL_DATUM: stack[pos] = ((struct cil_symtab_datum *)curr->data)->name; pos++; break; case CIL_OP: { int len; char *expr_str; enum cil_flavor op_flavor = *((enum cil_flavor *)curr->data); char *op_str = NULL; if (pos == 0) { rc = SEPOL_ERR; goto exit; } switch (op_flavor) { case CIL_AND: op_str = CIL_KEY_AND; break; case CIL_OR: op_str = CIL_KEY_OR; break; case CIL_NOT: op_str = CIL_KEY_NOT; break; case CIL_ALL: op_str = CIL_KEY_ALL; break; case CIL_EQ: op_str = CIL_KEY_EQ; break; case CIL_NEQ: op_str = CIL_KEY_NEQ; break; case CIL_XOR: op_str = CIL_KEY_XOR; break; case CIL_CONS_DOM: op_str = CIL_KEY_CONS_DOM; break; case CIL_CONS_DOMBY: op_str = CIL_KEY_CONS_DOMBY; break; case CIL_CONS_INCOMP: op_str = CIL_KEY_CONS_INCOMP; break; default: cil_log(CIL_ERR, "Unknown operator in expression\n"); goto exit; break; } if (op_flavor == CIL_NOT) { len = strlen(stack[pos-1]) + strlen(op_str) + 4; expr_str = cil_malloc(len); snprintf(expr_str, len, "(%s %s)", op_str, stack[pos-1]); free(stack[pos-1]); stack[pos-1] = NULL; pos--; } else { if (pos < 2) { rc = SEPOL_ERR; goto exit; } len = strlen(stack[pos-1]) + strlen(stack[pos-2]) + strlen(op_str) + 5; expr_str = cil_malloc(len); snprintf(expr_str, len, "(%s %s %s)", stack[pos-1], op_str, stack[pos-2]); free(stack[pos-2]); free(stack[pos-1]); stack[pos-2] = NULL; stack[pos-1] = NULL; pos -= 2; } stack[pos] = expr_str; pos++; break; } case CIL_CONS_OPERAND: { enum cil_flavor operand_flavor = *((enum cil_flavor *)curr->data); char *operand_str = NULL; switch (operand_flavor) { case CIL_CONS_U1: operand_str = CIL_KEY_CONS_U1; break; case CIL_CONS_U2: operand_str = CIL_KEY_CONS_U2; break; case CIL_CONS_U3: operand_str = CIL_KEY_CONS_U3; break; case CIL_CONS_T1: operand_str = CIL_KEY_CONS_T1; break; case CIL_CONS_T2: operand_str = CIL_KEY_CONS_T2; break; case CIL_CONS_T3: operand_str = CIL_KEY_CONS_T3; break; case CIL_CONS_R1: operand_str = CIL_KEY_CONS_R1; break; case CIL_CONS_R2: operand_str = CIL_KEY_CONS_R2; break; case CIL_CONS_R3: operand_str = CIL_KEY_CONS_R3; break; case CIL_CONS_L1: operand_str = CIL_KEY_CONS_L1; break; case CIL_CONS_L2: operand_str = CIL_KEY_CONS_L2; break; case CIL_CONS_H1: operand_str = CIL_KEY_CONS_H1; break; case CIL_CONS_H2: operand_str = CIL_KEY_CONS_H2; break; default: cil_log(CIL_ERR, "Unknown operand in expression\n"); goto exit; break; } stack[pos] = operand_str; pos++; break; } default: cil_log(CIL_ERR, "Unknown flavor in expression\n"); goto exit; break; } } *out = stack[0]; return SEPOL_OK; exit: for (i = 0; i < pos; i++) { free(stack[i]); } return rc; } int cil_expr_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *expr) { int rc = SEPOL_ERR; char *str_out; rc = cil_expr_to_string(expr, &str_out); if (rc != SEPOL_OK) { goto out; } fprintf(file_arr[file_index], "%s", str_out); free(str_out); return SEPOL_OK; out: return rc; } int __cil_booleanif_node_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args) { int rc = SEPOL_ERR; struct cil_args_booleanif *args; FILE **file_arr; uint32_t *file_index; args = extra_args; file_arr = args->file_arr; file_index = args->file_index; switch (node->flavor) { case CIL_AVRULE: rc = cil_avrule_to_policy(file_arr, *file_index, (struct cil_avrule*)node->data); if (rc != SEPOL_OK) { cil_log(CIL_INFO, "cil_avrule_to_policy failed, rc: %d\n", rc); return rc; } break; case CIL_TYPE_RULE: rc = cil_typerule_to_policy(file_arr, *file_index, (struct cil_type_rule*)node->data); if (rc != SEPOL_OK) { cil_log(CIL_INFO, "cil_typerule_to_policy failed, rc: %d\n", rc); return rc; } break; case CIL_FALSE: fprintf(file_arr[*file_index], "else {\n"); break; case CIL_TRUE: break; default: return SEPOL_ERR; } return SEPOL_OK; } int __cil_booleanif_last_child_helper(struct cil_tree_node *node, void *extra_args) { struct cil_args_booleanif *args; FILE **file_arr; uint32_t *file_index; args = extra_args; file_arr = args->file_arr; file_index = args->file_index; if (node->parent->flavor == CIL_FALSE) { fprintf(file_arr[*file_index], "}\n"); } return SEPOL_OK; } int cil_booleanif_to_policy(FILE **file_arr, uint32_t file_index, struct cil_tree_node *node) { int rc = SEPOL_ERR; struct cil_booleanif *bif = node->data; struct cil_list *expr = bif->datum_expr; struct cil_args_booleanif extra_args; struct cil_tree_node *true_node = NULL; struct cil_tree_node *false_node = NULL; struct cil_condblock *cb = NULL; extra_args.file_arr = file_arr; extra_args.file_index = &file_index;; fprintf(file_arr[file_index], "if "); rc = cil_expr_to_policy(file_arr, file_index, expr); if (rc != SEPOL_OK) { cil_log(CIL_ERR, "Failed to write expression\n"); return rc; } if (node->cl_head != NULL && node->cl_head->flavor == CIL_CONDBLOCK) { cb = node->cl_head->data; if (cb->flavor == CIL_CONDTRUE) { true_node = node->cl_head; } else if (cb->flavor == CIL_CONDFALSE) { false_node = node->cl_head; } } if (node->cl_head != NULL && node->cl_head->next != NULL && node->cl_head->next->flavor == CIL_CONDBLOCK) { cb = node->cl_head->next->data; if (cb->flavor == CIL_CONDTRUE) { true_node = node->cl_head->next; } else if (cb->flavor == CIL_CONDFALSE) { false_node = node->cl_head->next; } } fprintf(file_arr[file_index], "{\n"); if (true_node != NULL) { rc = cil_tree_walk(true_node, __cil_booleanif_node_helper, __cil_booleanif_last_child_helper, NULL, &extra_args); if (rc != SEPOL_OK) { cil_log(CIL_INFO, "Failed to write booleanif content to file, rc: %d\n", rc); return rc; } } fprintf(file_arr[file_index], "}\n"); if (false_node != NULL) { fprintf(file_arr[file_index], "else {\n"); rc = cil_tree_walk(false_node, __cil_booleanif_node_helper, __cil_booleanif_last_child_helper, NULL, &extra_args); if (rc != SEPOL_OK) { cil_log(CIL_INFO, "Failed to write booleanif false content to file, rc: %d\n", rc); return rc; } fprintf(file_arr[file_index], "}\n"); } return SEPOL_OK; } int cil_name_to_policy(FILE **file_arr, struct cil_tree_node *current) { uint32_t flavor = current->flavor; int rc = SEPOL_ERR; switch(flavor) { case CIL_TYPEATTRIBUTE: fprintf(file_arr[TYPEATTRTYPES], "attribute %s;\n", ((struct cil_symtab_datum*)current->data)->name); break; case CIL_TYPE: fprintf(file_arr[TYPEATTRTYPES], "type %s;\n", ((struct cil_symtab_datum*)current->data)->name); break; case CIL_TYPEALIAS: { struct cil_alias *alias = current->data; fprintf(file_arr[ALIASES], "typealias %s alias %s;\n", ((struct cil_symtab_datum*)alias->actual)->name, ((struct cil_symtab_datum*)current->data)->name); break; } case CIL_TYPEBOUNDS: { struct cil_bounds *bnds = current->data; fprintf(file_arr[ALLOWS], "typebounds %s %s;\n", bnds->parent_str, bnds->child_str); break; } case CIL_TYPEPERMISSIVE: { struct cil_typepermissive *typeperm = (struct cil_typepermissive*)current->data; fprintf(file_arr[TYPEATTRTYPES], "permissive %s;\n", ((struct cil_symtab_datum*)typeperm->type)->name); break; } case CIL_ROLE: fprintf(file_arr[TYPEATTRTYPES], "role %s;\n", ((struct cil_symtab_datum*)current->data)->name); break; case CIL_BOOL: { const char *boolean = ((struct cil_bool*)current->data)->value ? "true" : "false"; fprintf(file_arr[TYPEATTRTYPES], "bool %s %s;\n", ((struct cil_symtab_datum*)current->data)->name, boolean); break; } case CIL_COMMON: fprintf(file_arr[COMMONS], "common %s", ((struct cil_symtab_datum*)current->data)->name); if (current->cl_head != NULL) { current = current->cl_head; fprintf(file_arr[COMMONS], " {"); } else { cil_log(CIL_INFO, "No permissions given\n"); return SEPOL_ERR; } while (current != NULL) { if (current->flavor == CIL_PERM) { fprintf(file_arr[COMMONS], "%s ", ((struct cil_symtab_datum*)current->data)->name); } else { cil_log(CIL_INFO, "Improper data type found in common permissions: %d\n", current->flavor); return SEPOL_ERR; } current = current->next; } fprintf(file_arr[COMMONS], "}\n"); return SEPOL_DONE; case CIL_AVRULE: { struct cil_avrule *avrule = (struct cil_avrule*)current->data; rc = cil_avrule_to_policy(file_arr, ALLOWS, avrule); if (rc != SEPOL_OK) { cil_log(CIL_INFO, "Failed to write avrule to policy\n"); return rc; } break; } case CIL_TYPE_RULE: { struct cil_type_rule *rule = (struct cil_type_rule*)current->data; rc = cil_typerule_to_policy(file_arr, ALLOWS, rule); if (rc != SEPOL_OK) { cil_log(CIL_INFO, "Failed to write type rule to policy\n"); return rc; } break; } case CIL_NAMETYPETRANSITION: { struct cil_nametypetransition *nametypetrans = (struct cil_nametypetransition*)current->data; rc = cil_nametypetransition_to_policy(file_arr, ALLOWS, nametypetrans); if (rc != SEPOL_OK) { cil_log(CIL_INFO, "Failed to write nametypetransition to policy\n"); return rc; } } case CIL_ROLETRANSITION: { struct cil_roletransition *roletrans = (struct cil_roletransition*)current->data; char *src_str = ((struct cil_symtab_datum*)roletrans->src)->name; char *tgt_str = ((struct cil_symtab_datum*)roletrans->tgt)->name; char *obj_str = ((struct cil_symtab_datum*)roletrans->obj)->name; char *result_str = ((struct cil_symtab_datum*)roletrans->result)->name; fprintf(file_arr[ALLOWS], "role_transition %s %s:%s %s;\n", src_str, tgt_str, obj_str, result_str); break; } case CIL_ROLEALLOW: { struct cil_roleallow *roleallow = (struct cil_roleallow*)current->data; char *src_str = ((struct cil_symtab_datum*)roleallow->src)->name; char *tgt_str = ((struct cil_symtab_datum*)roleallow->tgt)->name; fprintf(file_arr[ALLOWS], "roleallow %s %s;\n", src_str, tgt_str); break; } case CIL_ROLETYPE: { struct cil_roletype *roletype = (struct cil_roletype*)current->data; char *role_str = ((struct cil_symtab_datum*)roletype->role)->name; char *type_str = ((struct cil_symtab_datum*)roletype->type)->name; fprintf(file_arr[ALIASES], "role %s types %s\n", role_str, type_str); break; } case CIL_LEVEL: fprintf(file_arr[LEVELS], "level "); cil_level_to_policy(file_arr, LEVELS, (struct cil_level*)current->data); fprintf(file_arr[LEVELS], ";\n"); break; case CIL_CONSTRAIN: cil_constrain_to_policy(file_arr, CONSTRAINS, (struct cil_constrain*)current->data, flavor); break; case CIL_MLSCONSTRAIN: cil_constrain_to_policy(file_arr, CONSTRAINS, (struct cil_constrain*)current->data, flavor); break; case CIL_VALIDATETRANS: { struct cil_validatetrans *vt = current->data; fprintf(file_arr[CONSTRAINS], "validatetrans"); fprintf(file_arr[CONSTRAINS], " %s ", ((struct cil_class*)vt->class)->datum.name); cil_expr_to_policy(file_arr, CONSTRAINS, vt->datum_expr); fprintf(file_arr[CONSTRAINS], ";\n"); break; } case CIL_MLSVALIDATETRANS: { struct cil_validatetrans *vt = current->data; fprintf(file_arr[CONSTRAINS], "mlsvalidatetrans"); fprintf(file_arr[CONSTRAINS], " %s " , ((struct cil_class*)vt->class)->datum.name); cil_expr_to_policy(file_arr, CONSTRAINS, vt->datum_expr); fprintf(file_arr[CONSTRAINS], ";\n"); break; } case CIL_SID: fprintf(file_arr[ISIDS], "sid %s\n", ((struct cil_symtab_datum*)current->data)->name); break; case CIL_SIDCONTEXT: { struct cil_sidcontext *sidcon = (struct cil_sidcontext*)current->data; fprintf(file_arr[SIDS], "sid %s ", sidcon->sid_str); cil_context_to_policy(file_arr, SIDS, sidcon->context); fprintf(file_arr[SIDS], "\n"); break; } case CIL_POLICYCAP: fprintf(file_arr[TYPEATTRTYPES], "policycap %s;\n", ((struct cil_symtab_datum*)current->data)->name); break; default: break; } return SEPOL_OK; } int __cil_gen_policy_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args) { int rc = SEPOL_ERR; struct cil_args_genpolicy *args = NULL; struct cil_list *users = NULL; struct cil_list *sens = NULL; struct cil_list *cats = NULL; FILE **file_arr = NULL; if (extra_args == NULL) { return SEPOL_ERR; } *finished = CIL_TREE_SKIP_NOTHING; args = extra_args; users = args->users; sens = args->sens; cats = args->cats; file_arr = args->file_arr; if (node->cl_head != NULL) { if (node->flavor == CIL_MACRO) { *finished = CIL_TREE_SKIP_HEAD; return SEPOL_OK; } if (node->flavor == CIL_BOOLEANIF) { rc = cil_booleanif_to_policy(file_arr, CONDS, node); if (rc != SEPOL_OK) { cil_log(CIL_INFO, "Failed to write booleanif contents to file\n"); return rc; } *finished = CIL_TREE_SKIP_HEAD; return SEPOL_OK; } if (node->flavor == CIL_BLOCK && ((struct cil_block*)node->data)->is_abstract == CIL_TRUE) { *finished = CIL_TREE_SKIP_HEAD; return SEPOL_OK; } if (node->flavor != CIL_ROOT) { rc = cil_name_to_policy(file_arr, node); if (rc != SEPOL_OK && rc != SEPOL_DONE) { cil_log(CIL_ERR, "Error converting node to policy %d\n", node->flavor); return SEPOL_ERR; } } } else { switch (node->flavor) { case CIL_USER: cil_multimap_insert(users, node->data, NULL, CIL_USERROLE, CIL_NONE); break; case CIL_USERROLE: { struct cil_userrole *userrole = node->data; cil_multimap_insert(users, &userrole->user->datum, (struct cil_symtab_datum *)userrole->role, CIL_USERROLE, CIL_ROLE); } break; case CIL_CATALIAS: { struct cil_alias *alias = node->data; struct cil_symtab_datum *datum = alias->actual; cil_multimap_insert(cats, datum, node->data, CIL_CAT, CIL_CATALIAS); } break; case CIL_SENSALIAS: { struct cil_alias *alias = node->data; struct cil_symtab_datum *datum = alias->actual; cil_multimap_insert(sens, datum, node->data, CIL_SENS, CIL_SENSALIAS); } break; default: rc = cil_name_to_policy(file_arr, node); if (rc != SEPOL_OK && rc != SEPOL_DONE) { cil_log(CIL_ERR, "Error converting node to policy %d\n", rc); return SEPOL_ERR; } break; } } return SEPOL_OK; } int cil_gen_policy(struct cil_db *db) { struct cil_tree_node *curr = db->ast->root; struct cil_list_item *item; int rc = SEPOL_ERR; FILE *policy_file; FILE **file_arr = cil_malloc(sizeof(FILE*) * NUM_POLICY_FILES); char *file_path_arr[NUM_POLICY_FILES]; char temp[32]; struct cil_list *users = NULL; struct cil_list *cats = NULL; struct cil_list *sens = NULL; struct cil_args_genpolicy extra_args; cil_list_init(&users, CIL_LIST_ITEM); cil_list_init(&cats, CIL_LIST_ITEM); cil_list_init(&sens, CIL_LIST_ITEM); strcpy(temp, "/tmp/cil_classdecl-XXXXXX"); file_arr[CLASS_DECL] = fdopen(mkstemp(temp), "w+"); file_path_arr[CLASS_DECL] = cil_strpool_add(temp); strcpy(temp, "/tmp/cil_isids-XXXXXX"); file_arr[ISIDS] = fdopen(mkstemp(temp), "w+"); file_path_arr[ISIDS] = cil_strpool_add(temp); strcpy(temp,"/tmp/cil_common-XXXXXX"); file_arr[COMMONS] = fdopen(mkstemp(temp), "w+"); file_path_arr[COMMONS] = cil_strpool_add(temp); strcpy(temp, "/tmp/cil_class-XXXXXX"); file_arr[CLASSES] = fdopen(mkstemp(temp), "w+"); file_path_arr[CLASSES] = cil_strpool_add(temp); strcpy(temp, "/tmp/cil_interf-XXXXXX"); file_arr[INTERFACES] = fdopen(mkstemp(temp), "w+"); file_path_arr[INTERFACES] = cil_strpool_add(temp); strcpy(temp, "/tmp/cil_sens-XXXXXX"); file_arr[SENS] = fdopen(mkstemp(temp), "w+"); file_path_arr[SENS] = cil_strpool_add(temp); strcpy(temp, "/tmp/cil_cats-XXXXXX"); file_arr[CATS] = fdopen(mkstemp(temp), "w+"); file_path_arr[CATS] = cil_strpool_add(temp); strcpy(temp, "/tmp/cil_levels-XXXXXX"); file_arr[LEVELS] = fdopen(mkstemp(temp), "w+"); file_path_arr[LEVELS] = cil_strpool_add(temp); strcpy(temp, "/tmp/cil_mlscon-XXXXXX"); file_arr[CONSTRAINS] = fdopen(mkstemp(temp), "w+"); file_path_arr[CONSTRAINS] = cil_strpool_add(temp); strcpy(temp, "/tmp/cil_attrtypes-XXXXXX"); file_arr[TYPEATTRTYPES] = fdopen(mkstemp(temp), "w+"); file_path_arr[TYPEATTRTYPES] = cil_strpool_add(temp); strcpy(temp, "/tmp/cil_aliases-XXXXXX"); file_arr[ALIASES] = fdopen(mkstemp(temp), "w+"); file_path_arr[ALIASES] = cil_strpool_add(temp); strcpy(temp, "/tmp/cil_allows-XXXXXX"); file_arr[ALLOWS] = fdopen(mkstemp(temp), "w+"); file_path_arr[ALLOWS] = cil_strpool_add(temp); strcpy(temp, "/tmp/cil_conds-XXXXXX"); file_arr[CONDS] = fdopen(mkstemp(temp), "w+"); file_path_arr[CONDS] = cil_strpool_add(temp); strcpy(temp, "/tmp/cil_userroles-XXXXXX"); file_arr[USERROLES] = fdopen(mkstemp(temp), "w+"); file_path_arr[USERROLES] = cil_strpool_add(temp); strcpy(temp, "/tmp/cil_sids-XXXXXX"); file_arr[SIDS] = fdopen(mkstemp(temp), "w+"); file_path_arr[SIDS] = cil_strpool_add(temp); strcpy(temp, "/tmp/cil_netifcons-XXXXXX"); file_arr[NETIFCONS] = fdopen(mkstemp(temp), "w+"); file_path_arr[NETIFCONS] = cil_strpool_add(temp); policy_file = fopen("policy.conf", "w+"); cil_list_for_each(item, db->sidorder) { fprintf(file_arr[ISIDS], "sid %s ", ((struct cil_sid*)item->data)->datum.name); } cil_list_for_each(item, db->classorder) { struct cil_class *class = item->data; struct cil_tree_node *node = class->datum.nodes->head->data; fprintf(file_arr[CLASS_DECL], "class %s\n", class->datum.name); fprintf(file_arr[CLASSES], "class %s ", class->datum.name); if (class->common != NULL) { fprintf(file_arr[CLASSES], "inherits %s ", class->common->datum.name); } if (node->cl_head != NULL) { struct cil_tree_node *curr_perm = node->cl_head; fprintf(file_arr[CLASSES], "{ "); while (curr_perm != NULL) { fprintf(file_arr[CLASSES], "%s ", ((struct cil_symtab_datum*)curr_perm->data)->name); curr_perm = curr_perm->next; } fprintf(file_arr[CLASSES], "}"); } fprintf(file_arr[CLASSES], "\n"); } if (db->catorder->head != NULL) { cil_list_for_each(item, db->catorder) { cil_multimap_insert(cats, item->data, NULL, CIL_CAT, 0); } } if (db->sensitivityorder->head != NULL) { fprintf(file_arr[SENS], "sensitivityorder { "); cil_list_for_each(item, db->sensitivityorder) { fprintf(file_arr[SENS], "%s ", ((struct cil_sens*)item->data)->datum.name); } fprintf(file_arr[SENS], "};\n"); } extra_args.users = users; extra_args.sens = sens; extra_args.cats = cats; extra_args.file_arr= file_arr; rc = cil_tree_walk(curr, __cil_gen_policy_node_helper, NULL, NULL, &extra_args); if (rc != SEPOL_OK) { cil_log(CIL_ERR, "Error walking tree\n"); return rc; } rc = cil_netifcon_to_policy(file_arr, db->netifcon); if (rc != SEPOL_OK) { cil_log(CIL_ERR, "Error creating policy.conf\n"); return rc; } rc = cil_genfscon_to_policy(file_arr, db->genfscon); if (rc != SEPOL_OK) { cil_log(CIL_ERR, "Error creating policy.conf\n"); return rc; } rc = cil_portcon_to_policy(file_arr, db->portcon); if (rc != SEPOL_OK) { cil_log(CIL_ERR, "Error creating policy.conf\n"); return rc; } rc = cil_nodecon_to_policy(file_arr, db->nodecon); if (rc != SEPOL_OK) { cil_log(CIL_ERR, "Error creating policy.conf\n"); return rc; } rc = cil_fsuse_to_policy(file_arr, db->fsuse); if (rc != SEPOL_OK) { cil_log(CIL_ERR, "Error creating policy.conf\n"); return rc; } rc = cil_pirqcon_to_policy(file_arr, db->pirqcon); if (rc != SEPOL_OK) { cil_log(CIL_ERR, "Error creating policy.conf\n"); return rc; } rc = cil_iomemcon_to_policy(file_arr, db->iomemcon); if (rc != SEPOL_OK) { cil_log(CIL_ERR, "Error creating policy.conf\n"); return rc; } rc = cil_ioportcon_to_policy(file_arr, db->ioportcon); if (rc != SEPOL_OK) { cil_log(CIL_ERR, "Error creating policy.conf\n"); return rc; } rc = cil_pcidevicecon_to_policy(file_arr, db->pcidevicecon); if (rc != SEPOL_OK) { cil_log(CIL_ERR, "Error creating policy.conf\n"); return rc; } rc = cil_userrole_to_policy(file_arr, users); if (rc != SEPOL_OK) { cil_log(CIL_ERR, "Error creating policy.conf\n"); return SEPOL_ERR; } rc = cil_sens_to_policy(file_arr, sens); if (rc != SEPOL_OK) { cil_log(CIL_ERR, "Error creating policy.conf\n"); return SEPOL_ERR; } rc = cil_cat_to_policy(file_arr, cats); if (rc != SEPOL_OK) { cil_log(CIL_ERR, "Error creating policy.conf\n"); return SEPOL_ERR; } rc = cil_combine_policy(file_arr, policy_file); if (rc != SEPOL_OK) { cil_log(CIL_ERR, "Error creating policy.conf\n"); return SEPOL_ERR; } // Remove temp files int i; for (i=0; i<NUM_POLICY_FILES; i++) { rc = fclose(file_arr[i]); if (rc != 0) { cil_log(CIL_ERR, "Error closing temporary file\n"); return SEPOL_ERR; } rc = unlink(file_path_arr[i]); if (rc != 0) { cil_log(CIL_ERR, "Error unlinking temporary files\n"); return SEPOL_ERR; } } rc = fclose(policy_file); if (rc != 0) { cil_log(CIL_ERR, "Error closing policy.conf\n"); return SEPOL_ERR; } free(file_arr); cil_list_destroy(&users, CIL_FALSE); cil_list_destroy(&cats, CIL_FALSE); cil_list_destroy(&sens, CIL_FALSE); return SEPOL_OK; }