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

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