[PATCH] libsepol/cil: improve recursion detection

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add support for detecting recursive blockinherits, and print a trace of
the detected loop. Output will look something like this upon detection:

  Recursive blockinherit found:
    test.cil:42: block a
    test.cil:43: blockinherit b
    test.cil:36: block b
    test.cil:37: blockinherit c
    test.cil:39: block c
    test.cil:40: blockinherit a

Additionally, improve support for detecting recursive macros/calls. Due
to the way calls are copied, the existing code only detected recursion
with call depth of three or more. Smaller depths, like

  (macro m ()
    (call m))

were not detected and caused a segfault. The callstack that was used for
this was not sufficient, so that is removed and replaced with a method
similar to the block recursion detection. A similar trace is also
displayed for recursive macros/calls.

Also, cleanup sidorder, classorder, catorder, sensorder, and in lists at
the end of resolve, fixing a potential memory leak if errors occur
during resolve.

Signed-off-by: Steve Lawrence <slawrence@xxxxxxxxxx>
---
 libsepol/cil/src/cil_resolve_ast.c | 193 +++++++++++++++++++++++++++++--------
 1 file changed, 155 insertions(+), 38 deletions(-)

diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c
index 0df5c63..79cece5 100644
--- a/libsepol/cil/src/cil_resolve_ast.c
+++ b/libsepol/cil/src/cil_resolve_ast.c
@@ -52,7 +52,6 @@ struct cil_args_resolve {
 	enum cil_pass pass;
 	uint32_t *changed;
 	char *last_resolved_name;
-	struct cil_tree_node *callstack;
 	struct cil_tree_node *optstack;
 	struct cil_tree_node *boolif;
 	struct cil_tree_node *macro;
@@ -2210,6 +2209,70 @@ exit:
 	return rc;
 }
 
