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