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(¤t, path);
237
238 do {
239 cil_lexer_next(&tok);
240 switch (tok.type) {
241 case HLL_LINEMARK:
242 rc = add_hll_linemark(¤t, &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