• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_parser.h"
42 #include "cil_strpool.h"
43 #include "cil_stack.h"
44 
45 #define CIL_PARSER_MAX_EXPR_DEPTH (0x1 << 12)
46 
47 struct hll_info {
48 	uint32_t hll_offset;
49 	uint32_t hll_expand;
50 };
51 
push_hll_info(struct cil_stack * stack,uint32_t hll_offset,uint32_t hll_expand)52 static void push_hll_info(struct cil_stack *stack, uint32_t hll_offset, uint32_t hll_expand)
53 {
54 	struct hll_info *new = cil_malloc(sizeof(*new));
55 
56 	new->hll_offset = hll_offset;
57 	new->hll_expand = hll_expand;
58 
59 	cil_stack_push(stack, CIL_NONE, new);
60 }
61 
pop_hll_info(struct cil_stack * stack,uint32_t * hll_offset,uint32_t * hll_expand)62 static void pop_hll_info(struct cil_stack *stack, uint32_t *hll_offset, uint32_t *hll_expand)
63 {
64 	struct cil_stack_item *curr = cil_stack_pop(stack);
65 	struct hll_info *info;
66 
67 	if (!curr) {
68 		return;
69 	}
70 	info = curr->data;
71 	*hll_expand = info->hll_expand;
72 	*hll_offset = info->hll_offset;
73 	free(curr->data);
74 }
75 
create_node(struct cil_tree_node ** node,struct cil_tree_node * current,uint32_t line,uint32_t hll_offset,void * value)76 static void create_node(struct cil_tree_node **node, struct cil_tree_node *current, uint32_t line, uint32_t hll_offset, void *value)
77 {
78 	cil_tree_node_init(node);
79 	(*node)->parent = current;
80 	(*node)->flavor = CIL_NODE;
81 	(*node)->line = line;
82 	(*node)->hll_offset = hll_offset;
83 	(*node)->data = value;
84 }
85 
insert_node(struct cil_tree_node * node,struct cil_tree_node * current)86 static void insert_node(struct cil_tree_node *node, struct cil_tree_node *current)
87 {
88 	if (current->cl_head == NULL) {
89 		current->cl_head = node;
90 	} else {
91 		current->cl_tail->next = node;
92 	}
93 	current->cl_tail = node;
94 }
95 
add_hll_linemark(struct cil_tree_node ** current,uint32_t * hll_offset,uint32_t * hll_expand,struct cil_stack * stack,char * path)96 static int add_hll_linemark(struct cil_tree_node **current, uint32_t *hll_offset, uint32_t *hll_expand, struct cil_stack *stack, char *path)
97 {
98 	char *hll_type;
99 	struct cil_tree_node *node;
100 	struct token tok;
101 	uint32_t prev_hll_expand, prev_hll_offset;
102 
103 	cil_lexer_next(&tok);
104 	if (tok.type != SYMBOL) {
105 		cil_log(CIL_ERR, "Invalid line mark syntax\n");
106 		goto exit;
107 	}
108 	hll_type = cil_strpool_add(tok.value);
109 	if (hll_type != CIL_KEY_SRC_HLL_LME && hll_type != CIL_KEY_SRC_HLL_LMS && hll_type != CIL_KEY_SRC_HLL_LMX) {
110 		cil_log(CIL_ERR, "Invalid line mark syntax\n");
111 		goto exit;
112 	}
113 	if (hll_type == CIL_KEY_SRC_HLL_LME) {
114 		if (cil_stack_is_empty(stack)) {
115 			cil_log(CIL_ERR, "Line mark end without start\n");
116 			goto exit;
117 		}
118 		prev_hll_expand = *hll_expand;
119 		prev_hll_offset = *hll_offset;
120 		pop_hll_info(stack, hll_offset, hll_expand);
121 		if (!*hll_expand) {
122 			/* This is needed if not going back to an lmx section. */
123 			*hll_offset = prev_hll_offset;
124 		}
125 		if (prev_hll_expand && !*hll_expand) {
126 			/* This is needed to count the lme at the end of an lmx section
127 			 * within an lms section (or within no hll section).
128 			 */
129 			(*hll_offset)++;
130 		}
131 		*current = (*current)->parent;
132 	} else {
133 		push_hll_info(stack, *hll_offset, *hll_expand);
134 		if (cil_stack_number_of_items(stack) > CIL_PARSER_MAX_EXPR_DEPTH) {
135 			cil_log(CIL_ERR, "Number of active line marks exceeds limit of %d\n", CIL_PARSER_MAX_EXPR_DEPTH);
136 			goto exit;
137 		}
138 
139 		create_node(&node, *current, tok.line, *hll_offset, NULL);
140 		insert_node(node, *current);
141 		*current = node;
142 
143 		create_node(&node, *current, tok.line, *hll_offset, CIL_KEY_SRC_INFO);
144 		insert_node(node, *current);
145 
146 		create_node(&node, *current, tok.line, *hll_offset, hll_type);
147 		insert_node(node, *current);
148 
149 		cil_lexer_next(&tok);
150 		if (tok.type != SYMBOL) {
151 			cil_log(CIL_ERR, "Invalid line mark syntax\n");
152 			goto exit;
153 		}
154 
155 		create_node(&node, *current, tok.line, *hll_offset, cil_strpool_add(tok.value));
156 		insert_node(node, *current);
157 
158 		cil_lexer_next(&tok);
159 		if (tok.type != SYMBOL && tok.type != QSTRING) {
160 			cil_log(CIL_ERR, "Invalid line mark syntax\n");
161 			goto exit;
162 		}
163 
164 		if (tok.type == QSTRING) {
165 			tok.value[strlen(tok.value) - 1] = '\0';
166 			tok.value = tok.value+1;
167 		}
168 
169 		create_node(&node, *current, tok.line, *hll_offset, cil_strpool_add(tok.value));
170 		insert_node(node, *current);
171 
172 		*hll_expand = (hll_type == CIL_KEY_SRC_HLL_LMX) ? 1 : 0;
173 	}
174 
175 	cil_lexer_next(&tok);
176 	if (tok.type != NEWLINE) {
177 		cil_log(CIL_ERR, "Invalid line mark syntax\n");
178 		goto exit;
179 	}
180 
181 	if (!*hll_expand) {
182 		/* Need to increment because of the NEWLINE */
183 		(*hll_offset)++;
184 	}
185 
186 	return SEPOL_OK;
187 
188 exit:
189 	cil_log(CIL_ERR, "Problem with high-level line mark at line %u of %s\n", tok.line, path);
190 	return SEPOL_ERR;
191 }
192 
add_cil_path(struct cil_tree_node ** current,char * path)193 static void add_cil_path(struct cil_tree_node **current, char *path)
194 {
195 	struct cil_tree_node *node;
196 
197 	create_node(&node, *current, 0, 0, NULL);
198 	insert_node(node, *current);
199 	*current = node;
200 
201 	create_node(&node, *current, 0, 0, CIL_KEY_SRC_INFO);
202 	insert_node(node, *current);
203 
204 	create_node(&node, *current, 0, 0, CIL_KEY_SRC_CIL);
205 	insert_node(node, *current);
206 
207 	create_node(&node, *current, 0, 0, cil_strpool_add("1"));
208 	insert_node(node, *current);
209 
210 	create_node(&node, *current, 0, 0, path);
211 	insert_node(node, *current);
212 }
213 
cil_parser(const char * _path,char * buffer,uint32_t size,struct cil_tree ** parse_tree)214 int cil_parser(const char *_path, char *buffer, uint32_t size, struct cil_tree **parse_tree)
215 {
216 
217 	int paren_count = 0;
218 
219 	struct cil_tree *tree = NULL;
220 	struct cil_tree_node *node = NULL;
221 	struct cil_tree_node *current = NULL;
222 	char *path = cil_strpool_add(_path);
223 	struct cil_stack *stack;
224 	uint32_t hll_offset = 1;
225 	uint32_t hll_expand = 0;
226 	struct token tok;
227 	int rc = SEPOL_OK;
228 
229 	cil_stack_init(&stack);
230 
231 	cil_lexer_setup(buffer, size);
232 
233 	tree = *parse_tree;
234 	current = tree->root;
235 
236 	add_cil_path(&current, path);
237 
238 	do {
239 		cil_lexer_next(&tok);
240 		switch (tok.type) {
241 		case HLL_LINEMARK:
242 			rc = add_hll_linemark(&current, &hll_offset, &hll_expand, stack, path);
243 			if (rc != SEPOL_OK) {
244 				goto exit;
245 			}
246 			break;
247 		case OPAREN:
248 			paren_count++;
249 			if (paren_count > CIL_PARSER_MAX_EXPR_DEPTH) {
250 				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);
251 				goto exit;
252 			}
253 			create_node(&node, current, tok.line, hll_offset, NULL);
254 			insert_node(node, current);
255 			current = node;
256 			break;
257 		case CPAREN:
258 			paren_count--;
259 			if (paren_count < 0) {
260 				cil_log(CIL_ERR, "Close parenthesis without matching open at line %d of %s\n", tok.line, path);
261 				goto exit;
262 			}
263 			current = current->parent;
264 			break;
265 		case QSTRING:
266 			tok.value[strlen(tok.value) - 1] = '\0';
267 			tok.value = tok.value+1;
268 			/* FALLTHRU */
269 		case SYMBOL:
270 			if (paren_count == 0) {
271 				cil_log(CIL_ERR, "Symbol not inside parenthesis at line %d of %s\n", tok.line, path);
272 				goto exit;
273 			}
274 
275 			create_node(&node, current, tok.line, hll_offset, cil_strpool_add(tok.value));
276 			insert_node(node, current);
277 			break;
278 		case NEWLINE :
279 			if (!hll_expand) {
280 				hll_offset++;
281 			}
282 			break;
283 		case COMMENT:
284 			while (tok.type != NEWLINE && tok.type != END_OF_FILE) {
285 				cil_lexer_next(&tok);
286 			}
287 			if (!hll_expand) {
288 				hll_offset++;
289 			}
290 			if (tok.type != END_OF_FILE) {
291 				break;
292 			}
293 			/* FALLTHRU */
294 			// Fall through if EOF
295 		case END_OF_FILE:
296 			if (paren_count > 0) {
297 				cil_log(CIL_ERR, "Open parenthesis without matching close at line %d of %s\n", tok.line, path);
298 				goto exit;
299 			}
300 			if (!cil_stack_is_empty(stack)) {
301 				cil_log(CIL_ERR, "High-level language line marker start without close at line %d of %s\n", tok.line, path);
302 				goto exit;
303 			}
304 			break;
305 		case UNKNOWN:
306 			cil_log(CIL_ERR, "Invalid token '%s' at line %d of %s\n", tok.value, tok.line, path);
307 			goto exit;
308 		default:
309 			cil_log(CIL_ERR, "Unknown token type '%d' at line %d of %s\n", tok.type, tok.line, path);
310 			goto exit;
311 		}
312 	}
313 	while (tok.type != END_OF_FILE);
314 
315 	cil_lexer_destroy();
316 
317 	cil_stack_destroy(&stack);
318 
319 	*parse_tree = tree;
320 
321 	return SEPOL_OK;
322 
323 exit:
324 	while (!cil_stack_is_empty(stack)) {
325 		pop_hll_info(stack, &hll_offset, &hll_expand);
326 	}
327 	cil_lexer_destroy();
328 	cil_stack_destroy(&stack);
329 
330 	return SEPOL_ERR;
331 }
332