• 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_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 
push_hll_info(struct cil_stack * stack,int hll_lineno,int hll_expand)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 
pop_hll_info(struct cil_stack * stack,int * hll_lineno,int * hll_expand)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 
create_node(struct cil_tree_node ** node,struct cil_tree_node * current,int line,int hll_line,void * value)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 
insert_node(struct cil_tree_node * node,struct cil_tree_node * current)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 
add_hll_linemark(struct cil_tree_node ** current,int * hll_lineno,int * hll_expand,struct cil_stack * stack,char * path)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 
add_cil_path(struct cil_tree_node ** current,char * path)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 
cil_parser(char * _path,char * buffer,uint32_t size,struct cil_tree ** parse_tree)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 			/* 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 
309 exit:
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