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(¤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
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