16cd6a6acSopenharmony_ci/* 26cd6a6acSopenharmony_ci * Copyright 2011 Tresys Technology, LLC. All rights reserved. 36cd6a6acSopenharmony_ci * 46cd6a6acSopenharmony_ci * Redistribution and use in source and binary forms, with or without 56cd6a6acSopenharmony_ci * modification, are permitted provided that the following conditions are met: 66cd6a6acSopenharmony_ci * 76cd6a6acSopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, 86cd6a6acSopenharmony_ci * this list of conditions and the following disclaimer. 96cd6a6acSopenharmony_ci * 106cd6a6acSopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, 116cd6a6acSopenharmony_ci * this list of conditions and the following disclaimer in the documentation 126cd6a6acSopenharmony_ci * and/or other materials provided with the distribution. 136cd6a6acSopenharmony_ci * 146cd6a6acSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS 156cd6a6acSopenharmony_ci * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 166cd6a6acSopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 176cd6a6acSopenharmony_ci * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 186cd6a6acSopenharmony_ci * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 196cd6a6acSopenharmony_ci * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 206cd6a6acSopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 216cd6a6acSopenharmony_ci * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 226cd6a6acSopenharmony_ci * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 236cd6a6acSopenharmony_ci * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 246cd6a6acSopenharmony_ci * 256cd6a6acSopenharmony_ci * The views and conclusions contained in the software and documentation are those 266cd6a6acSopenharmony_ci * of the authors and should not be interpreted as representing official policies, 276cd6a6acSopenharmony_ci * either expressed or implied, of Tresys Technology, LLC. 286cd6a6acSopenharmony_ci */ 296cd6a6acSopenharmony_ci 306cd6a6acSopenharmony_ci#include <stdlib.h> 316cd6a6acSopenharmony_ci#include <stdio.h> 326cd6a6acSopenharmony_ci#include <string.h> 336cd6a6acSopenharmony_ci#include <stdint.h> 346cd6a6acSopenharmony_ci#include <sepol/errcodes.h> 356cd6a6acSopenharmony_ci 366cd6a6acSopenharmony_ci#include "cil_internal.h" 376cd6a6acSopenharmony_ci#include "cil_log.h" 386cd6a6acSopenharmony_ci#include "cil_mem.h" 396cd6a6acSopenharmony_ci#include "cil_tree.h" 406cd6a6acSopenharmony_ci#include "cil_lexer.h" 416cd6a6acSopenharmony_ci#include "cil_parser.h" 426cd6a6acSopenharmony_ci#include "cil_strpool.h" 436cd6a6acSopenharmony_ci#include "cil_stack.h" 446cd6a6acSopenharmony_ci 456cd6a6acSopenharmony_ci#define CIL_PARSER_MAX_EXPR_DEPTH (0x1 << 12) 466cd6a6acSopenharmony_ci 476cd6a6acSopenharmony_cistruct hll_info { 486cd6a6acSopenharmony_ci uint32_t hll_offset; 496cd6a6acSopenharmony_ci uint32_t hll_expand; 506cd6a6acSopenharmony_ci}; 516cd6a6acSopenharmony_ci 526cd6a6acSopenharmony_cistatic void push_hll_info(struct cil_stack *stack, uint32_t hll_offset, uint32_t hll_expand) 536cd6a6acSopenharmony_ci{ 546cd6a6acSopenharmony_ci struct hll_info *new = cil_malloc(sizeof(*new)); 556cd6a6acSopenharmony_ci 566cd6a6acSopenharmony_ci new->hll_offset = hll_offset; 576cd6a6acSopenharmony_ci new->hll_expand = hll_expand; 586cd6a6acSopenharmony_ci 596cd6a6acSopenharmony_ci cil_stack_push(stack, CIL_NONE, new); 606cd6a6acSopenharmony_ci} 616cd6a6acSopenharmony_ci 626cd6a6acSopenharmony_cistatic void pop_hll_info(struct cil_stack *stack, uint32_t *hll_offset, uint32_t *hll_expand) 636cd6a6acSopenharmony_ci{ 646cd6a6acSopenharmony_ci struct cil_stack_item *curr = cil_stack_pop(stack); 656cd6a6acSopenharmony_ci struct hll_info *info; 666cd6a6acSopenharmony_ci 676cd6a6acSopenharmony_ci if (!curr) { 686cd6a6acSopenharmony_ci return; 696cd6a6acSopenharmony_ci } 706cd6a6acSopenharmony_ci info = curr->data; 716cd6a6acSopenharmony_ci *hll_expand = info->hll_expand; 726cd6a6acSopenharmony_ci *hll_offset = info->hll_offset; 736cd6a6acSopenharmony_ci free(curr->data); 746cd6a6acSopenharmony_ci} 756cd6a6acSopenharmony_ci 766cd6a6acSopenharmony_cistatic void create_node(struct cil_tree_node **node, struct cil_tree_node *current, uint32_t line, uint32_t hll_offset, void *value) 776cd6a6acSopenharmony_ci{ 786cd6a6acSopenharmony_ci cil_tree_node_init(node); 796cd6a6acSopenharmony_ci (*node)->parent = current; 806cd6a6acSopenharmony_ci (*node)->flavor = CIL_NODE; 816cd6a6acSopenharmony_ci (*node)->line = line; 826cd6a6acSopenharmony_ci (*node)->hll_offset = hll_offset; 836cd6a6acSopenharmony_ci (*node)->data = value; 846cd6a6acSopenharmony_ci} 856cd6a6acSopenharmony_ci 866cd6a6acSopenharmony_cistatic void insert_node(struct cil_tree_node *node, struct cil_tree_node *current) 876cd6a6acSopenharmony_ci{ 886cd6a6acSopenharmony_ci if (current->cl_head == NULL) { 896cd6a6acSopenharmony_ci current->cl_head = node; 906cd6a6acSopenharmony_ci } else { 916cd6a6acSopenharmony_ci current->cl_tail->next = node; 926cd6a6acSopenharmony_ci } 936cd6a6acSopenharmony_ci current->cl_tail = node; 946cd6a6acSopenharmony_ci} 956cd6a6acSopenharmony_ci 966cd6a6acSopenharmony_cistatic int add_hll_linemark(struct cil_tree_node **current, uint32_t *hll_offset, uint32_t *hll_expand, struct cil_stack *stack, char *path) 976cd6a6acSopenharmony_ci{ 986cd6a6acSopenharmony_ci char *hll_type; 996cd6a6acSopenharmony_ci struct cil_tree_node *node; 1006cd6a6acSopenharmony_ci struct token tok; 1016cd6a6acSopenharmony_ci uint32_t prev_hll_expand, prev_hll_offset; 1026cd6a6acSopenharmony_ci 1036cd6a6acSopenharmony_ci cil_lexer_next(&tok); 1046cd6a6acSopenharmony_ci if (tok.type != SYMBOL) { 1056cd6a6acSopenharmony_ci cil_log(CIL_ERR, "Invalid line mark syntax\n"); 1066cd6a6acSopenharmony_ci goto exit; 1076cd6a6acSopenharmony_ci } 1086cd6a6acSopenharmony_ci hll_type = cil_strpool_add(tok.value); 1096cd6a6acSopenharmony_ci if (hll_type != CIL_KEY_SRC_HLL_LME && hll_type != CIL_KEY_SRC_HLL_LMS && hll_type != CIL_KEY_SRC_HLL_LMX) { 1106cd6a6acSopenharmony_ci cil_log(CIL_ERR, "Invalid line mark syntax\n"); 1116cd6a6acSopenharmony_ci goto exit; 1126cd6a6acSopenharmony_ci } 1136cd6a6acSopenharmony_ci if (hll_type == CIL_KEY_SRC_HLL_LME) { 1146cd6a6acSopenharmony_ci if (cil_stack_is_empty(stack)) { 1156cd6a6acSopenharmony_ci cil_log(CIL_ERR, "Line mark end without start\n"); 1166cd6a6acSopenharmony_ci goto exit; 1176cd6a6acSopenharmony_ci } 1186cd6a6acSopenharmony_ci prev_hll_expand = *hll_expand; 1196cd6a6acSopenharmony_ci prev_hll_offset = *hll_offset; 1206cd6a6acSopenharmony_ci pop_hll_info(stack, hll_offset, hll_expand); 1216cd6a6acSopenharmony_ci if (!*hll_expand) { 1226cd6a6acSopenharmony_ci /* This is needed if not going back to an lmx section. */ 1236cd6a6acSopenharmony_ci *hll_offset = prev_hll_offset; 1246cd6a6acSopenharmony_ci } 1256cd6a6acSopenharmony_ci if (prev_hll_expand && !*hll_expand) { 1266cd6a6acSopenharmony_ci /* This is needed to count the lme at the end of an lmx section 1276cd6a6acSopenharmony_ci * within an lms section (or within no hll section). 1286cd6a6acSopenharmony_ci */ 1296cd6a6acSopenharmony_ci (*hll_offset)++; 1306cd6a6acSopenharmony_ci } 1316cd6a6acSopenharmony_ci *current = (*current)->parent; 1326cd6a6acSopenharmony_ci } else { 1336cd6a6acSopenharmony_ci push_hll_info(stack, *hll_offset, *hll_expand); 1346cd6a6acSopenharmony_ci if (cil_stack_number_of_items(stack) > CIL_PARSER_MAX_EXPR_DEPTH) { 1356cd6a6acSopenharmony_ci cil_log(CIL_ERR, "Number of active line marks exceeds limit of %d\n", CIL_PARSER_MAX_EXPR_DEPTH); 1366cd6a6acSopenharmony_ci goto exit; 1376cd6a6acSopenharmony_ci } 1386cd6a6acSopenharmony_ci 1396cd6a6acSopenharmony_ci create_node(&node, *current, tok.line, *hll_offset, NULL); 1406cd6a6acSopenharmony_ci insert_node(node, *current); 1416cd6a6acSopenharmony_ci *current = node; 1426cd6a6acSopenharmony_ci 1436cd6a6acSopenharmony_ci create_node(&node, *current, tok.line, *hll_offset, CIL_KEY_SRC_INFO); 1446cd6a6acSopenharmony_ci insert_node(node, *current); 1456cd6a6acSopenharmony_ci 1466cd6a6acSopenharmony_ci create_node(&node, *current, tok.line, *hll_offset, hll_type); 1476cd6a6acSopenharmony_ci insert_node(node, *current); 1486cd6a6acSopenharmony_ci 1496cd6a6acSopenharmony_ci cil_lexer_next(&tok); 1506cd6a6acSopenharmony_ci if (tok.type != SYMBOL) { 1516cd6a6acSopenharmony_ci cil_log(CIL_ERR, "Invalid line mark syntax\n"); 1526cd6a6acSopenharmony_ci goto exit; 1536cd6a6acSopenharmony_ci } 1546cd6a6acSopenharmony_ci 1556cd6a6acSopenharmony_ci create_node(&node, *current, tok.line, *hll_offset, cil_strpool_add(tok.value)); 1566cd6a6acSopenharmony_ci insert_node(node, *current); 1576cd6a6acSopenharmony_ci 1586cd6a6acSopenharmony_ci cil_lexer_next(&tok); 1596cd6a6acSopenharmony_ci if (tok.type != SYMBOL && tok.type != QSTRING) { 1606cd6a6acSopenharmony_ci cil_log(CIL_ERR, "Invalid line mark syntax\n"); 1616cd6a6acSopenharmony_ci goto exit; 1626cd6a6acSopenharmony_ci } 1636cd6a6acSopenharmony_ci 1646cd6a6acSopenharmony_ci if (tok.type == QSTRING) { 1656cd6a6acSopenharmony_ci tok.value[strlen(tok.value) - 1] = '\0'; 1666cd6a6acSopenharmony_ci tok.value = tok.value+1; 1676cd6a6acSopenharmony_ci } 1686cd6a6acSopenharmony_ci 1696cd6a6acSopenharmony_ci create_node(&node, *current, tok.line, *hll_offset, cil_strpool_add(tok.value)); 1706cd6a6acSopenharmony_ci insert_node(node, *current); 1716cd6a6acSopenharmony_ci 1726cd6a6acSopenharmony_ci *hll_expand = (hll_type == CIL_KEY_SRC_HLL_LMX) ? 1 : 0; 1736cd6a6acSopenharmony_ci } 1746cd6a6acSopenharmony_ci 1756cd6a6acSopenharmony_ci cil_lexer_next(&tok); 1766cd6a6acSopenharmony_ci if (tok.type != NEWLINE) { 1776cd6a6acSopenharmony_ci cil_log(CIL_ERR, "Invalid line mark syntax\n"); 1786cd6a6acSopenharmony_ci goto exit; 1796cd6a6acSopenharmony_ci } 1806cd6a6acSopenharmony_ci 1816cd6a6acSopenharmony_ci if (!*hll_expand) { 1826cd6a6acSopenharmony_ci /* Need to increment because of the NEWLINE */ 1836cd6a6acSopenharmony_ci (*hll_offset)++; 1846cd6a6acSopenharmony_ci } 1856cd6a6acSopenharmony_ci 1866cd6a6acSopenharmony_ci return SEPOL_OK; 1876cd6a6acSopenharmony_ci 1886cd6a6acSopenharmony_ciexit: 1896cd6a6acSopenharmony_ci cil_log(CIL_ERR, "Problem with high-level line mark at line %u of %s\n", tok.line, path); 1906cd6a6acSopenharmony_ci return SEPOL_ERR; 1916cd6a6acSopenharmony_ci} 1926cd6a6acSopenharmony_ci 1936cd6a6acSopenharmony_cistatic void add_cil_path(struct cil_tree_node **current, char *path) 1946cd6a6acSopenharmony_ci{ 1956cd6a6acSopenharmony_ci struct cil_tree_node *node; 1966cd6a6acSopenharmony_ci 1976cd6a6acSopenharmony_ci create_node(&node, *current, 0, 0, NULL); 1986cd6a6acSopenharmony_ci insert_node(node, *current); 1996cd6a6acSopenharmony_ci *current = node; 2006cd6a6acSopenharmony_ci 2016cd6a6acSopenharmony_ci create_node(&node, *current, 0, 0, CIL_KEY_SRC_INFO); 2026cd6a6acSopenharmony_ci insert_node(node, *current); 2036cd6a6acSopenharmony_ci 2046cd6a6acSopenharmony_ci create_node(&node, *current, 0, 0, CIL_KEY_SRC_CIL); 2056cd6a6acSopenharmony_ci insert_node(node, *current); 2066cd6a6acSopenharmony_ci 2076cd6a6acSopenharmony_ci create_node(&node, *current, 0, 0, cil_strpool_add("1")); 2086cd6a6acSopenharmony_ci insert_node(node, *current); 2096cd6a6acSopenharmony_ci 2106cd6a6acSopenharmony_ci create_node(&node, *current, 0, 0, path); 2116cd6a6acSopenharmony_ci insert_node(node, *current); 2126cd6a6acSopenharmony_ci} 2136cd6a6acSopenharmony_ci 2146cd6a6acSopenharmony_ciint cil_parser(const char *_path, char *buffer, uint32_t size, struct cil_tree **parse_tree) 2156cd6a6acSopenharmony_ci{ 2166cd6a6acSopenharmony_ci 2176cd6a6acSopenharmony_ci int paren_count = 0; 2186cd6a6acSopenharmony_ci 2196cd6a6acSopenharmony_ci struct cil_tree *tree = NULL; 2206cd6a6acSopenharmony_ci struct cil_tree_node *node = NULL; 2216cd6a6acSopenharmony_ci struct cil_tree_node *current = NULL; 2226cd6a6acSopenharmony_ci char *path = cil_strpool_add(_path); 2236cd6a6acSopenharmony_ci struct cil_stack *stack; 2246cd6a6acSopenharmony_ci uint32_t hll_offset = 1; 2256cd6a6acSopenharmony_ci uint32_t hll_expand = 0; 2266cd6a6acSopenharmony_ci struct token tok; 2276cd6a6acSopenharmony_ci int rc = SEPOL_OK; 2286cd6a6acSopenharmony_ci 2296cd6a6acSopenharmony_ci cil_stack_init(&stack); 2306cd6a6acSopenharmony_ci 2316cd6a6acSopenharmony_ci cil_lexer_setup(buffer, size); 2326cd6a6acSopenharmony_ci 2336cd6a6acSopenharmony_ci tree = *parse_tree; 2346cd6a6acSopenharmony_ci current = tree->root; 2356cd6a6acSopenharmony_ci 2366cd6a6acSopenharmony_ci add_cil_path(¤t, path); 2376cd6a6acSopenharmony_ci 2386cd6a6acSopenharmony_ci do { 2396cd6a6acSopenharmony_ci cil_lexer_next(&tok); 2406cd6a6acSopenharmony_ci switch (tok.type) { 2416cd6a6acSopenharmony_ci case HLL_LINEMARK: 2426cd6a6acSopenharmony_ci rc = add_hll_linemark(¤t, &hll_offset, &hll_expand, stack, path); 2436cd6a6acSopenharmony_ci if (rc != SEPOL_OK) { 2446cd6a6acSopenharmony_ci goto exit; 2456cd6a6acSopenharmony_ci } 2466cd6a6acSopenharmony_ci break; 2476cd6a6acSopenharmony_ci case OPAREN: 2486cd6a6acSopenharmony_ci paren_count++; 2496cd6a6acSopenharmony_ci if (paren_count > CIL_PARSER_MAX_EXPR_DEPTH) { 2506cd6a6acSopenharmony_ci cil_log(CIL_ERR, "Number of open parenthesis exceeds limit of %d at line %d of %s\n", CIL_PARSER_MAX_EXPR_DEPTH, tok.line, path); 2516cd6a6acSopenharmony_ci goto exit; 2526cd6a6acSopenharmony_ci } 2536cd6a6acSopenharmony_ci create_node(&node, current, tok.line, hll_offset, NULL); 2546cd6a6acSopenharmony_ci insert_node(node, current); 2556cd6a6acSopenharmony_ci current = node; 2566cd6a6acSopenharmony_ci break; 2576cd6a6acSopenharmony_ci case CPAREN: 2586cd6a6acSopenharmony_ci paren_count--; 2596cd6a6acSopenharmony_ci if (paren_count < 0) { 2606cd6a6acSopenharmony_ci cil_log(CIL_ERR, "Close parenthesis without matching open at line %d of %s\n", tok.line, path); 2616cd6a6acSopenharmony_ci goto exit; 2626cd6a6acSopenharmony_ci } 2636cd6a6acSopenharmony_ci current = current->parent; 2646cd6a6acSopenharmony_ci break; 2656cd6a6acSopenharmony_ci case QSTRING: 2666cd6a6acSopenharmony_ci tok.value[strlen(tok.value) - 1] = '\0'; 2676cd6a6acSopenharmony_ci tok.value = tok.value+1; 2686cd6a6acSopenharmony_ci /* FALLTHRU */ 2696cd6a6acSopenharmony_ci case SYMBOL: 2706cd6a6acSopenharmony_ci if (paren_count == 0) { 2716cd6a6acSopenharmony_ci cil_log(CIL_ERR, "Symbol not inside parenthesis at line %d of %s\n", tok.line, path); 2726cd6a6acSopenharmony_ci goto exit; 2736cd6a6acSopenharmony_ci } 2746cd6a6acSopenharmony_ci 2756cd6a6acSopenharmony_ci create_node(&node, current, tok.line, hll_offset, cil_strpool_add(tok.value)); 2766cd6a6acSopenharmony_ci insert_node(node, current); 2776cd6a6acSopenharmony_ci break; 2786cd6a6acSopenharmony_ci case NEWLINE : 2796cd6a6acSopenharmony_ci if (!hll_expand) { 2806cd6a6acSopenharmony_ci hll_offset++; 2816cd6a6acSopenharmony_ci } 2826cd6a6acSopenharmony_ci break; 2836cd6a6acSopenharmony_ci case COMMENT: 2846cd6a6acSopenharmony_ci while (tok.type != NEWLINE && tok.type != END_OF_FILE) { 2856cd6a6acSopenharmony_ci cil_lexer_next(&tok); 2866cd6a6acSopenharmony_ci } 2876cd6a6acSopenharmony_ci if (!hll_expand) { 2886cd6a6acSopenharmony_ci hll_offset++; 2896cd6a6acSopenharmony_ci } 2906cd6a6acSopenharmony_ci if (tok.type != END_OF_FILE) { 2916cd6a6acSopenharmony_ci break; 2926cd6a6acSopenharmony_ci } 2936cd6a6acSopenharmony_ci /* FALLTHRU */ 2946cd6a6acSopenharmony_ci // Fall through if EOF 2956cd6a6acSopenharmony_ci case END_OF_FILE: 2966cd6a6acSopenharmony_ci if (paren_count > 0) { 2976cd6a6acSopenharmony_ci cil_log(CIL_ERR, "Open parenthesis without matching close at line %d of %s\n", tok.line, path); 2986cd6a6acSopenharmony_ci goto exit; 2996cd6a6acSopenharmony_ci } 3006cd6a6acSopenharmony_ci if (!cil_stack_is_empty(stack)) { 3016cd6a6acSopenharmony_ci cil_log(CIL_ERR, "High-level language line marker start without close at line %d of %s\n", tok.line, path); 3026cd6a6acSopenharmony_ci goto exit; 3036cd6a6acSopenharmony_ci } 3046cd6a6acSopenharmony_ci break; 3056cd6a6acSopenharmony_ci case UNKNOWN: 3066cd6a6acSopenharmony_ci cil_log(CIL_ERR, "Invalid token '%s' at line %d of %s\n", tok.value, tok.line, path); 3076cd6a6acSopenharmony_ci goto exit; 3086cd6a6acSopenharmony_ci default: 3096cd6a6acSopenharmony_ci cil_log(CIL_ERR, "Unknown token type '%d' at line %d of %s\n", tok.type, tok.line, path); 3106cd6a6acSopenharmony_ci goto exit; 3116cd6a6acSopenharmony_ci } 3126cd6a6acSopenharmony_ci } 3136cd6a6acSopenharmony_ci while (tok.type != END_OF_FILE); 3146cd6a6acSopenharmony_ci 3156cd6a6acSopenharmony_ci cil_lexer_destroy(); 3166cd6a6acSopenharmony_ci 3176cd6a6acSopenharmony_ci cil_stack_destroy(&stack); 3186cd6a6acSopenharmony_ci 3196cd6a6acSopenharmony_ci *parse_tree = tree; 3206cd6a6acSopenharmony_ci 3216cd6a6acSopenharmony_ci return SEPOL_OK; 3226cd6a6acSopenharmony_ci 3236cd6a6acSopenharmony_ciexit: 3246cd6a6acSopenharmony_ci while (!cil_stack_is_empty(stack)) { 3256cd6a6acSopenharmony_ci pop_hll_info(stack, &hll_offset, &hll_expand); 3266cd6a6acSopenharmony_ci } 3276cd6a6acSopenharmony_ci cil_lexer_destroy(); 3286cd6a6acSopenharmony_ci cil_stack_destroy(&stack); 3296cd6a6acSopenharmony_ci 3306cd6a6acSopenharmony_ci return SEPOL_ERR; 3316cd6a6acSopenharmony_ci} 332