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 44char *CIL_KEY_HLL_LMS; 45char *CIL_KEY_HLL_LMX; 46char *CIL_KEY_HLL_LME; 47 48struct hll_info { 49 int hll_lineno; 50 int hll_expand; 51}; 52 53static 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 63static 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 81static 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 91static 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 101static 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 176exit: 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 181static 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 199int 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 /* FALLTHRU */ 255 case SYMBOL: 256 if (paren_count == 0) { 257 cil_log(CIL_ERR, "Symbol not inside parenthesis at line %d of %s\n", tok.line, path); 258 goto exit; 259 } 260 261 create_node(&node, current, tok.line, hll_lineno, cil_strpool_add(tok.value)); 262 insert_node(node, current); 263 break; 264 case NEWLINE : 265 if (!hll_expand) { 266 hll_lineno++; 267 } 268 break; 269 case COMMENT: 270 while (tok.type != NEWLINE && tok.type != END_OF_FILE) { 271 cil_lexer_next(&tok); 272 } 273 if (!hll_expand) { 274 hll_lineno++; 275 } 276 if (tok.type != END_OF_FILE) { 277 break; 278 } 279 /* FALLTHRU */ 280 // Fall through if EOF 281 case END_OF_FILE: 282 if (paren_count > 0) { 283 cil_log(CIL_ERR, "Open parenthesis without matching close at line %d of %s\n", tok.line, path); 284 goto exit; 285 } 286 if (!cil_stack_is_empty(stack)) { 287 cil_log(CIL_ERR, "High-level language line marker start without close at line %d of %s\n", tok.line, path); 288 goto exit; 289 } 290 break; 291 case UNKNOWN: 292 cil_log(CIL_ERR, "Invalid token '%s' at line %d of %s\n", tok.value, tok.line, path); 293 goto exit; 294 default: 295 cil_log(CIL_ERR, "Unknown token type '%d' at line %d of %s\n", tok.type, tok.line, path); 296 goto exit; 297 } 298 } 299 while (tok.type != END_OF_FILE); 300 301 cil_lexer_destroy(); 302 303 cil_stack_destroy(&stack); 304 305 *parse_tree = tree; 306 307 return SEPOL_OK; 308 309exit: 310 while (!cil_stack_is_empty(stack)) { 311 pop_hll_info(stack, &hll_lineno, &hll_expand); 312 } 313 cil_stack_destroy(&stack); 314 315 return SEPOL_ERR; 316} 317