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 <stdio.h>
31 #include <stdarg.h>
32 #include <inttypes.h>
33
34 #include <sepol/policydb/conditional.h>
35
36 #include "cil_internal.h"
37 #include "cil_flavor.h"
38 #include "cil_log.h"
39 #include "cil_tree.h"
40 #include "cil_list.h"
41 #include "cil_parser.h"
42 #include "cil_strpool.h"
43
cil_tree_error(const char * msg,...)44 __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) void cil_tree_error(const char* msg, ...)
45 {
46 va_list ap;
47 va_start(ap, msg);
48 cil_vlog(CIL_ERR, msg, ap);
49 va_end(ap);
50 exit(1);
51 }
52
cil_tree_get_next_path(struct cil_tree_node * node,char ** info_kind,uint32_t * hll_line,char ** path)53 struct cil_tree_node *cil_tree_get_next_path(struct cil_tree_node *node, char **info_kind, uint32_t *hll_line, char **path)
54 {
55 int rc;
56
57 if (!node) {
58 goto exit;
59 }
60
61 node = node->parent;
62
63 while (node) {
64 if (node->flavor == CIL_NODE && node->data == NULL) {
65 if (node->cl_head && node->cl_head->data == CIL_KEY_SRC_INFO) {
66 if (!node->cl_head->next || !node->cl_head->next->next || !node->cl_head->next->next->next) {
67 goto exit;
68 }
69 /* Parse Tree */
70 *info_kind = node->cl_head->next->data;
71 rc = cil_string_to_uint32(node->cl_head->next->next->data, hll_line, 10);
72 if (rc != SEPOL_OK) {
73 goto exit;
74 }
75 *path = node->cl_head->next->next->next->data;
76 return node;
77 }
78 node = node->parent;
79 } else if (node->flavor == CIL_SRC_INFO) {
80 /* AST */
81 struct cil_src_info *info = node->data;
82 *info_kind = info->kind;
83 *hll_line = info->hll_line;
84 *path = info->path;
85 return node;
86 } else {
87 if (node->flavor == CIL_CALL) {
88 struct cil_call *call = node->data;
89 node = NODE(call->macro);
90 } else if (node->flavor == CIL_BLOCKINHERIT) {
91 struct cil_blockinherit *inherit = node->data;
92 node = NODE(inherit->block);
93 } else {
94 node = node->parent;
95 }
96 }
97 }
98
99 exit:
100 *info_kind = NULL;
101 *hll_line = 0;
102 *path = NULL;
103 return NULL;
104 }
105
cil_tree_get_cil_path(struct cil_tree_node * node)106 char *cil_tree_get_cil_path(struct cil_tree_node *node)
107 {
108 char *info_kind;
109 uint32_t hll_line;
110 char *path;
111
112 while (node) {
113 node = cil_tree_get_next_path(node, &info_kind, &hll_line, &path);
114 if (node && info_kind == CIL_KEY_SRC_CIL) {
115 return path;
116 }
117 }
118
119 return NULL;
120 }
121
cil_tree_log(struct cil_tree_node * node,enum cil_log_level lvl,const char * msg,...)122 __attribute__((format (printf, 3, 4))) void cil_tree_log(struct cil_tree_node *node, enum cil_log_level lvl, const char* msg, ...)
123 {
124 va_list ap;
125
126 va_start(ap, msg);
127 cil_vlog(lvl, msg, ap);
128 va_end(ap);
129
130 if (node) {
131 char *path = NULL;
132 uint32_t hll_offset = node->hll_offset;
133
134 path = cil_tree_get_cil_path(node);
135
136 if (path != NULL) {
137 cil_log(lvl, " at %s:%u", path, node->line);
138 }
139
140 while (node) {
141 do {
142 char *info_kind;
143 uint32_t hll_line;
144
145 node = cil_tree_get_next_path(node, &info_kind, &hll_line, &path);
146 if (!node || info_kind == CIL_KEY_SRC_CIL) {
147 break;
148 }
149 if (info_kind == CIL_KEY_SRC_HLL_LMS) {
150 hll_line += hll_offset - node->hll_offset - 1;
151 }
152
153 cil_log(lvl," from %s:%u", path, hll_line);
154 } while (1);
155 }
156 }
157
158 cil_log(lvl,"\n");
159 }
160
cil_tree_subtree_has_decl(struct cil_tree_node * node)161 int cil_tree_subtree_has_decl(struct cil_tree_node *node)
162 {
163 while (node) {
164 if (node->flavor >= CIL_MIN_DECLARATIVE) {
165 return CIL_TRUE;
166 }
167 if (node->cl_head != NULL) {
168 if (cil_tree_subtree_has_decl(node->cl_head))
169 return CIL_TRUE;
170 }
171 node = node->next;
172 }
173
174 return CIL_FALSE;
175 }
176
cil_tree_init(struct cil_tree ** tree)177 int cil_tree_init(struct cil_tree **tree)
178 {
179 struct cil_tree *new_tree = cil_malloc(sizeof(*new_tree));
180
181 cil_tree_node_init(&new_tree->root);
182
183 *tree = new_tree;
184
185 return SEPOL_OK;
186 }
187
cil_tree_destroy(struct cil_tree ** tree)188 void cil_tree_destroy(struct cil_tree **tree)
189 {
190 if (tree == NULL || *tree == NULL) {
191 return;
192 }
193
194 cil_tree_subtree_destroy((*tree)->root);
195 free(*tree);
196 *tree = NULL;
197 }
198
cil_tree_subtree_destroy(struct cil_tree_node * node)199 void cil_tree_subtree_destroy(struct cil_tree_node *node)
200 {
201 cil_tree_children_destroy(node);
202 cil_tree_node_destroy(&node);
203 }
204
cil_tree_children_destroy(struct cil_tree_node * node)205 void cil_tree_children_destroy(struct cil_tree_node *node)
206 {
207 struct cil_tree_node *curr, *next;
208
209 if (!node) {
210 return;
211 }
212
213 curr = node->cl_head;
214 while (curr) {
215 next = curr->next;
216 cil_tree_children_destroy(curr);
217 cil_tree_node_destroy(&curr);
218 curr = next;
219 }
220 node->cl_head = NULL;
221 node->cl_tail = NULL;
222 }
223
cil_tree_node_init(struct cil_tree_node ** node)224 void cil_tree_node_init(struct cil_tree_node **node)
225 {
226 struct cil_tree_node *new_node = cil_malloc(sizeof(*new_node));
227 new_node->cl_head = NULL;
228 new_node->cl_tail = NULL;
229 new_node->parent = NULL;
230 new_node->data = NULL;
231 new_node->next = NULL;
232 new_node->flavor = CIL_ROOT;
233 new_node->line = 0;
234 new_node->hll_offset = 0;
235
236 *node = new_node;
237 }
238
cil_tree_node_destroy(struct cil_tree_node ** node)239 void cil_tree_node_destroy(struct cil_tree_node **node)
240 {
241 struct cil_symtab_datum *datum;
242
243 if (node == NULL || *node == NULL) {
244 return;
245 }
246
247 if ((*node)->flavor >= CIL_MIN_DECLARATIVE) {
248 datum = (*node)->data;
249 cil_symtab_datum_remove_node(datum, *node);
250 if (datum->nodes == NULL) {
251 cil_destroy_data(&(*node)->data, (*node)->flavor);
252 }
253 } else {
254 cil_destroy_data(&(*node)->data, (*node)->flavor);
255 }
256 free(*node);
257 *node = NULL;
258 }
259
260 /* Perform depth-first walk of the tree
261 Parameters:
262 start_node: root node to start walking from
263 process_node: function to call when visiting a node
264 Takes parameters:
265 node: node being visited
266 finished: boolean indicating to the tree walker that it should move on from this branch
267 extra_args: additional data
268 first_child: Function to call before entering list of children
269 Takes parameters:
270 node: node of first child
271 extra args: additional data
272 last_child: Function to call when finished with the last child of a node's children
273 extra_args: any additional data to be passed to the helper functions
274 */
275
cil_tree_walk_core(struct cil_tree_node * node,int (* process_node)(struct cil_tree_node * node,uint32_t * finished,void * extra_args),int (* first_child)(struct cil_tree_node * node,void * extra_args),int (* last_child)(struct cil_tree_node * node,void * extra_args),void * extra_args)276 int cil_tree_walk_core(struct cil_tree_node *node,
277 int (*process_node)(struct cil_tree_node *node, uint32_t *finished, void *extra_args),
278 int (*first_child)(struct cil_tree_node *node, void *extra_args),
279 int (*last_child)(struct cil_tree_node *node, void *extra_args),
280 void *extra_args)
281 {
282 int rc = SEPOL_ERR;
283
284 while (node) {
285 uint32_t finished = CIL_TREE_SKIP_NOTHING;
286
287 if (process_node != NULL) {
288 rc = (*process_node)(node, &finished, extra_args);
289 if (rc != SEPOL_OK) {
290 cil_tree_log(node, CIL_INFO, "Problem");
291 return rc;
292 }
293 }
294
295 if (finished & CIL_TREE_SKIP_NEXT) {
296 return SEPOL_OK;
297 }
298
299 if (node->cl_head != NULL && !(finished & CIL_TREE_SKIP_HEAD)) {
300 rc = cil_tree_walk(node, process_node, first_child, last_child, extra_args);
301 if (rc != SEPOL_OK) {
302 return rc;
303 }
304 }
305
306 node = node->next;
307 }
308
309 return SEPOL_OK;
310 }
311
cil_tree_walk(struct cil_tree_node * node,int (* process_node)(struct cil_tree_node * node,uint32_t * finished,void * extra_args),int (* first_child)(struct cil_tree_node * node,void * extra_args),int (* last_child)(struct cil_tree_node * node,void * extra_args),void * extra_args)312 int cil_tree_walk(struct cil_tree_node *node,
313 int (*process_node)(struct cil_tree_node *node, uint32_t *finished, void *extra_args),
314 int (*first_child)(struct cil_tree_node *node, void *extra_args),
315 int (*last_child)(struct cil_tree_node *node, void *extra_args),
316 void *extra_args)
317 {
318 int rc = SEPOL_ERR;
319
320 if (!node || !node->cl_head) {
321 return SEPOL_OK;
322 }
323
324 if (first_child != NULL) {
325 rc = (*first_child)(node->cl_head, extra_args);
326 if (rc != SEPOL_OK) {
327 cil_tree_log(node, CIL_INFO, "Problem");
328 return rc;
329 }
330 }
331
332 rc = cil_tree_walk_core(node->cl_head, process_node, first_child, last_child, extra_args);
333 if (rc != SEPOL_OK) {
334 return rc;
335 }
336
337 if (last_child != NULL) {
338 rc = (*last_child)(node->cl_tail, extra_args);
339 if (rc != SEPOL_OK) {
340 cil_tree_log(node, CIL_INFO, "Problem");
341 return rc;
342 }
343 }
344
345 return SEPOL_OK;
346 }
347