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

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