• 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 <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