Blame SOURCES/0034-libsepol-cil-Check-for-statements-not-allowed-in-opt.patch

71cd55
From 340f0eb7f3673e8aacaf0a96cbfcd4d12a405521 Mon Sep 17 00:00:00 2001
71cd55
From: James Carter <jwcart2@gmail.com>
71cd55
Date: Tue, 30 Mar 2021 13:39:18 -0400
71cd55
Subject: [PATCH] libsepol/cil: Check for statements not allowed in optional
71cd55
 blocks
71cd55
71cd55
While there are some checks for invalid statements in an optional
71cd55
block when resolving the AST, there are no checks when building the
71cd55
AST.
71cd55
71cd55
OSS-Fuzz found the following policy which caused a null dereference
71cd55
in cil_tree_get_next_path().
71cd55
  (blockinherit b3)
71cd55
  (sid SID)
71cd55
  (sidorder(SID))
71cd55
  (optional o
71cd55
    (ibpkeycon :(1 0)s)
71cd55
    (block b3
71cd55
      (filecon""block())
71cd55
      (filecon""block())))
71cd55
71cd55
The problem is that the blockinherit copies block b3 before
71cd55
the optional block is disabled. When the optional is disabled,
71cd55
block b3 is deleted along with everything else in the optional.
71cd55
Later, when filecon statements with the same path are found an
71cd55
error message is produced and in trying to find out where the block
71cd55
was copied from, the reference to the deleted block is used. The
71cd55
error handling code assumes (rightly) that if something was copied
71cd55
from a block then that block should still exist.
71cd55
71cd55
It is clear that in-statements, blocks, and macros cannot be in an
71cd55
optional, because that allows nodes to be copied from the optional
71cd55
block to somewhere outside even though the optional could be disabled
71cd55
later. When optionals are disabled the AST is reset and the
71cd55
resolution is restarted at the point of resolving macro calls, so
71cd55
anything resolved before macro calls will never be re-resolved.
71cd55
This includes tunableifs, in-statements, blockinherits,
71cd55
blockabstracts, and macro definitions. Tunable declarations also
71cd55
cannot be in an optional block because they are needed to resolve
71cd55
tunableifs. It should be fine to allow blockinherit statements in
71cd55
an optional, because that is copying nodes from outside the optional
71cd55
to the optional and if the optional is later disabled, everything
71cd55
will be deleted anyway.
71cd55
71cd55
Check and quit with an error if a tunable declaration, in-statement,
71cd55
block, blockabstract, or macro definition is found within an
71cd55
optional when either building or resolving the AST.
71cd55
71cd55
Signed-off-by: James Carter <jwcart2@gmail.com>
71cd55
---
71cd55
 libsepol/cil/src/cil_build_ast.c   | 32 ++++++++++++++++++++++++++++++
71cd55
 libsepol/cil/src/cil_resolve_ast.c |  4 +++-
71cd55
 2 files changed, 35 insertions(+), 1 deletion(-)
71cd55
71cd55
diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c
71cd55
index 96c944975def..8825485855f6 100644
71cd55
--- a/libsepol/cil/src/cil_build_ast.c
71cd55
+++ b/libsepol/cil/src/cil_build_ast.c
71cd55
@@ -52,6 +52,7 @@ struct cil_args_build {
71cd55
 	struct cil_tree_node *tunif;
71cd55
 	struct cil_tree_node *in;
71cd55
 	struct cil_tree_node *macro;
71cd55
+	struct cil_tree_node *optional;
71cd55
 	struct cil_tree_node *boolif;
71cd55
 };
71cd55
 
71cd55
@@ -6071,6 +6072,7 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f
71cd55
 	struct cil_tree_node *tunif = args->tunif;
71cd55
 	struct cil_tree_node *in = args->in;
71cd55
 	struct cil_tree_node *macro = args->macro;
71cd55
+	struct cil_tree_node *optional = args->optional;
71cd55
 	struct cil_tree_node *boolif = args->boolif;
71cd55
 	struct cil_tree_node *ast_node = NULL;
71cd55
 	int rc = SEPOL_ERR;
71cd55
@@ -6121,6 +6123,18 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f
71cd55
 		}
