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(¤t, path); 226 227 do { 228 cil_lexer_next(&tok); 229 switch (tok.type) { 230 case HLL_LINEMARK: 231 rc = add_hll_linemark(¤t, &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