/* * 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 #include #include #include #include "cil_internal.h" #include "cil_flavor.h" #include "cil_log.h" #include "cil_tree.h" #include "cil_list.h" #include "cil_parser.h" #include "cil_strpool.h" struct cil_tree_node *cil_tree_get_next_path(struct cil_tree_node *node, char **info_kind, uint32_t *hll_line, char **path) { int rc; if (!node) { goto exit; } node = node->parent; while (node) { if (node->flavor == CIL_NODE && node->data == NULL) { if (node->cl_head && node->cl_head->data == CIL_KEY_SRC_INFO) { if (!node->cl_head->next || !node->cl_head->next->next || !node->cl_head->next->next->next) { goto exit; } /* Parse Tree */ *info_kind = node->cl_head->next->data; rc = cil_string_to_uint32(node->cl_head->next->next->data, hll_line, 10); if (rc != SEPOL_OK) { goto exit; } *path = node->cl_head->next->next->next->data; return node; } node = node->parent; } else if (node->flavor == CIL_SRC_INFO) { /* AST */ struct cil_src_info *info = node->data; *info_kind = info->kind; *hll_line = info->hll_line; *path = info->path; return node; } else { if (node->flavor == CIL_CALL) { struct cil_call *call = node->data; node = NODE(call->macro); } else if (node->flavor == CIL_BLOCKINHERIT) { struct cil_blockinherit *inherit = node->data; node = NODE(inherit->block); } else { node = node->parent; } } } exit: *info_kind = NULL; *hll_line = 0; *path = NULL; return NULL; } char *cil_tree_get_cil_path(struct cil_tree_node *node) { char *info_kind; uint32_t hll_line; char *path; while (node) { node = cil_tree_get_next_path(node, &info_kind, &hll_line, &path); if (node && info_kind == CIL_KEY_SRC_CIL) { return path; } } return NULL; } __attribute__((format (printf, 3, 4))) void cil_tree_log(struct cil_tree_node *node, enum cil_log_level lvl, const char* msg, ...) { va_list ap; va_start(ap, msg); cil_vlog(lvl, msg, ap); va_end(ap); if (node) { char *path = NULL; uint32_t hll_offset = node->hll_offset; path = cil_tree_get_cil_path(node); if (path != NULL) { cil_log(lvl, " at %s:%u", path, node->line); } while (node) { do { char *info_kind; uint32_t hll_line; node = cil_tree_get_next_path(node, &info_kind, &hll_line, &path); if (!node || info_kind == CIL_KEY_SRC_CIL) { break; } if (info_kind == CIL_KEY_SRC_HLL_LMS) { hll_line += hll_offset - node->hll_offset - 1; } cil_log(lvl," from %s:%u", path, hll_line); } while (1); } } cil_log(lvl,"\n"); } int cil_tree_subtree_has_decl(struct cil_tree_node *node) { while (node) { if (node->flavor >= CIL_MIN_DECLARATIVE) { return CIL_TRUE; } if (node->cl_head != NULL) { if (cil_tree_subtree_has_decl(node->cl_head)) return CIL_TRUE; } node = node->next; } return CIL_FALSE; } int cil_tree_init(struct cil_tree **tree) { struct cil_tree *new_tree = cil_malloc(sizeof(*new_tree)); cil_tree_node_init(&new_tree->root); *tree = new_tree; return SEPOL_OK; } void cil_tree_destroy(struct cil_tree **tree) { if (tree == NULL || *tree == NULL) { return; } cil_tree_subtree_destroy((*tree)->root); free(*tree); *tree = NULL; } void cil_tree_subtree_destroy(struct cil_tree_node *node) { cil_tree_children_destroy(node); cil_tree_node_destroy(&node); } void cil_tree_children_destroy(struct cil_tree_node *node) { struct cil_tree_node *curr, *next; if (!node) { return; } curr = node->cl_head; while (curr) { next = curr->next; cil_tree_children_destroy(curr); cil_tree_node_destroy(&curr); curr = next; } node->cl_head = NULL; node->cl_tail = NULL; } void cil_tree_node_init(struct cil_tree_node **node) { struct cil_tree_node *new_node = cil_malloc(sizeof(*new_node)); new_node->cl_head = NULL; new_node->cl_tail = NULL; new_node->parent = NULL; new_node->data = NULL; new_node->next = NULL; new_node->flavor = CIL_ROOT; new_node->line = 0; new_node->hll_offset = 0; *node = new_node; } void cil_tree_node_destroy(struct cil_tree_node **node) { struct cil_symtab_datum *datum; if (node == NULL || *node == NULL) { return; } if ((*node)->flavor >= CIL_MIN_DECLARATIVE) { datum = (*node)->data; cil_symtab_datum_remove_node(datum, *node); if (datum->nodes == NULL) { cil_destroy_data(&(*node)->data, (*node)->flavor); } } else { cil_destroy_data(&(*node)->data, (*node)->flavor); } free(*node); *node = NULL; } /* Perform depth-first walk of the tree Parameters: start_node: root node to start walking from process_node: function to call when visiting a node Takes parameters: node: node being visited finished: boolean indicating to the tree walker that it should move on from this branch extra_args: additional data first_child: Function to call before entering list of children Takes parameters: node: node of first child extra args: additional data last_child: Function to call when finished with the last child of a node's children extra_args: any additional data to be passed to the helper functions */ static int cil_tree_walk_core(struct cil_tree_node *node, int (*process_node)(struct cil_tree_node *node, uint32_t *finished, void *extra_args), int (*first_child)(struct cil_tree_node *node, void *extra_args), int (*last_child)(struct cil_tree_node *node, void *extra_args), void *extra_args) { int rc = SEPOL_ERR; while (node) { uint32_t finished = CIL_TREE_SKIP_NOTHING; if (process_node != NULL) { rc = (*process_node)(node, &finished, extra_args); if (rc != SEPOL_OK) { cil_tree_log(node, CIL_INFO, "Problem"); return rc; } } if (finished & CIL_TREE_SKIP_NEXT) { return SEPOL_OK; } if (node->cl_head != NULL && !(finished & CIL_TREE_SKIP_HEAD)) { rc = cil_tree_walk(node, process_node, first_child, last_child, extra_args); if (rc != SEPOL_OK) { return rc; } } node = node->next; } return SEPOL_OK; } int cil_tree_walk(struct cil_tree_node *node, int (*process_node)(struct cil_tree_node *node, uint32_t *finished, void *extra_args), int (*first_child)(struct cil_tree_node *node, void *extra_args), int (*last_child)(struct cil_tree_node *node, void *extra_args), void *extra_args) { int rc = SEPOL_ERR; if (!node || !node->cl_head) { return SEPOL_OK; } if (first_child != NULL) { rc = (*first_child)(node->cl_head, extra_args); if (rc != SEPOL_OK) { cil_tree_log(node, CIL_INFO, "Problem"); return rc; } } rc = cil_tree_walk_core(node->cl_head, process_node, first_child, last_child, extra_args); if (rc != SEPOL_OK) { return rc; } if (last_child != NULL) { rc = (*last_child)(node->cl_tail, extra_args); if (rc != SEPOL_OK) { cil_tree_log(node, CIL_INFO, "Problem"); return rc; } } return SEPOL_OK; }