71cd55
 	}
71cd55
 
71cd55
+	if (optional != NULL) {
71cd55
+		if (parse_current->data == CIL_KEY_TUNABLE ||
71cd55
+			parse_current->data == CIL_KEY_IN ||
71cd55
+			parse_current->data == CIL_KEY_BLOCK ||
71cd55
+			parse_current->data == CIL_KEY_BLOCKABSTRACT ||
71cd55
+			parse_current->data == CIL_KEY_MACRO) {
71cd55
+			rc = SEPOL_ERR;
71cd55
+			cil_tree_log(parse_current, CIL_ERR, "%s is not allowed in optionals", (char *)parse_current->data);
71cd55
+			goto exit;
71cd55
+		}
71cd55
+	}
71cd55
+
71cd55
 	if (boolif != NULL) {
71cd55
 		if (parse_current->data != CIL_KEY_TUNABLEIF &&
71cd55
 			parse_current->data != CIL_KEY_CALL &&
71cd55
@@ -6462,6 +6476,10 @@ int __cil_build_ast_first_child_helper(__attribute__((unused)) struct cil_tree_n
71cd55
 		args->macro = ast;
71cd55
 	}
71cd55
 
71cd55
+	if (ast->flavor == CIL_OPTIONAL) {
71cd55
+		args->optional = ast;
71cd55
+	}
71cd55
+
71cd55
 	if (ast->flavor == CIL_BOOLEANIF) {
71cd55
 		args->boolif = ast;
71cd55
 	}
71cd55
@@ -6492,6 +6510,19 @@ int __cil_build_ast_last_child_helper(struct cil_tree_node *parse_current, void
71cd55
 		args->macro = NULL;
71cd55
 	}
71cd55
 
71cd55
+	if (ast->flavor == CIL_OPTIONAL) {
71cd55
+		struct cil_tree_node *n = ast->parent;
71cd55
+		args->optional = NULL;
71cd55
+		/* Optionals can be nested */
71cd55
+		while (n && n->flavor != CIL_ROOT) {
71cd55
+			if (n->flavor == CIL_OPTIONAL) {
71cd55
+				args->optional = n;
71cd55
+				break;
71cd55
+			}
71cd55
+			n = n->parent;
71cd55
+		}
71cd55
+	}
71cd55
+
71cd55
 	if (ast->flavor == CIL_BOOLEANIF) {
71cd55
 		args->boolif = NULL;
71cd55
 	}
71cd55
@@ -6520,6 +6551,7 @@ int cil_build_ast(struct cil_db *db, struct cil_tree_node *parse_tree, struct ci
71cd55
 	extra_args.tunif = NULL;
71cd55
 	extra_args.in = NULL;
71cd55
 	extra_args.macro = NULL;
71cd55
+	extra_args.optional = NULL;
71cd55
 	extra_args.boolif = NULL;
71cd55
 
71cd55
 	rc = cil_tree_walk(parse_tree, __cil_build_ast_node_helper, __cil_build_ast_first_child_helper, __cil_build_ast_last_child_helper, &extra_args);
71cd55
diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c
71cd55
index 56295a047ba2..efff0f2ec49d 100644
71cd55
--- a/libsepol/cil/src/cil_resolve_ast.c
71cd55
+++ b/libsepol/cil/src/cil_resolve_ast.c
71cd55
@@ -3808,8 +3808,10 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished
71cd55
 
71cd55
 	if (optional != NULL) {
71cd55
 		if (node->flavor == CIL_TUNABLE ||
71cd55
+			node->flavor == CIL_IN ||
71cd55
+			node->flavor == CIL_BLOCK ||
71cd55
+			node->flavor == CIL_BLOCKABSTRACT ||
71cd55
 		    node->flavor == CIL_MACRO) {
71cd55
-			/* tuanbles and macros are not allowed in optionals*/
71cd55
 			cil_tree_log(node, CIL_ERR, "%s statement is not allowed in optionals", cil_node_to_string(node));
71cd55
 			rc = SEPOL_ERR;
71cd55
 			goto exit;
71cd55
-- 
71cd55
2.32.0
71cd55