Repository: selinuxproject/selinux
Fuzzing engine: libfuzzer
Fuzz target: secilc-fuzzer
Sanitizer: address
Crash type: Heap-buffer-overflow READ 8

Sanitizer report:
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 3636622255
INFO: Loaded 1 modules   (18299 inline 8-bit counters): 18299 [0x55e350f92a28, 0x55e350f971a3), 
INFO: Loaded 1 PC tables (18299 PCs): 18299 [0x55e350f971a8,0x55e350fde958), 
/out/secilc-fuzzer: Running 1 inputs 1 time(s) each.
Running: /testcase/OSV-2021-585.poc
=================================================================
==7==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7fac81f787f0 at pc 0x55e350e773ff bp 0x7fff90ebdf30 sp 0x7fff90ebdf28
READ of size 8 at 0x7fac81f787f0 thread T0
SCARINESS: 33 (8-byte-read-heap-buffer-overflow-far-from-bounds)
    #0 0x55e350e773fe in ebitmap_match_any /src/selinux/libsepol/src/ebitmap.c:232:27
    #1 0x55e350e679a6 in check_assertion_avtab_match /src/selinux/libsepol/src/assertion.c:462:7
    #2 0x55e350e6c0e7 in avtab_map /src/selinux/libsepol/src/avtab.c:346:10
    #3 0x55e350e67585 in check_assertion /src/selinux/libsepol/src/assertion.c:513:7
    #4 0x55e350dd45cf in cil_check_neverallow /src/selinux/libsepol/src/../cil/src/cil_binary.c:4685:8
    #5 0x55e350dd45cf in cil_check_neverallows /src/selinux/libsepol/src/../cil/src/cil_binary.c:4739:8
    #6 0x55e350dd2d04 in cil_binary_create_allocated_pdb /src/selinux/libsepol/src/../cil/src/cil_binary.c:4998:8
    #7 0x55e350dd22a9 in cil_binary_create /src/selinux/libsepol/src/../cil/src/cil_binary.c:4325:7
    #8 0x55e350dade91 in cil_build_policydb /src/selinux/libsepol/src/../cil/src/cil.c:580:7
    #9 0x55e350d94982 in LLVMFuzzerTestOneInput /src/secilc-fuzzer.c:62:6
    #10 0x55e350c49330 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:614:13
    #11 0x55e350c345a5 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:327:6
    #12 0x55e350c3a03f in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:862:9
    #13 0x55e350c652e2 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
    #14 0x7fac8731b082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082) (BuildId: 0702430aef5fa3dda43986563e9ffcc47efbd75e)
    #15 0x55e350c2c78d in _start (/out/secilc-fuzzer+0xcc78d)

DEDUP_TOKEN: ebitmap_match_any--check_assertion_avtab_match--avtab_map
0x7fac81f787f0 is located 16 bytes before 1127072-byte region [0x7fac81f78800,0x7fac8208baa0)
allocated by thread T0 here:
    #0 0x55e350d550ff in malloc /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:68:3
    #1 0x55e350e14dc7 in cil_malloc /src/selinux/libsepol/src/../cil/src/cil_mem.c:40:14
    #2 0x55e350db974b in __cil_typeattr_bitmap_init /src/selinux/libsepol/src/../cil/src/cil_binary.c:598:23
    #3 0x55e350db9bc9 in cil_typeattribute_to_bitmap /src/selinux/libsepol/src/../cil/src/cil_binary.c:636:8
    #4 0x55e350dcfa8d in __cil_node_to_policydb /src/selinux/libsepol/src/../cil/src/cil_binary.c:3758:9
    #5 0x55e350e5668b in cil_tree_walk_core /src/selinux/libsepol/src/../cil/src/cil_tree.c:272:9
    #6 0x55e350e56871 in cil_tree_walk /src/selinux/libsepol/src/../cil/src/cil_tree.c:316:7
    #7 0x55e350e56871 in cil_tree_walk_core /src/selinux/libsepol/src/../cil/src/cil_tree.c:284:9
    #8 0x55e350e56871 in cil_tree_walk /src/selinux/libsepol/src/../cil/src/cil_tree.c:316:7
    #9 0x55e350e56871 in cil_tree_walk_core /src/selinux/libsepol/src/../cil/src/cil_tree.c:284:9
    #10 0x55e350e56871 in cil_tree_walk /src/selinux/libsepol/src/../cil/src/cil_tree.c:316:7
    #11 0x55e350e56871 in cil_tree_walk_core /src/selinux/libsepol/src/../cil/src/cil_tree.c:284:9
    #12 0x55e350e56871 in cil_tree_walk /src/selinux/libsepol/src/../cil/src/cil_tree.c:316:7
    #13 0x55e350e56871 in cil_tree_walk_core /src/selinux/libsepol/src/../cil/src/cil_tree.c:284:9
    #14 0x55e350e56a7e in cil_tree_walk /src/selinux/libsepol/src/../cil/src/cil_tree.c:316:7
    #15 0x55e350dd2a73 in cil_binary_create_allocated_pdb /src/selinux/libsepol/src/../cil/src/cil_binary.c:4950:8
    #16 0x55e350dd22a9 in cil_binary_create /src/selinux/libsepol/src/../cil/src/cil_binary.c:4325:7
    #17 0x55e350dade91 in cil_build_policydb /src/selinux/libsepol/src/../cil/src/cil.c:580:7
    #18 0x55e350d94982 in LLVMFuzzerTestOneInput /src/secilc-fuzzer.c:62:6
    #19 0x55e350c49330 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:614:13
    #20 0x55e350c345a5 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:327:6
    #21 0x55e350c3a03f in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:862:9
    #22 0x55e350c652e2 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
    #23 0x7fac8731b082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082) (BuildId: 0702430aef5fa3dda43986563e9ffcc47efbd75e)