+int cil_check_recursive_blockinherit(struct cil_tree_node *bi_node)
+{
+	struct cil_tree_node *curr = NULL;
+	struct cil_blockinherit *bi = NULL;
+	struct cil_block *block = NULL;
+	struct cil_list_item *item = NULL;
+	struct cil_list *trace = NULL;
+	int rc = SEPOL_ERR;
+
+	bi = bi_node->data;
+
+	for (curr = bi_node->parent; curr != NULL; curr = curr->parent) {
+		if (curr->flavor != CIL_BLOCK) {
+			continue;
+		}
+
+		block = curr->data;
+
+		if (block != bi->block) {
+			continue;
+		}
+
+		cil_log(CIL_ERR, "Recursive blockinherit found:\n");
+
+		cil_list_init(&trace, CIL_NODE);
+
+		for (curr = bi_node; curr != NULL; curr = curr->parent) {
+			if (curr->flavor == CIL_BLOCK) {
+				cil_list_prepend(trace, CIL_NODE, curr);
+			} else {
+				if (curr != bi_node) {
+					cil_list_prepend(trace, CIL_NODE, NODE(((struct cil_blockinherit *)curr->data)->block));
+				}
+				cil_list_prepend(trace, CIL_NODE, curr);
+			}
+
+			if (curr == NODE(block)) {
+				break;
+			}
+		}
+
+		cil_list_for_each(item, trace) {
+			curr = item->data;
+			cil_log(CIL_ERR, "  %s:%d: ", curr->path, curr->line);
+
+			if (curr->flavor == CIL_BLOCK) {
+				cil_log(CIL_ERR, "block %s\n", DATUM(curr->data)->name);
+			} else {
+				cil_log(CIL_ERR, "blockinherit %s\n", ((struct cil_blockinherit *)curr->data)->block_str);
+			}
+		}
+
+		cil_list_destroy(&trace, CIL_FALSE);
+
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	rc = SEPOL_OK;
+
+exit:
+	return rc;
+}
+
 int cil_resolve_blockinherit_copy(struct cil_tree_node *current, void *extra_args)
 {
 	struct cil_block *block = current->data;
@@ -2233,6 +2296,11 @@ int cil_resolve_blockinherit_copy(struct cil_tree_node *current, void *extra_arg
 	}
 
 	cil_list_for_each(item, block->bi_nodes) {
+		rc = cil_check_recursive_blockinherit(item->data);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
 		rc = cil_copy_ast(db, current, item->data);
 		if (rc != SEPOL_OK) {
 			cil_log(CIL_ERR, "Failed to copy block contents into blockinherit\n");
@@ -2500,6 +2568,77 @@ exit:
 	return rc;
 }
 
+int cil_check_recursive_call(struct cil_tree_node *call_node, struct cil_tree_node *macro_node)
+{
+	struct cil_tree_node *curr = NULL;
+	struct cil_list *trace = NULL;
+	struct cil_list_item *item = NULL;
+	struct cil_call * call = NULL;
+	struct cil_tree_node *terminating_node = NULL;
+	int rc = SEPOL_ERR;
+
+	for (curr = call_node; curr != NULL; curr = curr->parent) {
+		if (curr->flavor == CIL_CALL) {
+			if (curr == call_node) {
+				continue;
+			}
+
+			call = curr->data;
+			if (call->macro != macro_node->data) {
+				continue;
+			}
+		} else if (curr->flavor == CIL_MACRO) {
+			if (curr != macro_node) {
+				rc = SEPOL_OK;
+				goto exit;
+			}
+		} else {
+			continue;
+		}
+
+		cil_log(CIL_ERR, "Recursive macro call found:\n");
+		cil_list_init(&trace, CIL_NODE);
+
+		terminating_node = curr;
+
+		for (curr = call_node; curr != terminating_node; curr = curr->parent) {
+			if (curr->flavor == CIL_CALL) {
+				if (curr != call_node) {
+					cil_list_prepend(trace, CIL_NODE, NODE(((struct cil_call *)curr->data)->macro));
+				}
+				cil_list_prepend(trace, CIL_NODE, curr);
+			}
+		}
+
+		if (terminating_node->flavor == CIL_MACRO) {
+			cil_list_prepend(trace, CIL_NODE, terminating_node);
+		} else {
+			call = terminating_node->data;
+			cil_list_prepend(trace, CIL_NODE, NODE(call->macro));
+		}
+
+		cil_list_for_each(item, trace) {
+			curr = item->data;
+			cil_log(CIL_ERR, "  %s:%d: ", curr->path, curr->line);
+
+			if (curr->flavor == CIL_MACRO) {
+				cil_log(CIL_ERR, "macro %s\n", DATUM(curr->data)->name);
+			} else {
+				cil_log(CIL_ERR, "call %s\n", ((struct cil_call *)curr->data)->macro_str);
+			}
+		}
+
+		cil_list_destroy(&trace, CIL_FALSE);
+
+		rc = SEPOL_ERR;
+		goto exit;
+	}
+
+	rc = SEPOL_OK;
+exit:
+	return rc;
+}
+
 int cil_resolve_call1(struct cil_tree_node *current, void *extra_args)
 {
 	struct cil_call *new_call = current->data;
@@ -2736,6 +2875,12 @@ int cil_resolve_call1(struct cil_tree_node *current, void *extra_args)
 
 	if (new_call->copied == 0) {
 		new_call->copied = 1;
+
+		rc = cil_check_recursive_call(current, macro_node);
+		if (rc != SEPOL_OK) {
+			goto exit;
+		}
+
 		rc = cil_copy_ast(db, macro_node, current);
 		if (rc != SEPOL_OK) {
 			cil_log(CIL_ERR, "Failed to copy macro, rc: %d\n", rc);
@@ -3509,7 +3654,6 @@ int __cil_resolve_ast_first_child_helper(struct cil_tree_node *current, void *ex
 {
 	int rc = SEPOL_ERR;
 	struct cil_args_resolve *args = extra_args;
-	struct cil_tree_node *callstack = NULL;
 	struct cil_tree_node *optstack = NULL;
 	struct cil_tree_node *parent = NULL;
 	struct cil_tree_node *blockstack = NULL;
@@ -3519,36 +3663,18 @@ int __cil_resolve_ast_first_child_helper(struct cil_tree_node *current, void *ex
 		goto exit;
 	}
 
-	callstack = args->callstack;
 	optstack = args->optstack;
 	parent = current->parent;
 	blockstack = args->blockstack;
 
-	if (parent->flavor == CIL_CALL || parent->flavor == CIL_OPTIONAL || parent->flavor == CIL_BLOCK) {
+	if (parent->flavor == CIL_OPTIONAL || parent->flavor == CIL_BLOCK) {
 		/* push this node onto a stack */
 		cil_tree_node_init(&new);
 
 		new->data = parent->data;
 		new->flavor = parent->flavor;
 
-		if (parent->flavor == CIL_CALL) {
-			if (callstack != NULL) {
-				struct cil_tree_node *curr = NULL;
-				struct cil_call *new_call = new->data;
-				for (curr = callstack->cl_head; curr != NULL;
-					curr = curr->cl_head) {
-					struct cil_call *curr_call = curr->data;
-					if (curr_call->macro == new_call->macro) {
-						cil_log(CIL_ERR, "Recursive macro call found\n");
-						rc = SEPOL_ERR;
-						goto exit;
-					}
-				}
-				callstack->parent = new;
-				new->cl_head = callstack;
-			}
-			args->callstack = new;
-		} else if (parent->flavor == CIL_OPTIONAL) {
+		if (parent->flavor == CIL_OPTIONAL) {
 			if (optstack != NULL) {
 				optstack->parent = new;
 				new->cl_head = optstack;
@@ -3587,15 +3713,7 @@ int __cil_resolve_ast_last_child_helper(struct cil_tree_node *current, void *ext
 
 	parent = current->parent;
 
-	if (parent->flavor == CIL_CALL) {
-		/* pop off the stack */
-		struct cil_tree_node *callstack = args->callstack;
-		args->callstack = callstack->cl_head;
-		if (callstack->cl_head) {
-			callstack->cl_head->parent = NULL;
-		}
-		free(callstack);
-	} else if (parent->flavor == CIL_MACRO) {
+	if (parent->flavor == CIL_MACRO) {
 		args->macro = NULL;
 	} else if (parent->flavor == CIL_OPTIONAL) {
 		struct cil_tree_node *optstack;
@@ -3645,7 +3763,6 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current)
 	extra_args.pass = pass;
 	extra_args.changed = &changed;
 	extra_args.last_resolved_name = NULL;
-	extra_args.callstack = NULL;
 	extra_args.optstack = NULL;
 	extra_args.boolif= NULL;
 	extra_args.macro = NULL;
@@ -3737,12 +3854,6 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current)
 
 		/* reset the arguments */
 		changed = 0;
-		while (extra_args.callstack != NULL) {
-			struct cil_tree_node *curr = extra_args.callstack;
-			struct cil_tree_node *next = curr->cl_head;
-			free(curr);
-			extra_args.callstack = next;
-		}
 		while (extra_args.optstack != NULL) {
 			struct cil_tree_node *curr = extra_args.optstack;
 			struct cil_tree_node *next = curr->cl_head;
@@ -3764,6 +3875,12 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current)
 
 	rc = SEPOL_OK;
 exit:
+	__cil_ordered_lists_destroy(&extra_args.sidorder_lists);
+	__cil_ordered_lists_destroy(&extra_args.classorder_lists);
+	__cil_ordered_lists_destroy(&extra_args.catorder_lists);
+	__cil_ordered_lists_destroy(&extra_args.sensitivityorder_lists);
+	cil_list_destroy(&extra_args.in_list, CIL_FALSE);
+
 	return rc;
 }
 
-- 
2.4.3

_______________________________________________
Selinux mailing list
Selinux@xxxxxxxxxxxxx
To unsubscribe, send email to Selinux-leave@xxxxxxxxxxxxx.
To get help, send an email containing "help" to Selinux-request@xxxxxxxxxxxxx.



[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux