Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright 2011 Tresys Technology, LLC. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are met:
      6  *
      7  *    1. Redistributions of source code must retain the above copyright notice,
      8  *       this list of conditions and the following disclaimer.
      9  *
     10  *    2. Redistributions in binary form must reproduce the above copyright notice,
     11  *       this list of conditions and the following disclaimer in the documentation
     12  *       and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
     15  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     16  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     17  * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     18  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     19  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     21  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     22  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     23  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  *
     25  * The views and conclusions contained in the software and documentation are those
     26  * of the authors and should not be interpreted as representing official policies,
     27  * either expressed or implied, of Tresys Technology, LLC.
     28  */
     29 
     30 #include <stdlib.h>
     31 #include <stdio.h>
     32 #include <string.h>
     33 #include <stdint.h>
     34 #include <sepol/errcodes.h>
     35 
     36 #include "cil_internal.h"
     37 #include "cil_log.h"
     38 #include "cil_mem.h"
     39 #include "cil_tree.h"
     40 #include "cil_lexer.h"
     41 #include "cil_strpool.h"
     42 #include "cil_stack.h"
     43 
     44 char *CIL_KEY_HLL_LMS;
     45 char *CIL_KEY_HLL_LMX;
     46 char *CIL_KEY_HLL_LME;
     47 
     48 struct hll_info {
     49 	int hll_lineno;
     50 	int hll_expand;
     51 };
     52 
     53 static void push_hll_info(struct cil_stack *stack, int hll_lineno, int hll_expand)
     54 {
     55 	struct hll_info *new = cil_malloc(sizeof(*new));
     56 
     57 	new->hll_lineno = hll_lineno;
     58 	new->hll_expand = hll_expand;
     59 
     60 	cil_stack_push(stack, CIL_NONE, new);
     61 }
     62 
     63 static void pop_hll_info(struct cil_stack *stack, int *hll_lineno, int *hll_expand)
     64 {
     65 	struct cil_stack_item *curr = cil_stack_pop(stack);
     66 	struct cil_stack_item *prev = cil_stack_peek(stack);
     67 	struct hll_info *old;
     68 
     69 	free(curr->data);
     70 
     71 	if (!prev) {
     72 		*hll_lineno = -1;
     73 		*hll_expand = -1;
     74 	} else {
     75 		old = prev->data;
     76 		*hll_lineno = old->hll_lineno;
     77 		*hll_expand = old->hll_expand;
     78 	}
     79 }
     80 
     81 static void create_node(struct cil_tree_node **node, struct cil_tree_node *current, int line, int hll_line, void *value)
     82 {
     83 	cil_tree_node_init(node);
     84 	(*node)->parent = current;
     85 	(*node)->flavor = CIL_NODE;
     86 	(*node)->line = line;
     87 	(*node)->hll_line = hll_line;
     88 	(*node)->data = value;
     89 }
     90 
     91 static void insert_node(struct cil_tree_node *node, struct cil_tree_node *current)
     92 {
     93 	if (current->cl_head == NULL) {
     94 		current->cl_head = node;
     95 	} else {
     96 		current->cl_tail->next = node;
     97 	}
     98 	current->cl_tail = node;
     99 }
    100 
    101 static int add_hll_linemark(struct cil_tree_node **current, int *hll_lineno, int *hll_expand, struct cil_stack *stack, char *path)
    102 {
    103 	char *hll_type;
    104 	struct cil_tree_node *node;
    105 	struct token tok;
    106 	char *hll_file;
    107 	char *end = NULL;
    108 
    109 	cil_lexer_next(&tok);
    110 	hll_type = cil_strpool_add(tok.value);
    111 	if (hll_type == CIL_KEY_HLL_LME) {
    112 		if (cil_stack_is_empty(stack)) {
    113 			cil_log(CIL_ERR, "Line mark end without start\n");
    114 			goto exit;
    115 		}
    116 		pop_hll_info(stack, hll_lineno, hll_expand);
    117 		*current = (*current)->parent;
    118 	} else {
    119 		create_node(&node, *current, tok.line, *hll_lineno, NULL);
    120 		insert_node(node, *current);
    121 		*current = node;
    122 
    123 		create_node(&node, *current, tok.line, *hll_lineno, CIL_KEY_SRC_INFO);
    124 		insert_node(node, *current);
    125 
    126 		create_node(&node, *current, tok.line, *hll_lineno, CIL_KEY_SRC_HLL);
    127 		insert_node(node, *current);
    128 
    129 		if (hll_type == CIL_KEY_HLL_LMS) {
    130 			*hll_expand = 0;
    131 		} else if (hll_type == CIL_KEY_HLL_LMX) {
    132 			*hll_expand = 1;
    133 		} else {
    134 			cil_log(CIL_ERR, "Invalid line mark syntax\n");
    135 			goto exit;
    136 		}
    137 
    138 		cil_lexer_next(&tok);
    139 		if (tok.type != SYMBOL) {
    140 			cil_log(CIL_ERR, "Invalid line mark syntax\n");
    141 			goto exit;
    142 		}
    143 		*hll_lineno = strtol(tok.value, &end, 10);
    144 		if (errno == ERANGE || *end != '\0') {
    145 			cil_log(CIL_ERR, "Problem parsing line number for line mark\n");
    146 			goto exit;
    147 		}
    148 
    149 		push_hll_info(stack, *hll_lineno, *hll_expand);
    150 
    151 		cil_lexer_next(&tok);
    152 		if (tok.type != SYMBOL && tok.type != QSTRING) {
    153 			cil_log(CIL_ERR, "Invalid line mark syntax\n");
    154 			goto exit;
    155 		}
    156 
    157 		if (tok.type == QSTRING) {
    158 			tok.value[strlen(tok.value) - 1] = '\0';
    159 			tok.value = tok.value+1;
    160 		}
    161 
    162 		hll_file = cil_strpool_add(tok.value);
    163 
    164 		create_node(&node, *current, tok.line, *hll_lineno, hll_file);
    165 		insert_node(node, *current);
    166 	}
    167 
    168 	cil_lexer_next(&tok);
    169 	if (tok.type != NEWLINE) {
    170 		cil_log(CIL_ERR, "Invalid line mark syntax\n");
    171 		goto exit;
    172 	}
    173 
    174 	return SEPOL_OK;
    175 
    176 exit:
    177 	cil_log(CIL_ERR, "Problem with high-level line mark at line %d of %s\n", tok.line, path);
    178 	return SEPOL_ERR;
    179 }
    180 
    181 static void add_cil_path(struct cil_tree_node **current, char *path)
    182 {
    183 	struct cil_tree_node *node;
    184 
    185 	create_node(&node, *current, 0, 0, NULL);
    186 	insert_node(node, *current);
    187 	*current = node;
    188 
    189 	create_node(&node, *current, 0, 0, CIL_KEY_SRC_INFO);
    190 	insert_node(node, *current);
    191 
    192 	create_node(&node, *current, 0, 0, CIL_KEY_SRC_CIL);
    193 	insert_node(node, *current);
    194 
    195 	create_node(&node, *current, 0, 0, path);
    196 	insert_node(node, *current);
    197 }
    198 
    199 int cil_parser(char *_path, char *buffer, uint32_t size, struct cil_tree **parse_tree)
    200 {
    201 
    202 	int paren_count = 0;
    203 
    204 	struct cil_tree *tree = NULL;
    205 	struct cil_tree_node *node = NULL;
    206 	struct cil_tree_node *current = NULL;
    207 	char *path = cil_strpool_add(_path);
    208 	struct cil_stack *stack;
    209 	int hll_lineno = -1;
    210 	int hll_expand = -1;
    211 	struct token tok;
    212 	int rc = SEPOL_OK;
    213 
    214 	CIL_KEY_HLL_LMS = cil_strpool_add("lms");
    215 	CIL_KEY_HLL_LMX = cil_strpool_add("lmx");
    216 	CIL_KEY_HLL_LME = cil_strpool_add("lme");
    217 
    218 	cil_stack_init(&stack);
    219 
    220 	cil_lexer_setup(buffer, size);
    221 
    222 	tree = *parse_tree;
    223 	current = tree->root;
    224 
    225 	add_cil_path(&current, path);
    226 
    227 	do {
    228 		cil_lexer_next(&tok);
    229 		switch (tok.type) {
    230 		case HLL_LINEMARK:
    231 			rc = add_hll_linemark(&current, &hll_lineno, &hll_expand, stack, path);
    232 			if (rc != SEPOL_OK) {
    233 				goto exit;
    234 			}
    235 			break;
    236 		case OPAREN:
    237 			paren_count++;
    238 
    239 			create_node(&node, current, tok.line, hll_lineno, NULL);
    240 			insert_node(node, current);
    241 			current = node;
    242 			break;
    243 		case CPAREN:
    244 			paren_count--;
    245 			if (paren_count < 0) {
    246 				cil_log(CIL_ERR, "Close parenthesis without matching open at line %d of %s\n", tok.line, path);
    247 				goto exit;
    248 			}
    249 			current = current->parent;
    250 			break;
    251 		case QSTRING:
    252 			tok.value[strlen(tok.value) - 1] = '\0';
    253 			tok.value = tok.value+1;
    254 		case SYMBOL:
    255 			if (paren_count == 0) {
    256 				cil_log(CIL_ERR, "Symbol not inside parenthesis at line %d of %s\n", tok.line, path);
    257 				goto exit;
    258 			}
    259 
    260 			create_node(&node, current, tok.line, hll_lineno, cil_strpool_add(tok.value));
    261 			insert_node(node, current);
    262 			break;
    263 		case NEWLINE :
    264 			if (!hll_expand) {
    265 				hll_lineno++;
    266 			}
    267 			break;
    268 		case COMMENT:
    269 			while (tok.type != NEWLINE && tok.type != END_OF_FILE) {
    270 				cil_lexer_next(&tok);
    271 			}
    272 			if (!hll_expand) {
    273 				hll_lineno++;
    274 			}
    275 			if (tok.type != END_OF_FILE) {
    276 				break;
    277 			}
    278 			// Fall through if EOF
    279 		case END_OF_FILE:
    280 			if (paren_count > 0) {
    281 				cil_log(CIL_ERR, "Open parenthesis without matching close at line %d of %s\n", tok.line, path);
    282 				goto exit;
    283 			}
    284 			if (!cil_stack_is_empty(stack)) {
    285 				cil_log(CIL_ERR, "High-level language line marker start without close at line %d of %s\n", tok.line, path);
    286 				goto exit;
    287 			}
    288 			break;
    289 		case UNKNOWN:
    290 			cil_log(CIL_ERR, "Invalid token '%s' at line %d of %s\n", tok.value, tok.line, path);
    291 			goto exit;
    292 		default:
    293 			cil_log(CIL_ERR, "Unknown token type '%d' at line %d of %s\n", tok.type, tok.line, path);
    294 			goto exit;
    295 		}
    296 	}
    297 	while (tok.type != END_OF_FILE);
    298 
    299 	cil_lexer_destroy();
    300 
    301 	cil_stack_destroy(&stack);
    302 
    303 	*parse_tree = tree;
    304 
    305 	return SEPOL_OK;
    306 
    307 exit:
    308 	while (!cil_stack_is_empty(stack)) {
    309 		pop_hll_info(stack, &hll_lineno, &hll_expand);
    310 	}
    311 	cil_stack_destroy(&stack);
    312 
    313 	return SEPOL_ERR;
    314 }
    315