DEDUP_TOKEN: __interceptor_malloc--cil_malloc--__cil_typeattr_bitmap_init
SUMMARY: AddressSanitizer: heap-buffer-overflow /src/selinux/libsepol/src/ebitmap.c:232:27 in ebitmap_match_any
Shadow bytes around the buggy address:
  0x7fac81f78500: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7fac81f78580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7fac81f78600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7fac81f78680: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7fac81f78700: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x7fac81f78780: fa fa fa fa fa fa fa fa fa fa fa fa fa fa[fa]fa
  0x7fac81f78800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7fac81f78880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7fac81f78900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7fac81f78980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7fac81f78a00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==7==ABORTING


Fix patch:
diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c
index 96c94497..88254858 100644
--- a/libsepol/cil/src/cil_build_ast.c
+++ b/libsepol/cil/src/cil_build_ast.c
@@ -52,6 +52,7 @@ struct cil_args_build {
 	struct cil_tree_node *tunif;
 	struct cil_tree_node *in;
 	struct cil_tree_node *macro;
+	struct cil_tree_node *optional;
 	struct cil_tree_node *boolif;
 };
 
@@ -6071,6 +6072,7 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f
 	struct cil_tree_node *tunif = args->tunif;
 	struct cil_tree_node *in = args->in;
 	struct cil_tree_node *macro = args->macro;
+	struct cil_tree_node *optional = args->optional;
 	struct cil_tree_node *boolif = args->boolif;
 	struct cil_tree_node *ast_node = NULL;
 	int rc = SEPOL_ERR;
@@ -6121,6 +6123,18 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f
 		}
 	}
 
+	if (optional != NULL) {
+		if (parse_current->data == CIL_KEY_TUNABLE ||
+			parse_current->data == CIL_KEY_IN ||
+			parse_current->data == CIL_KEY_BLOCK ||
+			parse_current->data == CIL_KEY_BLOCKABSTRACT ||
+			parse_current->data == CIL_KEY_MACRO) {
+			rc = SEPOL_ERR;
+			cil_tree_log(parse_current, CIL_ERR, "%s is not allowed in optionals", (char *)parse_current->data);
+			goto exit;
+		}
+	}
+
 	if (boolif != NULL) {
 		if (parse_current->data != CIL_KEY_TUNABLEIF &&
 			parse_current->data != CIL_KEY_CALL &&
@@ -6462,6 +6476,10 @@ int __cil_build_ast_first_child_helper(__attribute__((unused)) struct cil_tree_n
 		args->macro = ast;
 	}
 
+	if (ast->flavor == CIL_OPTIONAL) {
+		args->optional = ast;
+	}
+
 	if (ast->flavor == CIL_BOOLEANIF) {
 		args->boolif = ast;
 	}
@@ -6492,6 +6510,19 @@ int __cil_build_ast_last_child_helper(struct cil_tree_node *parse_current, void
 		args->macro = NULL;
 	}
 
+	if (ast->flavor == CIL_OPTIONAL) {
+		struct cil_tree_node *n = ast->parent;
+		args->optional = NULL;
+		/* Optionals can be nested */
+		while (n && n->flavor != CIL_ROOT) {
+			if (n->flavor == CIL_OPTIONAL) {
+				args->optional = n;
+				break;
+			}
+			n = n->parent;
+		}
+	}
+
 	if (ast->flavor == CIL_BOOLEANIF) {
 		args->boolif = NULL;
 	}
@@ -6520,6 +6551,7 @@ int cil_build_ast(struct cil_db *db, struct cil_tree_node *parse_tree, struct ci
 	extra_args.tunif = NULL;
 	extra_args.in = NULL;
 	extra_args.macro = NULL;
+	extra_args.optional = NULL;
 	extra_args.boolif = NULL;
 
 	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);
diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c
index 56295a04..efff0f2e 100644
--- a/libsepol/cil/src/cil_resolve_ast.c
+++ b/libsepol/cil/src/cil_resolve_ast.c
@@ -3808,8 +3808,10 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished
 
 	if (optional != NULL) {
 		if (node->flavor == CIL_TUNABLE ||
+			node->flavor == CIL_IN ||
+			node->flavor == CIL_BLOCK ||
+			node->flavor == CIL_BLOCKABSTRACT ||
 		    node->flavor == CIL_MACRO) {
-			/* tuanbles and macros are not allowed in optionals*/
 			cil_tree_log(node, CIL_ERR, "%s statement is not allowed in optionals", cil_node_to_string(node));
 			rc = SEPOL_ERR;
 			goto exit;