From 7454dd70b19516a0320b4965e52a7a643fbd18aa Mon Sep 17 00:00:00 2001 From: steven_q Date: Fri, 11 Mar 2022 20:16:32 +0800 Subject: [PATCH 01/10] CVE-2021-36085 Signed-off-by: steven_q Change-Id: I15714d91906d943f42faf0c61ecb78cbc678014b --- libsepol/cil/src/cil_reset_ast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsepol/cil/src/cil_reset_ast.c b/libsepol/cil/src/cil_reset_ast.c index 3da1b9a6..47138dc4 100644 --- a/libsepol/cil/src/cil_reset_ast.c +++ b/libsepol/cil/src/cil_reset_ast.c @@ -36,7 +36,7 @@ static void cil_reset_class(struct cil_class *class) static void cil_reset_perm(struct cil_perm *perm) { - cil_reset_classperms_list(perm->classperms); + cil_list_destroy(&perm->classperms, CIL_FALSE); } static inline void cil_reset_classperms(struct cil_classperms *cp) -- Gitee From 30232c4eae6607aa6d65c2fdcf1c6beabd734b98 Mon Sep 17 00:00:00 2001 From: steven_q Date: Fri, 11 Mar 2022 20:46:51 +0800 Subject: [PATCH 02/10] CVE-2021-36084 Signed-off-by: steven_q Change-Id: I289eeae464e543cad3fb81e5ceaf568147ab344c --- libsepol/cil/src/cil_reset_ast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsepol/cil/src/cil_reset_ast.c b/libsepol/cil/src/cil_reset_ast.c index 47138dc4..89f91e56 100644 --- a/libsepol/cil/src/cil_reset_ast.c +++ b/libsepol/cil/src/cil_reset_ast.c @@ -54,7 +54,7 @@ static void cil_reset_classpermission(struct cil_classpermission *cp) return; } - cil_reset_classperms_list(cp->classperms); + cil_list_destroy(&cp->classperms, CIL_FALSE); } static void cil_reset_classperms_set(struct cil_classperms_set *cp_set) -- Gitee From 1780fa7505a8ac14fbc62cca7fae65bd5fa4275e Mon Sep 17 00:00:00 2001 From: steven_q Date: Fri, 11 Mar 2022 20:48:48 +0800 Subject: [PATCH 03/10] CVE-2021-36087:Reorder checks for invalid rules when building AST Signed-off-by: steven_q Change-Id: Ie60656959afccbc9b9b3df466ba173fa91557d30 --- libsepol/cil/src/cil_build_ast.c | 100 +++++++++++++++---------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c index 4e53f06a..1c530bbc 100644 --- a/libsepol/cil/src/cil_build_ast.c +++ b/libsepol/cil/src/cil_build_ast.c @@ -49,10 +49,10 @@ struct cil_args_build { struct cil_tree_node *ast; struct cil_db *db; - struct cil_tree_node *macro; - struct cil_tree_node *boolif; struct cil_tree_node *tunif; struct cil_tree_node *in; + struct cil_tree_node *macro; + struct cil_tree_node *boolif; }; int cil_fill_list(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **list) @@ -6097,10 +6097,10 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f struct cil_tree_node *ast_current = NULL; struct cil_db *db = NULL; struct cil_tree_node *ast_node = NULL; - struct cil_tree_node *macro = NULL; - struct cil_tree_node *boolif = NULL; struct cil_tree_node *tunif = NULL; struct cil_tree_node *in = NULL; + struct cil_tree_node *macro = NULL; + struct cil_tree_node *boolif = NULL; int rc = SEPOL_ERR; if (parse_current == NULL || finished == NULL || extra_args == NULL) { @@ -6110,10 +6110,10 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f args = extra_args; ast_current = args->ast; db = args->db; - macro = args->macro; - boolif = args->boolif; tunif = args->tunif; in = args->in; + macro = args->macro; + boolif = args->boolif; if (parse_current->parent->cl_head != parse_current) { /* ignore anything that isn't following a parenthesis */ @@ -6130,13 +6130,31 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f goto exit; } + if (tunif != NULL) { + if (parse_current->data == CIL_KEY_TUNABLE) { + rc = SEPOL_ERR; + cil_tree_log(parse_current, CIL_ERR, "Found tunable"); + cil_log(CIL_ERR, "Tunables cannot be defined within tunableif statement\n"); + goto exit; + } + } + + if (in != NULL) { + if (parse_current->data == CIL_KEY_IN) { + rc = SEPOL_ERR; + cil_tree_log(parse_current, CIL_ERR, "Found in-statement"); + cil_log(CIL_ERR, "in-statements cannot be defined within in-statements\n"); + goto exit; + } + } + if (macro != NULL) { - if (parse_current->data == CIL_KEY_MACRO || - parse_current->data == CIL_KEY_TUNABLE || + if (parse_current->data == CIL_KEY_TUNABLE || parse_current->data == CIL_KEY_IN || parse_current->data == CIL_KEY_BLOCK || parse_current->data == CIL_KEY_BLOCKINHERIT || - parse_current->data == CIL_KEY_BLOCKABSTRACT) { + 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 macros", (char *)parse_current->data); goto exit; @@ -6144,15 +6162,15 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f } if (boolif != NULL) { - if (parse_current->data != CIL_KEY_CONDTRUE && + if (parse_current->data != CIL_KEY_TUNABLEIF && + parse_current->data != CIL_KEY_CALL && + parse_current->data != CIL_KEY_CONDTRUE && parse_current->data != CIL_KEY_CONDFALSE && - parse_current->data != CIL_KEY_AUDITALLOW && - parse_current->data != CIL_KEY_TUNABLEIF && parse_current->data != CIL_KEY_ALLOW && parse_current->data != CIL_KEY_DONTAUDIT && + parse_current->data != CIL_KEY_AUDITALLOW && parse_current->data != CIL_KEY_TYPETRANSITION && - parse_current->data != CIL_KEY_TYPECHANGE && - parse_current->data != CIL_KEY_CALL) { + parse_current->data != CIL_KEY_TYPECHANGE) { rc = SEPOL_ERR; cil_tree_log(parse_current, CIL_ERR, "Found %s", (char*)parse_current->data); if (((struct cil_booleanif*)boolif->data)->preserved_tunable) { @@ -6166,24 +6184,6 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f } } - if (tunif != NULL) { - if (parse_current->data == CIL_KEY_TUNABLE) { - rc = SEPOL_ERR; - cil_tree_log(parse_current, CIL_ERR, "Found tunable"); - cil_log(CIL_ERR, "Tunables cannot be defined within tunableif statement\n"); - goto exit; - } - } - - if (in != NULL) { - if (parse_current->data == CIL_KEY_IN) { - rc = SEPOL_ERR; - cil_tree_log(parse_current, CIL_ERR, "Found in-statement"); - cil_log(CIL_ERR, "in-statements cannot be defined within in-statements\n"); - goto exit; - } - } - cil_tree_node_init(&ast_node); ast_node->parent = ast_current; @@ -6469,14 +6469,6 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f if (rc == SEPOL_OK) { if (ast_current->cl_head == NULL) { - if (ast_current->flavor == CIL_MACRO) { - args->macro = ast_current; - } - - if (ast_current->flavor == CIL_BOOLEANIF) { - args->boolif = ast_current; - } - if (ast_current->flavor == CIL_TUNABLEIF) { args->tunif = ast_current; } @@ -6485,6 +6477,14 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f args->in = ast_current; } + if (ast_current->flavor == CIL_MACRO) { + args->macro = ast_current; + } + + if (ast_current->flavor == CIL_BOOLEANIF) { + args->boolif = ast_current; + } + ast_current->cl_head = ast_node; } else { ast_current->cl_tail->next = ast_node; @@ -6520,14 +6520,6 @@ int __cil_build_ast_last_child_helper(struct cil_tree_node *parse_current, void args->ast = ast->parent; - if (ast->flavor == CIL_MACRO) { - args->macro = NULL; - } - - if (ast->flavor == CIL_BOOLEANIF) { - args->boolif = NULL; - } - if (ast->flavor == CIL_TUNABLEIF) { args->tunif = NULL; } @@ -6536,6 +6528,14 @@ int __cil_build_ast_last_child_helper(struct cil_tree_node *parse_current, void args->in = NULL; } + if (ast->flavor == CIL_MACRO) { + args->macro = NULL; + } + + if (ast->flavor == CIL_BOOLEANIF) { + args->boolif = NULL; + } + // At this point we no longer have any need for parse_current or any of its // siblings; they have all been converted to the appropriate AST node. The // full parse tree will get deleted elsewhere, but in an attempt to @@ -6560,10 +6560,10 @@ int cil_build_ast(struct cil_db *db, struct cil_tree_node *parse_tree, struct ci extra_args.ast = ast; extra_args.db = db; - extra_args.macro = NULL; - extra_args.boolif = NULL; extra_args.tunif = NULL; extra_args.in = NULL; + extra_args.macro = NULL; + extra_args.boolif = NULL; rc = cil_tree_walk(parse_tree, __cil_build_ast_node_helper, NULL, __cil_build_ast_last_child_helper, &extra_args); if (rc != SEPOL_OK) { -- Gitee From 12b8656a1d1aa921149ac935ac792fe5e722a7ca Mon Sep 17 00:00:00 2001 From: steven_q Date: Fri, 11 Mar 2022 20:49:53 +0800 Subject: [PATCH 04/10] CVE-2021-36087:Cleanup build AST helper functions Signed-off-by: steven_q Change-Id: I56ae93a30edcde30ed6ef10679e90167a53a4027 --- libsepol/cil/src/cil_build_ast.c | 44 ++++++++------------------------ 1 file changed, 10 insertions(+), 34 deletions(-) diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c index 1c530bbc..dd57ad82 100644 --- a/libsepol/cil/src/cil_build_ast.c +++ b/libsepol/cil/src/cil_build_ast.c @@ -6093,28 +6093,16 @@ void cil_destroy_src_info(struct cil_src_info *info) int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *finished, void *extra_args) { - struct cil_args_build *args = NULL; - struct cil_tree_node *ast_current = NULL; - struct cil_db *db = NULL; + struct cil_args_build *args = extra_args; + struct cil_db *db = args->db; + struct cil_tree_node *ast_current = args->ast; + 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 *boolif = args->boolif; struct cil_tree_node *ast_node = NULL; - struct cil_tree_node *tunif = NULL; - struct cil_tree_node *in = NULL; - struct cil_tree_node *macro = NULL; - struct cil_tree_node *boolif = NULL; int rc = SEPOL_ERR; - if (parse_current == NULL || finished == NULL || extra_args == NULL) { - goto exit; - } - - args = extra_args; - ast_current = args->ast; - db = args->db; - tunif = args->tunif; - in = args->in; - macro = args->macro; - boolif = args->boolif; - if (parse_current->parent->cl_head != parse_current) { /* ignore anything that isn't following a parenthesis */ rc = SEPOL_OK; @@ -6502,20 +6490,11 @@ exit: int __cil_build_ast_last_child_helper(struct cil_tree_node *parse_current, void *extra_args) { - int rc = SEPOL_ERR; - struct cil_tree_node *ast = NULL; - struct cil_args_build *args = NULL; - - if (extra_args == NULL) { - goto exit; - } - - args = extra_args; - ast = args->ast; + struct cil_args_build *args = extra_args; + struct cil_tree_node *ast = args->ast; if (ast->flavor == CIL_ROOT) { - rc = SEPOL_OK; - goto exit; + return SEPOL_OK; } args->ast = ast->parent; @@ -6544,9 +6523,6 @@ int __cil_build_ast_last_child_helper(struct cil_tree_node *parse_current, void cil_tree_children_destroy(parse_current->parent); return SEPOL_OK; - -exit: - return rc; } int cil_build_ast(struct cil_db *db, struct cil_tree_node *parse_tree, struct cil_tree_node *ast) -- Gitee From 82b24261595a22480640fb0ad892d544e0a3b024 Mon Sep 17 00:00:00 2001 From: steven_q Date: Fri, 11 Mar 2022 20:50:42 +0800 Subject: [PATCH 05/10] CVE-2021-36087:Create new first child helper function for building AST Signed-off-by: steven_q Change-Id: If0934f0977d31dd3df0df50a8a55a25bf251bd59 --- libsepol/cil/src/cil_build_ast.c | 42 +++++++++++++++++++------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c index dd57ad82..c0783ba6 100644 --- a/libsepol/cil/src/cil_build_ast.c +++ b/libsepol/cil/src/cil_build_ast.c @@ -6457,22 +6457,6 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f if (rc == SEPOL_OK) { if (ast_current->cl_head == NULL) { - if (ast_current->flavor == CIL_TUNABLEIF) { - args->tunif = ast_current; - } - - if (ast_current->flavor == CIL_IN) { - args->in = ast_current; - } - - if (ast_current->flavor == CIL_MACRO) { - args->macro = ast_current; - } - - if (ast_current->flavor == CIL_BOOLEANIF) { - args->boolif = ast_current; - } - ast_current->cl_head = ast_node; } else { ast_current->cl_tail->next = ast_node; @@ -6488,6 +6472,30 @@ exit: return rc; } +int __cil_build_ast_first_child_helper(__attribute__((unused)) struct cil_tree_node *parse_current, void *extra_args) +{ + struct cil_args_build *args = extra_args; + struct cil_tree_node *ast = args->ast; + + if (ast->flavor == CIL_TUNABLEIF) { + args->tunif = ast; + } + + if (ast->flavor == CIL_IN) { + args->in = ast; + } + + if (ast->flavor == CIL_MACRO) { + args->macro = ast; + } + + if (ast->flavor == CIL_BOOLEANIF) { + args->boolif = ast; + } + + return SEPOL_OK; +} + int __cil_build_ast_last_child_helper(struct cil_tree_node *parse_current, void *extra_args) { struct cil_args_build *args = extra_args; @@ -6541,7 +6549,7 @@ int cil_build_ast(struct cil_db *db, struct cil_tree_node *parse_tree, struct ci extra_args.macro = NULL; extra_args.boolif = NULL; - rc = cil_tree_walk(parse_tree, __cil_build_ast_node_helper, NULL, __cil_build_ast_last_child_helper, &extra_args); + 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); if (rc != SEPOL_OK) { goto exit; } -- Gitee From 1f57b0d47b79a09e2f7cb2681915ca2ca092637a Mon Sep 17 00:00:00 2001 From: steven_q Date: Fri, 11 Mar 2022 20:52:37 +0800 Subject: [PATCH 06/10] CVE-2021-36087:Use AST to track blocks and optionals when resolving Signed-off-by: steven_q Change-Id: Iff089706075e33a5d8e7bc1c51ff93b77c2daea0 --- libsepol/cil/src/cil_resolve_ast.c | 107 +++++++++-------------------- 1 file changed, 32 insertions(+), 75 deletions(-) diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c index 0e078561..64272adf 100644 --- a/libsepol/cil/src/cil_resolve_ast.c +++ b/libsepol/cil/src/cil_resolve_ast.c @@ -52,10 +52,10 @@ struct cil_args_resolve { enum cil_pass pass; uint32_t *changed; struct cil_list *disabled_optionals; - struct cil_tree_node *optstack; + struct cil_tree_node *optional; struct cil_tree_node *boolif; struct cil_tree_node *macro; - struct cil_tree_node *blockstack; + struct cil_tree_node *block; struct cil_list *sidorder_lists; struct cil_list *classorder_lists; struct cil_list *unordered_classorder_lists; @@ -3778,16 +3778,16 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished int rc = SEPOL_ERR; struct cil_args_resolve *args = extra_args; enum cil_pass pass = args->pass; - struct cil_tree_node *optstack = args->optstack; + struct cil_tree_node *optional = args->optional; struct cil_tree_node *boolif = args->boolif; - struct cil_tree_node *blockstack = args->blockstack; + struct cil_tree_node *block = args->block; struct cil_tree_node *macro = args->macro; if (node == NULL) { goto exit; } - if (optstack != NULL) { + if (optional != NULL) { if (node->flavor == CIL_TUNABLE || 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)); @@ -3796,7 +3796,7 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished } } - if (blockstack != NULL) { + if (block != NULL) { if (node->flavor == CIL_CAT || node->flavor == CIL_SENS) { cil_tree_log(node, CIL_ERR, "%s statement is not allowed in blocks", cil_node_to_string(node)); rc = SEPOL_ERR; @@ -3850,11 +3850,11 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished if (rc == SEPOL_ENOENT) { enum cil_log_level lvl = CIL_ERR; - if (optstack != NULL) { + if (optional != NULL) { lvl = CIL_INFO; - struct cil_optional *opt = (struct cil_optional *)optstack->data; - struct cil_tree_node *opt_node = opt->datum.nodes->head->data; + struct cil_optional *opt = (struct cil_optional *)optional->data; + struct cil_tree_node *opt_node = NODE(opt);; /* disable an optional if something failed to resolve */ opt->enabled = CIL_FALSE; cil_tree_log(node, lvl, "Failed to resolve %s statement", cil_node_to_string(node)); @@ -3877,39 +3877,18 @@ 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 *optstack = NULL; struct cil_tree_node *parent = NULL; - struct cil_tree_node *blockstack = NULL; - struct cil_tree_node *new = NULL; if (current == NULL || extra_args == NULL) { goto exit; } - optstack = args->optstack; parent = current->parent; - blockstack = args->blockstack; - 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_OPTIONAL) { - if (optstack != NULL) { - optstack->parent = new; - new->cl_head = optstack; - } - args->optstack = new; - } else if (parent->flavor == CIL_BLOCK) { - if (blockstack != NULL) { - blockstack->parent = new; - new->cl_head = blockstack; - } - args->blockstack = new; - } + if (parent->flavor == CIL_BLOCK) { + args->block = parent; + } else if (parent->flavor == CIL_OPTIONAL) { + args->optional = parent; } else if (parent->flavor == CIL_BOOLEANIF) { args->boolif = parent; } else if (parent->flavor == CIL_MACRO) { @@ -3928,7 +3907,6 @@ int __cil_resolve_ast_last_child_helper(struct cil_tree_node *current, void *ext int rc = SEPOL_ERR; struct cil_args_resolve *args = extra_args; struct cil_tree_node *parent = NULL; - struct cil_tree_node *blockstack = NULL; if (current == NULL || extra_args == NULL) { goto exit; @@ -3939,30 +3917,31 @@ int __cil_resolve_ast_last_child_helper(struct cil_tree_node *current, void *ext if (parent->flavor == CIL_MACRO) { args->macro = NULL; } else if (parent->flavor == CIL_OPTIONAL) { - struct cil_tree_node *optstack; - + struct cil_tree_node *n = parent->parent; if (((struct cil_optional *)parent->data)->enabled == CIL_FALSE) { *(args->changed) = CIL_TRUE; cil_list_append(args->disabled_optionals, CIL_NODE, parent); } - - /* pop off the stack */ - optstack = args->optstack; - args->optstack = optstack->cl_head; - if (optstack->cl_head) { - optstack->cl_head->parent = NULL; + args->optional = NULL; + while (n && n->flavor != CIL_ROOT) { + if (n->flavor == CIL_OPTIONAL) { + args->optional = n; + break; + } + n = n->parent; } - free(optstack); } else if (parent->flavor == CIL_BOOLEANIF) { args->boolif = NULL; } else if (parent->flavor == CIL_BLOCK) { - /* pop off the stack */ - blockstack = args->blockstack; - args->blockstack = blockstack->cl_head; - if (blockstack->cl_head) { - blockstack->cl_head->parent = NULL; + struct cil_tree_node *n = parent->parent; + args->block = NULL; + while (n && n->flavor != CIL_ROOT) { + if (n->flavor == CIL_BLOCK) { + args->block = n; + break; + } + n = n->parent; } - free(blockstack); } return SEPOL_OK; @@ -3971,16 +3950,6 @@ exit: return rc; } -static void cil_destroy_tree_node_stack(struct cil_tree_node *curr) -{ - struct cil_tree_node *next; - while (curr != NULL) { - next = curr->cl_head; - free(curr); - curr = next; - } -} - int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) { int rc = SEPOL_ERR; @@ -3995,7 +3964,8 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) extra_args.db = db; extra_args.pass = pass; extra_args.changed = &changed; - extra_args.optstack = NULL; + extra_args.block = NULL; + extra_args.optional = NULL; extra_args.boolif= NULL; extra_args.macro = NULL; extra_args.sidorder_lists = NULL; @@ -4004,7 +3974,6 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) extra_args.catorder_lists = NULL; extra_args.sensitivityorder_lists = NULL; extra_args.in_list = NULL; - extra_args.blockstack = NULL; cil_list_init(&extra_args.disabled_optionals, CIL_NODE); cil_list_init(&extra_args.sidorder_lists, CIL_LIST_ITEM); @@ -4108,17 +4077,7 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) } cil_list_destroy(&extra_args.disabled_optionals, CIL_FALSE); cil_list_init(&extra_args.disabled_optionals, CIL_NODE); - } - - /* reset the arguments */ - changed = 0; - while (extra_args.optstack != NULL) { - cil_destroy_tree_node_stack(extra_args.optstack); - extra_args.optstack = NULL; - } - while (extra_args.blockstack!= NULL) { - cil_destroy_tree_node_stack(extra_args.blockstack); - extra_args.blockstack = NULL; + changed = 0; } } @@ -4129,8 +4088,6 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) rc = SEPOL_OK; exit: - cil_destroy_tree_node_stack(extra_args.optstack); - cil_destroy_tree_node_stack(extra_args.blockstack); __cil_ordered_lists_destroy(&extra_args.sidorder_lists); __cil_ordered_lists_destroy(&extra_args.classorder_lists); __cil_ordered_lists_destroy(&extra_args.catorder_lists); -- Gitee From 7aea19e2eb5b4ca572eb330d51e027aeaac9b336 Mon Sep 17 00:00:00 2001 From: steven_q Date: Fri, 11 Mar 2022 20:53:44 +0800 Subject: [PATCH 07/10] CVE-2021-36087:Reorder checks for invalid rules when resolving AST Signed-off-by: steven_q Change-Id: I18856939891ca92171e95796a5d118a31c03a27a --- libsepol/cil/src/cil_resolve_ast.c | 76 +++++++++++++++--------------- 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c index 64272adf..0dac3d15 100644 --- a/libsepol/cil/src/cil_resolve_ast.c +++ b/libsepol/cil/src/cil_resolve_ast.c @@ -52,10 +52,10 @@ struct cil_args_resolve { enum cil_pass pass; uint32_t *changed; struct cil_list *disabled_optionals; + struct cil_tree_node *block; + struct cil_tree_node *macro; struct cil_tree_node *optional; struct cil_tree_node *boolif; - struct cil_tree_node *macro; - struct cil_tree_node *block; struct cil_list *sidorder_lists; struct cil_list *classorder_lists; struct cil_list *unordered_classorder_lists; @@ -3778,50 +3778,52 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished int rc = SEPOL_ERR; struct cil_args_resolve *args = extra_args; enum cil_pass pass = args->pass; - struct cil_tree_node *optional = args->optional; - struct cil_tree_node *boolif = args->boolif; struct cil_tree_node *block = args->block; struct cil_tree_node *macro = args->macro; + struct cil_tree_node *optional = args->optional; + struct cil_tree_node *boolif = args->boolif; if (node == NULL) { goto exit; } - if (optional != NULL) { - if (node->flavor == CIL_TUNABLE || 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)); + if (block != NULL) { + if (node->flavor == CIL_CAT || + node->flavor == CIL_SENS) { + cil_tree_log(node, CIL_ERR, "%s statement is not allowed in blocks", cil_node_to_string(node)); rc = SEPOL_ERR; goto exit; } } - if (block != NULL) { - if (node->flavor == CIL_CAT || node->flavor == CIL_SENS) { - cil_tree_log(node, CIL_ERR, "%s statement is not allowed in blocks", cil_node_to_string(node)); + if (macro != NULL) { + if (node->flavor == CIL_BLOCK || + node->flavor == CIL_BLOCKINHERIT || + node->flavor == CIL_BLOCKABSTRACT || + node->flavor == CIL_MACRO) { + cil_tree_log(node, CIL_ERR, "%s statement is not allowed in macros", cil_node_to_string(node)); rc = SEPOL_ERR; goto exit; } } - if (macro != NULL) { - if (node->flavor == CIL_BLOCKINHERIT || - node->flavor == CIL_BLOCK || - node->flavor == CIL_BLOCKABSTRACT || - node->flavor == CIL_MACRO) { - cil_tree_log(node, CIL_ERR, "%s statement is not allowed in macros", cil_node_to_string(node)); + if (optional != NULL) { + if (node->flavor == CIL_TUNABLE || + 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; } } if (boolif != NULL) { - if (!(node->flavor == CIL_CONDBLOCK || - node->flavor == CIL_AVRULE || - node->flavor == CIL_TYPE_RULE || - node->flavor == CIL_CALL || - node->flavor == CIL_TUNABLEIF || - node->flavor == CIL_NAMETYPETRANSITION)) { + if (!(node->flavor == CIL_TUNABLEIF || + node->flavor == CIL_CALL || + node->flavor == CIL_CONDBLOCK || + node->flavor == CIL_AVRULE || + node->flavor == CIL_TYPE_RULE || + node->flavor == CIL_NAMETYPETRANSITION)) { if (((struct cil_booleanif*)boolif->data)->preserved_tunable) { cil_tree_log(node, CIL_ERR, "%s statement is not allowed in booleanifs (tunableif treated as a booleanif)", cil_node_to_string(node)); } else { @@ -3887,12 +3889,12 @@ int __cil_resolve_ast_first_child_helper(struct cil_tree_node *current, void *ex if (parent->flavor == CIL_BLOCK) { args->block = parent; + } else if (parent->flavor == CIL_MACRO) { + args->macro = parent; } else if (parent->flavor == CIL_OPTIONAL) { args->optional = parent; } else if (parent->flavor == CIL_BOOLEANIF) { args->boolif = parent; - } else if (parent->flavor == CIL_MACRO) { - args->macro = parent; } return SEPOL_OK; @@ -3914,7 +3916,17 @@ int __cil_resolve_ast_last_child_helper(struct cil_tree_node *current, void *ext parent = current->parent; - if (parent->flavor == CIL_MACRO) { + if (parent->flavor == CIL_BLOCK) { + struct cil_tree_node *n = parent->parent; + args->block = NULL; + while (n && n->flavor != CIL_ROOT) { + if (n->flavor == CIL_BLOCK) { + args->block = n; + break; + } + n = n->parent; + } + } else if (parent->flavor == CIL_MACRO) { args->macro = NULL; } else if (parent->flavor == CIL_OPTIONAL) { struct cil_tree_node *n = parent->parent; @@ -3932,16 +3944,6 @@ int __cil_resolve_ast_last_child_helper(struct cil_tree_node *current, void *ext } } else if (parent->flavor == CIL_BOOLEANIF) { args->boolif = NULL; - } else if (parent->flavor == CIL_BLOCK) { - struct cil_tree_node *n = parent->parent; - args->block = NULL; - while (n && n->flavor != CIL_ROOT) { - if (n->flavor == CIL_BLOCK) { - args->block = n; - break; - } - n = n->parent; - } } return SEPOL_OK; @@ -3965,9 +3967,9 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) extra_args.pass = pass; extra_args.changed = &changed; extra_args.block = NULL; + extra_args.macro = NULL; extra_args.optional = NULL; extra_args.boolif= NULL; - extra_args.macro = NULL; extra_args.sidorder_lists = NULL; extra_args.classorder_lists = NULL; extra_args.unordered_classorder_lists = NULL; -- Gitee From df317107f578b0a484dab2f6fc27ba9a74989ab5 Mon Sep 17 00:00:00 2001 From: steven_q Date: Fri, 11 Mar 2022 20:54:38 +0800 Subject: [PATCH 08/10] CVE-2021-36087:Sync checks for invalid rules in booleanifs Signed-off-by: steven_q Change-Id: I750df53616a29f70f84ed04605a8aae9cb6bf310 --- libsepol/cil/src/cil_build_ast.c | 3 ++- libsepol/cil/src/cil_resolve_ast.c | 23 +++++++++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c index c0783ba6..457d3ee7 100644 --- a/libsepol/cil/src/cil_build_ast.c +++ b/libsepol/cil/src/cil_build_ast.c @@ -6158,7 +6158,8 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f parse_current->data != CIL_KEY_DONTAUDIT && parse_current->data != CIL_KEY_AUDITALLOW && parse_current->data != CIL_KEY_TYPETRANSITION && - parse_current->data != CIL_KEY_TYPECHANGE) { + parse_current->data != CIL_KEY_TYPECHANGE && + parse_current->data != CIL_KEY_TYPEMEMBER) { rc = SEPOL_ERR; cil_tree_log(parse_current, CIL_ERR, "Found %s", (char*)parse_current->data); if (((struct cil_booleanif*)boolif->data)->preserved_tunable) { diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c index 0dac3d15..729f9cc7 100644 --- a/libsepol/cil/src/cil_resolve_ast.c +++ b/libsepol/cil/src/cil_resolve_ast.c @@ -3775,7 +3775,7 @@ exit: int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args) { - int rc = SEPOL_ERR; + int rc = SEPOL_OK; struct cil_args_resolve *args = extra_args; enum cil_pass pass = args->pass; struct cil_tree_node *block = args->block; @@ -3818,18 +3818,25 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished } if (boolif != NULL) { - if (!(node->flavor == CIL_TUNABLEIF || - node->flavor == CIL_CALL || - node->flavor == CIL_CONDBLOCK || - node->flavor == CIL_AVRULE || - node->flavor == CIL_TYPE_RULE || - node->flavor == CIL_NAMETYPETRANSITION)) { + if (node->flavor != CIL_TUNABLEIF && + node->flavor != CIL_CALL && + node->flavor != CIL_CONDBLOCK && + node->flavor != CIL_AVRULE && + node->flavor != CIL_TYPE_RULE && + node->flavor != CIL_NAMETYPETRANSITION) { + rc = SEPOL_ERR; + } else if (node->flavor == CIL_AVRULE) { + struct cil_avrule *rule = node->data; + if (rule->rule_kind == CIL_AVRULE_NEVERALLOW) { + rc = SEPOL_ERR; + } + } + if (rc == SEPOL_ERR) { if (((struct cil_booleanif*)boolif->data)->preserved_tunable) { cil_tree_log(node, CIL_ERR, "%s statement is not allowed in booleanifs (tunableif treated as a booleanif)", cil_node_to_string(node)); } else { cil_tree_log(node, CIL_ERR, "%s statement is not allowed in booleanifs", cil_node_to_string(node)); } - rc = SEPOL_ERR; goto exit; } } -- Gitee From d629a8d83f64514ea6fb24f379b274f2a178c507 Mon Sep 17 00:00:00 2001 From: steven_q Date: Fri, 11 Mar 2022 20:55:51 +0800 Subject: [PATCH 09/10] CVE-2021-36087:Check for statements not allowed in optional blocks Signed-off-by: steven_q Change-Id: I1e7b0532254b0cb9205cd034cd79278e9352ad77 --- libsepol/cil/src/cil_build_ast.c | 32 ++++++++++++++++++++++++++++++ libsepol/cil/src/cil_resolve_ast.c | 4 +++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c index 457d3ee7..1fef25d4 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; }; @@ -6099,6 +6100,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; @@ -6149,6 +6151,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 && @@ -6490,6 +6504,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; } @@ -6520,6 +6538,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; } @@ -6548,6 +6579,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 729f9cc7..b5edfc04 100644 --- a/libsepol/cil/src/cil_resolve_ast.c +++ b/libsepol/cil/src/cil_resolve_ast.c @@ -3809,8 +3809,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; -- Gitee From 1fede1402ff61b1c3cdb15b901f718e0f685b858 Mon Sep 17 00:00:00 2001 From: steven_q Date: Fri, 11 Mar 2022 20:58:15 +0800 Subject: [PATCH 10/10] CVE-2021-36087:Update the CIL documentation for various blocks Signed-off-by: steven_q Change-Id: Ic4dda59a750ede81a0897225b32fb4844de3c21e --- secilc/docs/cil_call_macro_statements.md | 2 ++ secilc/docs/cil_conditional_statements.md | 6 +++++ secilc/docs/cil_container_statements.md | 28 +++++++++++++++-------- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/secilc/docs/cil_call_macro_statements.md b/secilc/docs/cil_call_macro_statements.md index 332eb28f..352a9fb0 100644 --- a/secilc/docs/cil_call_macro_statements.md +++ b/secilc/docs/cil_call_macro_statements.md @@ -58,6 +58,8 @@ When resolving macros the following places are checked in this order: - Items defined in the global namespace +[`tunable`](cil_conditional_statements.md#tunable), [`in`](cil_container_statements.md#in), [`block`](cil_container_statements.md#block), [`blockinherit`](cil_container_statements.md#blockinherit), [`blockabstract`](cil_container_statements.md#blockabstract), and other [`macro`](cil_call_macro_statements.md#macro) statements are not allowed in [`macro`](cil_call_macro_statements.md#macro) blocks. + **Statement definition:** ```secil diff --git a/secilc/docs/cil_conditional_statements.md b/secilc/docs/cil_conditional_statements.md index a55a9b6c..d0c8e2ce 100644 --- a/secilc/docs/cil_conditional_statements.md +++ b/secilc/docs/cil_conditional_statements.md @@ -6,6 +6,8 @@ boolean Declares a run time boolean as true or false in the current namespace. The [`booleanif`](cil_conditional_statements.md#booleanif) statement contains the CIL code that will be in the binary policy file. +[`boolean`](cil_conditional_statements.md#boolean) are not allowed in [`booleanif`](cil_conditional_statements.md#booleanif) blocks. + **Statement definition:** ```secil @@ -126,6 +128,8 @@ Tunables are similar to booleans, however they are used to manage areas of CIL s Note that tunables can be treated as booleans by the CIL compiler command line parameter `-P` or `--preserve-tunables` flags. +Since [`tunableif`](cil_conditional_statements.md#tunableif) statements are resolved first, [`tunable`](cil_conditional_statements.md#tunable) statements are not allowed in [`in`](cil_container_statements.md#in), [`macro`](cil_call_macro_statements.md#macro), [`optional`](cil_container_statements.md#optional), and [`booleanif`](cil_conditional_statements.md#booleanif) blocks. To simplify processing, they are also not allowed in [`tunableif`](cil_conditional_statements.md#tunableif) blocks. + **Statement definition:** ```secil @@ -164,6 +168,8 @@ tunableif Compile time conditional statement that may or may not add CIL statements to be compiled. +If tunables are being treated as booleans (by using the CIL compiler command line parameter `-P` or `--preserve-tunables` flag), then only the statements allowed in a [`booleanif`](cil_conditional_statements.md#booleanif) block are allowed in a [`tunableif`](cil_conditional_statements.md#tunableif) block. Otherwise, [`tunable`](cil_conditional_statements.md#tunable) statements are not allowed in a [`tunableif`](cil_conditional_statements.md#tunableif) block. + **Statement definition:** ```secil diff --git a/secilc/docs/cil_container_statements.md b/secilc/docs/cil_container_statements.md index 76e9da51..7a7f67cc 100644 --- a/secilc/docs/cil_container_statements.md +++ b/secilc/docs/cil_container_statements.md @@ -4,7 +4,11 @@ Container Statements block ----- -Start a new namespace where any CIL statement is valid. +Start a new namespace. + +Not allowed in [`macro`](cil_call_macro_statements.md#macro) and [`optional`](cil_container_statements.md#optional) blocks. + +[`sensitivity`](cil_mls_labeling_statements.md#sensitivity) and [`category`](cil_mls_labeling_statements.md#category) statements are not allowed in [`block`](cil_container_statements.md#block) blocks. **Statement definition:** @@ -47,6 +51,8 @@ blockabstract Declares the namespace as a 'template' and does not generate code until instantiated by another namespace that has a [`blockinherit`](cil_container_statements.md#blockinherit) statement. +Not allowed in [`macro`](cil_call_macro_statements.md#macro) and [`optional`](cil_container_statements.md#optional) blocks. + **Statement definition:** ```secil @@ -97,6 +103,8 @@ blockinherit Used to add common policy rules to the current namespace via a template that has been defined with the [`blockabstract`](cil_container_statements.md#blockabstract) statement. All [`blockinherit`](cil_container_statements.md#blockinherit) statements are resolved first and then the contents of the block are copied. This is so that inherited blocks will not be inherited. For a concrete example, please see the examples section. +Not allowed in [`macro`](cil_call_macro_statements.md#macro) blocks. + **Statement definition:** ```secil @@ -199,15 +207,11 @@ This example contains a template `client_server` that is instantiated in two blo optional -------- -Declare an [`optional`](cil_container_statements.md#optional) namespace. All CIL statements in the optional block must be satisfied before instantiation in the binary policy. [`tunableif`](cil_conditional_statements.md#tunableif) and [`macro`](cil_call_macro_statements.md#macro) statements are not allowed in optional containers. The same restrictions apply to CIL policy statements within [`optional`](cil_container_statements.md#optional)'s that apply to kernel policy statements, i.e. only the policy statements shown in the following table are valid: +Declare an [`optional`](cil_container_statements.md#optional) namespace. All CIL statements in the optional block must be satisfied before instantiation in the binary policy. -| | | | | -| ------------------- | -------------- | ------------------ | ------------------ | -| [`allow`](cil_access_vector_rules.md#allow) | [`allowx`](cil_access_vector_rules.md#allowx) | [`auditallow`](cil_access_vector_rules.md#auditallow) | [`auditallowx`](cil_access_vector_rules.md#auditallowx) | -| [`booleanif`](cil_conditional_statements.md#booleanif) | [`dontaudit`](cil_access_vector_rules.md#dontaudit) | [`dontauditx`](cil_access_vector_rules.md#dontauditx) | [`typepermissive`](cil_type_statements.md#typepermissive) | -| [`rangetransition`](cil_mls_labeling_statements.md#rangetransition) | [`role`](cil_role_statements.md#role) | [`roleallow`](cil_role_statements.md#roleallow) | [`roleattribute`](cil_role_statements.md#roleattribute) | -| [`roletransition`](cil_role_statements.md#roletransition) | [`type`](cil_type_statements.md#type) | [`typealias`](cil_type_statements.md#typealias) | [`typeattribute`](cil_type_statements.md#typeattribute) | -| [`typechange`](cil_type_statements.md#typechange) | [`typemember`](cil_type_statements.md#typemember) | [`typetransition`](cil_type_statements.md#typetransition) | | +Not allowed in [`booleanif`](cil_conditional_statements.md#booleanif) blocks. + +[`tunable`](cil_conditional_statements.md#tunable), [`in`](cil_container_statements.md#in), [`block`](cil_container_statements.md#block), [`blockabstract`](cil_container_statements.md#blockabstract), and [`macro`](cil_call_macro_statements.md#macro) statements are not allowed in [`optional`](cil_container_statements.md#optional) blocks. **Statement definition:** @@ -266,7 +270,11 @@ This example will instantiate the optional block `ext_gateway.move_file` into po in -- -Allows the insertion of CIL statements into a named container ([`block`](cil_container_statements.md#block), [`optional`](cil_container_statements.md#optional) or [`macro`](cil_call_macro_statements.md#macro)). This statement is not allowed in [`booleanif`](cil_conditional_statements.md#booleanif) or [`tunableif`](cil_conditional_statements.md#tunableif) statements. This only works for containers that aren't inherited using [`blockinherit`](cil_conditional_statements.md#blockinherit). +Allows the insertion of CIL statements into a named container ([`block`](cil_container_statements.md#block), [`optional`](cil_container_statements.md#optional) or [`macro`](cil_call_macro_statements.md#macro)). + +Not allowed in [`macro`](cil_call_macro_statements.md#macro), [`booleanif`](cil_conditional_statements.md#booleanif), and other [`in`](cil_container_statements.md#in) blocks. + +[`tunable`](cil_conditional_statements.md#tunable) and [`in`](cil_container_statements.md#in) statements are not allowed in [`in`](cil_container_statements.md#in) blocks. **Statement definition:** -- Gitee