diff --git a/backport-CVE-2021-36084.patch b/backport-CVE-2021-36084.patch new file mode 100644 index 0000000000000000000000000000000000000000..c1e5e08cc74cc399dcfd7856bca36f7bff5ed6ee --- /dev/null +++ b/backport-CVE-2021-36084.patch @@ -0,0 +1,94 @@ +From f34d3d30c8325e4847a6b696fe7a3936a8a361f3 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 8 Apr 2021 13:32:01 -0400 +Subject: [PATCH] libsepol/cil: Destroy classperms list when resetting + classpermission + +Nicolas Iooss reports: + A few months ago, OSS-Fuzz found a crash in the CIL compiler, which + got reported as + https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28648 (the title + is misleading, or is caused by another issue that conflicts with the + one I report in this message). Here is a minimized CIL policy which + reproduces the issue: + + (class CLASS (PERM)) + (classorder (CLASS)) + (sid SID) + (sidorder (SID)) + (user USER) + (role ROLE) + (type TYPE) + (category CAT) + (categoryorder (CAT)) + (sensitivity SENS) + (sensitivityorder (SENS)) + (sensitivitycategory SENS (CAT)) + (allow TYPE self (CLASS (PERM))) + (roletype ROLE TYPE) + (userrole USER ROLE) + (userlevel USER (SENS)) + (userrange USER ((SENS)(SENS (CAT)))) + (sidcontext SID (USER ROLE TYPE ((SENS)(SENS)))) + + (classpermission CLAPERM) + + (optional OPT + (roletype nonexistingrole nonexistingtype) + (classpermissionset CLAPERM (CLASS (PERM))) + ) + + The CIL policy fuzzer (which mimics secilc built with clang Address + Sanitizer) reports: + + ==36541==ERROR: AddressSanitizer: heap-use-after-free on address + 0x603000004f98 at pc 0x56445134c842 bp 0x7ffe2a256590 sp + 0x7ffe2a256588 + READ of size 8 at 0x603000004f98 thread T0 + #0 0x56445134c841 in __cil_verify_classperms + /selinux/libsepol/src/../cil/src/cil_verify.c:1620:8 + #1 0x56445134a43e in __cil_verify_classpermission + /selinux/libsepol/src/../cil/src/cil_verify.c:1650:9 + #2 0x56445134a43e in __cil_pre_verify_helper + /selinux/libsepol/src/../cil/src/cil_verify.c:1715:8 + #3 0x5644513225ac in cil_tree_walk_core + /selinux/libsepol/src/../cil/src/cil_tree.c:272:9 + #4 0x564451322ab1 in cil_tree_walk + /selinux/libsepol/src/../cil/src/cil_tree.c:316:7 + #5 0x5644513226af in cil_tree_walk_core + /selinux/libsepol/src/../cil/src/cil_tree.c:284:9 + #6 0x564451322ab1 in cil_tree_walk + /selinux/libsepol/src/../cil/src/cil_tree.c:316:7 + #7 0x5644512b88fd in cil_pre_verify + /selinux/libsepol/src/../cil/src/cil_post.c:2510:7 + #8 0x5644512b88fd in cil_post_process + /selinux/libsepol/src/../cil/src/cil_post.c:2524:7 + #9 0x5644511856ff in cil_compile + /selinux/libsepol/src/../cil/src/cil.c:564:7 + +The classperms list of a classpermission rule is created and filled +in when classpermissionset rules are processed, so it doesn't own any +part of the list and shouldn't retain any of it when it is reset. + +Destroy the classperms list (without destroying the data in it) when +resetting a classpermission rule. + +Reported-by: Nicolas Iooss +Signed-off-by: James Carter +--- + 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 3da1b9a64..db70a535b 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) diff --git a/backport-CVE-2021-36085.patch b/backport-CVE-2021-36085.patch new file mode 100644 index 0000000000000000000000000000000000000000..fdb13e3f65c883790371c206605a9ef8513412f4 --- /dev/null +++ b/backport-CVE-2021-36085.patch @@ -0,0 +1,33 @@ +From 2d35fcc7e9e976a2346b1de20e54f8663e8a6cba Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 8 Apr 2021 13:32:04 -0400 +Subject: [PATCH] libsepol/cil: Destroy classperm list when resetting map perms + +Map perms share the same struct as regular perms, but only the +map perms use the classperms field. This field is a pointer to a +list of classperms that is created and added to when resolving +classmapping rules, so the map permission doesn't own any of the +data in the list and this list should be destroyed when the AST is +reset. + +When resetting a perm, destroy the classperms list without destroying +the data in the list. + +Signed-off-by: James Carter +--- + 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 db70a535b..89f91e568 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) diff --git a/backport-CVE-2021-36086.patch b/backport-CVE-2021-36086.patch new file mode 100644 index 0000000000000000000000000000000000000000..a6e98999472c7aee8125b53fd2bcde514da72f47 --- /dev/null +++ b/backport-CVE-2021-36086.patch @@ -0,0 +1,36 @@ +From c49a8ea09501ad66e799ea41b8154b6770fec2c8 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 8 Apr 2021 13:32:06 -0400 +Subject: [PATCH] libsepol/cil: cil_reset_classperms_set() should not reset + classpermission + +In struct cil_classperms_set, the set field is a pointer to a +struct cil_classpermission which is looked up in the symbol table. +Since the cil_classperms_set does not create the cil_classpermission, +it should not reset it. + +Set the set field to NULL instead of resetting the classpermission +that it points to. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_reset_ast.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_reset_ast.c b/libsepol/cil/src/cil_reset_ast.c +index 89f91e568..1d9ca704e 100644 +--- a/libsepol/cil/src/cil_reset_ast.c ++++ b/libsepol/cil/src/cil_reset_ast.c +@@ -59,7 +59,11 @@ static void cil_reset_classpermission(struct cil_classpermission *cp) + + static void cil_reset_classperms_set(struct cil_classperms_set *cp_set) + { +- cil_reset_classpermission(cp_set->set); ++ if (cp_set == NULL) { ++ return; ++ } ++ ++ cp_set->set = NULL; + } + + static inline void cil_reset_classperms_list(struct cil_list *cp_list) diff --git a/backport-CVE-2021-36087.patch b/backport-CVE-2021-36087.patch new file mode 100644 index 0000000000000000000000000000000000000000..120ea20be352f912209cc33e23e2a19fa3d10984 --- /dev/null +++ b/backport-CVE-2021-36087.patch @@ -0,0 +1,148 @@ +From 340f0eb7f3673e8aacaf0a96cbfcd4d12a405521 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 30 Mar 2021 13:39:18 -0400 +Subject: [PATCH] libsepol/cil: Check for statements not allowed in optional + blocks + +While there are some checks for invalid statements in an optional +block when resolving the AST, there are no checks when building the +AST. + +OSS-Fuzz found the following policy which caused a null dereference +in cil_tree_get_next_path(). + (blockinherit b3) + (sid SID) + (sidorder(SID)) + (optional o + (ibpkeycon :(1 0)s) + (block b3 + (filecon""block()) + (filecon""block()))) + +The problem is that the blockinherit copies block b3 before +the optional block is disabled. When the optional is disabled, +block b3 is deleted along with everything else in the optional. +Later, when filecon statements with the same path are found an +error message is produced and in trying to find out where the block +was copied from, the reference to the deleted block is used. The +error handling code assumes (rightly) that if something was copied +from a block then that block should still exist. + +It is clear that in-statements, blocks, and macros cannot be in an +optional, because that allows nodes to be copied from the optional +block to somewhere outside even though the optional could be disabled +later. When optionals are disabled the AST is reset and the +resolution is restarted at the point of resolving macro calls, so +anything resolved before macro calls will never be re-resolved. +This includes tunableifs, in-statements, blockinherits, +blockabstracts, and macro definitions. Tunable declarations also +cannot be in an optional block because they are needed to resolve +tunableifs. It should be fine to allow blockinherit statements in +an optional, because that is copying nodes from outside the optional +to the optional and if the optional is later disabled, everything +will be deleted anyway. + +Check and quit with an error if a tunable declaration, in-statement, +block, blockabstract, or macro definition is found within an +optional when either building or resolving the AST. + +Signed-off-by: James Carter +--- + 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 96c944975..882548585 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 56295a047..efff0f2ec 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; diff --git a/backport-libsepol-add-missing-oom-checks.patch b/backport-libsepol-add-missing-oom-checks.patch new file mode 100644 index 0000000000000000000000000000000000000000..840e9df9aeb096a437f90f235be5662622f5660c --- /dev/null +++ b/backport-libsepol-add-missing-oom-checks.patch @@ -0,0 +1,77 @@ +From 0233e4f6d59a96b759e32661a20be4bbadb374a4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Thu, 31 Mar 2022 16:44:52 +0200 +Subject: [PATCH] libsepol: add missing oom checks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Check return values of memory allocation functions and propagate their +failure. + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + src/kernel_to_cil.c | 5 +++++ + src/module_to_cil.c | 7 +++++++ + src/policydb.c | 3 ++- + 3 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/src/kernel_to_cil.c b/src/kernel_to_cil.c +index d4dee8d..ef6161c 100644 +--- a/libsepol/src/kernel_to_cil.c ++++ b/libsepol/src/kernel_to_cil.c +@@ -555,6 +555,11 @@ static int write_sids_to_cil(FILE *out, const char *const *sid_to_str, + } else { + snprintf(unknown, 18, "%s%u", "UNKNOWN", i); + sid = strdup(unknown); ++ if (!sid) { ++ sepol_log_err("Out of memory"); ++ rc = -1; ++ goto exit; ++ } + } + rc = strs_add_at_index(strs, sid, i); + if (rc != 0) { +diff --git a/src/module_to_cil.c b/src/module_to_cil.c +index 3e17018..5027fb7 100644 +--- a/libsepol/src/module_to_cil.c ++++ b/libsepol/src/module_to_cil.c +@@ -391,6 +391,8 @@ static int typealias_list_create(struct policydb *pdb) + } + + typealias_lists = calloc(max_decl_id + 1, sizeof(*typealias_lists)); ++ if (!typealias_lists) ++ goto exit; + typealias_lists_len = max_decl_id + 1; + + rc = hashtab_map(pdb->p_types.table, typealiases_gather_map, pdb); +@@ -2551,6 +2553,11 @@ static int ocontext_isid_to_cil(struct policydb *pdb, const char *const *sid_to_ + goto exit; + } + item->sid_key = strdup(sid); ++ if (!item->sid_key) { ++ log_err("Out of memory"); ++ rc = -1; ++ goto exit; ++ } + item->next = head; + head = item; + } +diff --git a/src/policydb.c b/src/policydb.c +index 3992ea5..982bc23 100644 +--- a/libsepol/src/policydb.c ++++ b/libsepol/src/policydb.c +@@ -1248,7 +1248,8 @@ int policydb_index_others(sepol_handle_t * handle, + if (!p->type_val_to_struct) + return -1; + +- cond_init_bool_indexes(p); ++ if (cond_init_bool_indexes(p)) ++ return -1; + + for (i = SYM_ROLES; i < SYM_NUM; i++) { + free(p->sym_val_to_name[i]); +-- +2.27.0 + diff --git a/backport-libsepol-avoid-potential-NULL-dereference-on-optional-parameter.patch b/backport-libsepol-avoid-potential-NULL-dereference-on-optional-parameter.patch new file mode 100644 index 0000000000000000000000000000000000000000..2d7f0413a29e3a7217449965034c669c03fa9021 --- /dev/null +++ b/backport-libsepol-avoid-potential-NULL-dereference-on-optional-parameter.patch @@ -0,0 +1,32 @@ +From f505a73b06302ba5e84f8c56851121d4a410c1ea Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Fri, 10 Jun 2022 17:06:23 +0200 +Subject: [PATCH] libsepol: avoid potential NULL dereference on optional + parameter +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The parameter `reason` of `context_struct_compute_av()` is optional and +can be passed in as NULL, like from `type_attribute_bounds_av()`. + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/src/services.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/libsepol/src/services.c b/libsepol/src/services.c +index d7510e9da..24412d837 100644 +--- a/libsepol/src/services.c ++++ b/libsepol/src/services.c +@@ -894,7 +894,8 @@ static void type_attribute_bounds_av(context_struct_t *scontext, + /* mask violated permissions */ + avd->allowed &= ~masked; + +- *reason |= SEPOL_COMPUTEAV_BOUNDS; ++ if (reason) ++ *reason |= SEPOL_COMPUTEAV_BOUNDS; + } + + /* diff --git a/backport-libsepol-check-correct-pointer-for-oom.patch b/backport-libsepol-check-correct-pointer-for-oom.patch new file mode 100644 index 0000000000000000000000000000000000000000..20f8e17c9ac11fa6194308ede4fddaf680ca02c2 --- /dev/null +++ b/backport-libsepol-check-correct-pointer-for-oom.patch @@ -0,0 +1,34 @@ +From 68a29c3aee60a6dd4e0d435fc10adb0f2cc1c0ef Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Fri, 8 Apr 2022 15:10:51 +0200 +Subject: [PATCH] libsepol: check correct pointer for oom +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Check the actual pointer which memory was assigned to, not its parent +array pointer. + + services.c:810:14: warning: Assigned value is garbage or undefined [core.uninitialized.Assign] + **r_buf = **new_buf; + ^ ~~~~~~~~~ + +Acked-by: James Carter +Signed-off-by: Christian Göttsche +--- + libsepol/src/services.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libsepol/src/services.c b/libsepol/src/services.c +index 47e564df4..d7510e9da 100644 +--- a/libsepol/src/services.c ++++ b/libsepol/src/services.c +@@ -803,7 +803,7 @@ static int constraint_expr_eval_reason(context_struct_t *scontext, + if (len < 0 || len >= reason_buf_len - reason_buf_used) { + new_buf_len = reason_buf_len + REASON_BUF_SIZE; + *new_buf = realloc(*r_buf, new_buf_len); +- if (!new_buf) { ++ if (!*new_buf) { + ERR(NULL, "failed to realloc reason buffer"); + goto out1; + } diff --git a/backport-libsepol-cil-Allow-duplicate-optional-blocks-in-most.patch b/backport-libsepol-cil-Allow-duplicate-optional-blocks-in-most.patch new file mode 100644 index 0000000000000000000000000000000000000000..bb2af7081d47aba591734ae878a3a8ffe1531b5f --- /dev/null +++ b/backport-libsepol-cil-Allow-duplicate-optional-blocks-in-most.patch @@ -0,0 +1,276 @@ +From 67a8dc8117e0c3887c39f7add8932e4ad23c1d9c Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Wed, 16 Jun 2021 17:04:00 -0400 +Subject: [PATCH] libsepol/cil: Allow duplicate optional blocks in most cases + +The commit d155b410d4bbc90d28f361b966f0429598da8188 (libsepol/cil: +Check for duplicate blocks, optionals, and macros) fixed a bug +that allowed duplicate blocks, optionals, and macros with the same +name in the same namespace. For blocks and macros, a duplicate +is always a problem, but optional block names are only used for +in-statement resolution. If no in-statement refers to an optional +block, then it does not matter if more than one with same name +exists. + +One easy way to generate multiple optional blocks with the same +name declaration is to call a macro with an optional block multiple +times in the same namespace. + +As an example, here is a portion of CIL policy + (macro m1 ((type t)) + (optional op1 + (allow t self (CLASS (PERM))) + ) + ) + (type t1) + (call m1 (t1)) + (type t2) + (call m1 (t2)) +This will result in two optional blocks with the name op1. + +There are three parts to allowing multiple optional blocks with +the same name declaration. + +1) Track an optional block's enabled status in a different way. + + One hinderance to allowing multiple optional blocks with the same + name declaration is that they cannot share the same datum. This is + because the datum is used to get the struct cil_optional which has + the enabled field and each block's enabled status is independent of + the others. + + Remove the enabled field from struct cil_optional, so it only contains + the datum. Use a stack to track which optional blocks are being + disabled, so they can be deleted in the right order. + +2) Allow multiple declarations of optional blocks. + + Update cil_allow_multiple_decls() so that a flavor of CIL_OPTIONAL + will return CIL_TRUE. Also remove the check in cil_copy_optional(). + +3) Check if an in-statement refers to an optional with multiple + declarations and exit with an error if it does. + +Signed-off-by: James Carter +Acked-by: Nicolas Iooss +--- + libsepol/cil/src/cil.c | 1 - + libsepol/cil/src/cil_build_ast.c | 3 +++ + libsepol/cil/src/cil_copy_ast.c | 11 +------- + libsepol/cil/src/cil_internal.h | 1 - + libsepol/cil/src/cil_resolve_ast.c | 55 +++++++++++++++++++++++--------------- + 5 files changed, 37 insertions(+), 34 deletions(-) + +diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c +index 0d351b4..671b5ec 100644 +--- a/libsepol/cil/src/cil.c ++++ b/libsepol/cil/src/cil.c +@@ -2752,7 +2752,6 @@ void cil_call_init(struct cil_call **call) + void cil_optional_init(struct cil_optional **optional) + { + *optional = cil_malloc(sizeof(**optional)); +- (*optional)->enabled = CIL_TRUE; + cil_symtab_datum_init(&(*optional)->datum); + } + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index 71ddada..ea665a3 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -96,6 +96,9 @@ static int cil_allow_multiple_decls(struct cil_db *db, enum cil_flavor f_new, en + return CIL_TRUE; + } + break; ++ case CIL_OPTIONAL: ++ return CIL_TRUE; ++ break; + default: + break; + } +diff --git a/libsepol/cil/src/cil_copy_ast.c b/libsepol/cil/src/cil_copy_ast.c +index 954eab3..9c0231f 100644 +--- a/libsepol/cil/src/cil_copy_ast.c ++++ b/libsepol/cil/src/cil_copy_ast.c +@@ -1529,19 +1529,10 @@ int cil_copy_macro(__attribute__((unused)) struct cil_db *db, void *data, void * + return SEPOL_OK; + } + +-int cil_copy_optional(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab) ++int cil_copy_optional(__attribute__((unused)) struct cil_db *db, __attribute__((unused)) void *data, void **copy, __attribute__((unused)) symtab_t *symtab) + { +- struct cil_optional *orig = data; +- char *key = orig->datum.name; +- struct cil_symtab_datum *datum = NULL; + struct cil_optional *new; + +- cil_symtab_get_datum(symtab, key, &datum); +- if (datum != NULL) { +- cil_tree_log(NODE(datum), CIL_ERR, "Re-declaration of %s %s", cil_node_to_string(NODE(datum)), key); +- return SEPOL_ERR; +- } +- + cil_optional_init(&new); + *copy = new; + +diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h +index a77c952..24be09a 100644 +--- a/libsepol/cil/src/cil_internal.h ++++ b/libsepol/cil/src/cil_internal.h +@@ -358,7 +358,6 @@ struct cil_in { + + struct cil_optional { + struct cil_symtab_datum datum; +- int enabled; + }; + + struct cil_perm { +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index b5199ba..6d13544 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -46,12 +46,13 @@ + #include "cil_verify.h" + #include "cil_strpool.h" + #include "cil_symtab.h" ++#include "cil_stack.h" + + struct cil_args_resolve { + struct cil_db *db; + enum cil_pass pass; + uint32_t *changed; +- struct cil_list *disabled_optionals; ++ struct cil_list *to_destroy; + struct cil_tree_node *block; + struct cil_tree_node *macro; + struct cil_tree_node *optional; +@@ -62,6 +63,7 @@ struct cil_args_resolve { + struct cil_list *catorder_lists; + struct cil_list *sensitivityorder_lists; + struct cil_list *in_list; ++ struct cil_stack *disabled_optionals; + }; + + static struct cil_name * __cil_insert_name(struct cil_db *db, hashtab_key_t key, struct cil_tree_node *ast_node) +@@ -2552,6 +2554,15 @@ int cil_resolve_in(struct cil_tree_node *current, void *extra_args) + + block_node = NODE(block_datum); + ++ if (block_node->flavor == CIL_OPTIONAL) { ++ if (block_datum->nodes && block_datum->nodes->head != block_datum->nodes->tail) { ++ cil_tree_log(current, CIL_ERR, "Multiple optional blocks referred to by in-statement"); ++ cil_tree_log(block_node, CIL_ERR, "First optional block"); ++ rc = SEPOL_ERR; ++ goto exit; ++ } ++ } ++ + rc = cil_copy_ast(db, current, block_node); + if (rc != SEPOL_OK) { + cil_tree_log(current, CIL_ERR, "Failed to copy in-statement"); +@@ -3874,6 +3885,7 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + struct cil_tree_node *macro = args->macro; + struct cil_tree_node *optional = args->optional; + struct cil_tree_node *boolif = args->boolif; ++ struct cil_stack *disabled_optionals = args->disabled_optionals; + + if (node == NULL) { + goto exit; +@@ -3953,22 +3965,14 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + + rc = __cil_resolve_ast_node(node, extra_args); + if (rc == SEPOL_ENOENT) { +- enum cil_log_level lvl = CIL_ERR; +- +- if (optional != NULL) { +- struct cil_optional *opt = (struct cil_optional *)optional->data; +- struct cil_tree_node *opt_node = NODE(opt); +- +- lvl = CIL_INFO; +- /* 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)); +- cil_tree_log(opt_node, lvl, "Disabling optional '%s'", opt->datum.name); ++ if (optional == NULL) { ++ cil_tree_log(node, CIL_ERR, "Failed to resolve %s statement", cil_node_to_string(node)); ++ } else { ++ cil_stack_push(disabled_optionals, CIL_NODE, optional); ++ cil_tree_log(node, CIL_INFO, "Failed to resolve %s statement", cil_node_to_string(node)); ++ cil_tree_log(optional, CIL_INFO, "Disabling optional '%s'", DATUM(optional->data)->name); + rc = SEPOL_OK; +- goto exit; + } +- +- cil_tree_log(node, lvl, "Failed to resolve %s statement", cil_node_to_string(node)); + goto exit; + } + +@@ -4011,6 +4015,7 @@ 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_stack *disabled_optionals = args->disabled_optionals; + struct cil_tree_node *parent = NULL; + + if (current == NULL || extra_args == NULL) { +@@ -4033,9 +4038,11 @@ int __cil_resolve_ast_last_child_helper(struct cil_tree_node *current, void *ext + args->macro = NULL; + } else if (parent->flavor == CIL_OPTIONAL) { + struct cil_tree_node *n = parent->parent; +- if (((struct cil_optional *)parent->data)->enabled == CIL_FALSE) { ++ struct cil_stack_item *item = cil_stack_peek(disabled_optionals); ++ if (item && item->data == parent) { ++ cil_stack_pop(disabled_optionals); + *(args->changed) = CIL_TRUE; +- cil_list_append(args->disabled_optionals, CIL_NODE, parent); ++ cil_list_append(args->to_destroy, CIL_NODE, parent); + } + args->optional = NULL; + while (n && n->flavor != CIL_ROOT) { +@@ -4079,14 +4086,17 @@ 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.disabled_optionals = NULL; + +- cil_list_init(&extra_args.disabled_optionals, CIL_NODE); ++ cil_list_init(&extra_args.to_destroy, CIL_NODE); + cil_list_init(&extra_args.sidorder_lists, CIL_LIST_ITEM); + cil_list_init(&extra_args.classorder_lists, CIL_LIST_ITEM); + cil_list_init(&extra_args.unordered_classorder_lists, CIL_LIST_ITEM); + cil_list_init(&extra_args.catorder_lists, CIL_LIST_ITEM); + cil_list_init(&extra_args.sensitivityorder_lists, CIL_LIST_ITEM); + cil_list_init(&extra_args.in_list, CIL_IN); ++ cil_stack_init(&extra_args.disabled_optionals); ++ + for (pass = CIL_PASS_TIF; pass < CIL_PASS_NUM; pass++) { + extra_args.pass = pass; + rc = cil_tree_walk(current, __cil_resolve_ast_node_helper, __cil_resolve_ast_first_child_helper, __cil_resolve_ast_last_child_helper, &extra_args); +@@ -4179,11 +4189,11 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + goto exit; + } + } +- cil_list_for_each(item, extra_args.disabled_optionals) { ++ cil_list_for_each(item, extra_args.to_destroy) { + cil_tree_children_destroy(item->data); + } +- cil_list_destroy(&extra_args.disabled_optionals, CIL_FALSE); +- cil_list_init(&extra_args.disabled_optionals, CIL_NODE); ++ cil_list_destroy(&extra_args.to_destroy, CIL_FALSE); ++ cil_list_init(&extra_args.to_destroy, CIL_NODE); + changed = 0; + } + } +@@ -4200,8 +4210,9 @@ exit: + __cil_ordered_lists_destroy(&extra_args.catorder_lists); + __cil_ordered_lists_destroy(&extra_args.sensitivityorder_lists); + __cil_ordered_lists_destroy(&extra_args.unordered_classorder_lists); +- cil_list_destroy(&extra_args.disabled_optionals, CIL_FALSE); ++ cil_list_destroy(&extra_args.to_destroy, CIL_FALSE); + cil_list_destroy(&extra_args.in_list, CIL_FALSE); ++ cil_stack_destroy(&extra_args.disabled_optionals); + + return rc; + } +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Allow-permission-expressions-when-using.patch b/backport-libsepol-cil-Allow-permission-expressions-when-using.patch new file mode 100644 index 0000000000000000000000000000000000000000..2df73b154a39ca851378b9a7e8ab584cf389fdb3 --- /dev/null +++ b/backport-libsepol-cil-Allow-permission-expressions-when-using.patch @@ -0,0 +1,75 @@ +From 22fb6f477bf10e834ece9eff84438fcaebf7d2ec Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 8 Apr 2021 13:32:14 -0400 +Subject: [PATCH] libsepol/cil: Allow permission expressions when using map + classes + +The following policy will cause a segfault: + (class CLASS (PERM)) + (class C (P1 P2 P3)) + (classorder (CLASS C)) + (sid SID) + (sidorder (SID)) + (user USER) + (role ROLE) + (type TYPE) + (category CAT) + (categoryorder (CAT)) + (sensitivity SENS) + (sensitivityorder (SENS)) + (sensitivitycategory SENS (CAT)) + (allow TYPE self (CLASS (PERM))) + (roletype ROLE TYPE) + (userrole USER ROLE) + (userlevel USER (SENS)) + (userrange USER ((SENS)(SENS (CAT)))) + (sidcontext SID (USER ROLE TYPE ((SENS)(SENS)))) + + (classmap CM (PM1 PM2 PM3)) + (classmapping CM PM1 (C (P1))) + (classmapping CM PM2 (C (P2))) + (classmapping CM PM3 (C (P3))) + (allow TYPE self (CM (and (all) (not PM2)))) + +The problem is that, while permission expressions are allowed for +normal classes, map classes are expected to only have permission +lists and no check is done to verify that only a permission list +is being used. + +When the above policy is parsed, the "and" and "all" are seen as +expression operators, but when the map permissions are converted to +normal class and permissions, the permission expression is assumed +to be a list of datums and since the operators are not datums a +segfault is the result. + +There is no reason to limit map classes to only using a list of +permissions and, in fact, it would be better to be able to use them +in the same way normal classes are used. + +Allow permissions expressions to be used for map classes by first +evaluating the permission expression and then converting the +resulting list to normal classes and permissions. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_post.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c +index fd4758d..05842b6 100644 +--- a/libsepol/cil/src/cil_post.c ++++ b/libsepol/cil/src/cil_post.c +@@ -2137,6 +2137,10 @@ static int __evaluate_classperms_list(struct cil_list *classperms, struct cil_db + } + } else { /* MAP */ + struct cil_list_item *i = NULL; ++ rc = __evaluate_classperms(cp, db); ++ if (rc != SEPOL_OK) { ++ goto exit; ++ } + cil_list_for_each(i, cp->perms) { + struct cil_perm *cmp = i->data; + rc = __evaluate_classperms_list(cmp->classperms, db); +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Allow-some-duplicate-macro-and-block-de.patch b/backport-libsepol-cil-Allow-some-duplicate-macro-and-block-de.patch new file mode 100644 index 0000000000000000000000000000000000000000..6f1540df22550acb0f1ab178ed5b68024ea8fdcc --- /dev/null +++ b/backport-libsepol-cil-Allow-some-duplicate-macro-and-block-de.patch @@ -0,0 +1,216 @@ +From 8d197879f91337c2c4d972a3dd23bb4b133ff355 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Mon, 16 Aug 2021 16:01:39 -0400 +Subject: [PATCH] libsepol/cil: Allow some duplicate macro and block + declarations + +The commit d155b410d4bbc90d28f361b966f0429598da8188 (libsepol/cil: +Check for duplicate blocks, optionals, and macros) added checks when +copying blocks, macros, and optionals so that a duplicate would cause +an exit with an error. Unfortunately, some policies exist that depend +on this behavior when using inheritance. + +The behavior is as follows. + +For macros only the first declared macro matters. +; +(macro m ((type ARG1)) + (allow ARG1 self (CLASS (PERM1))) +) +(block b + (macro m ((type ARG1)) + (allow ARG1 self (CLASS (PERM2))) + ) +) +(blockinherit b) +(type t) +(call m (t)) +; +For this policy segment, the macro m in block b will not be called. +Only the original macro m will be. + +This behavior has been used to override macros that are going to +be inherited. Only the inherited macros that have not already been +declared in the destination namespace will be used. + +Blocks seem to work fine even though there are two of them +; +(block b1 + (blockinherit b2) + (block b + (type t1) + (allow t1 self (CLASS (PERM))) + ) +) +(block b2 + (block b + (type t2) + (allow t2 self (CLASS (PERM))) + ) +) +(blockinherit b1) +; +In this example, the blockinherit of b2 will cause there to be +two block b's in block b1. Note that if both block b's tried to +declare the same type, then that would be an error. The blockinherit +of b1 will copy both block b's. + +This behavior has been used to allow the use of in-statements for +a block that is being inherited. Since the in-statements are resolved +before block inheritance, this only works if a block with the same +name as the block to be inherited is declared in the namespace. + +To support the use of these two behaviors, allow duplicate blocks +and macros when they occur as the result of block inheritance. In +any other circumstances and error for a redeclaration will be given. + +Since the duplicate macro is not going to be used it is just skipped. +The duplicate block will use the datum of the original block. In both +cases a warning message will be produced (it will only be seen if +"-v" is used when compiling the policy). + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_copy_ast.c | 69 +++++++++++++++++++++++++++++------------ + 1 file changed, 50 insertions(+), 19 deletions(-) + +diff --git a/libsepol/cil/src/cil_copy_ast.c b/libsepol/cil/src/cil_copy_ast.c +index 34282a9..cdbc84e 100644 +--- a/libsepol/cil/src/cil_copy_ast.c ++++ b/libsepol/cil/src/cil_copy_ast.c +@@ -43,6 +43,7 @@ + #include "cil_strpool.h" + + struct cil_args_copy { ++ struct cil_tree_node *orig_dest; + struct cil_tree_node *dest; + struct cil_db *db; + }; +@@ -101,17 +102,23 @@ int cil_copy_block(__attribute__((unused)) struct cil_db *db, void *data, void * + struct cil_block *orig = data; + char *key = orig->datum.name; + struct cil_symtab_datum *datum = NULL; +- struct cil_block *new; + + cil_symtab_get_datum(symtab, key, &datum); + if (datum != NULL) { +- cil_tree_log(NODE(datum), CIL_ERR, "Re-declaration of %s %s", cil_node_to_string(NODE(datum)), key); +- return SEPOL_ERR; ++ if (FLAVOR(datum) != CIL_BLOCK) { ++ cil_tree_log(NODE(orig), CIL_ERR, "Block %s being copied", key); ++ cil_tree_log(NODE(datum), CIL_ERR, " Conflicts with %s already declared", cil_node_to_string(NODE(datum))); ++ return SEPOL_ERR; ++ } ++ cil_tree_log(NODE(orig), CIL_WARN, "Block %s being copied", key); ++ cil_tree_log(NODE(datum), CIL_WARN, " Previously declared"); ++ *copy = datum; ++ } else { ++ struct cil_block *new; ++ cil_block_init(&new); ++ *copy = new; + } + +- cil_block_init(&new); +- *copy = new; +- + return SEPOL_OK; + } + +@@ -1511,21 +1518,26 @@ int cil_copy_macro(__attribute__((unused)) struct cil_db *db, void *data, void * + struct cil_macro *orig = data; + char *key = orig->datum.name; + struct cil_symtab_datum *datum = NULL; +- struct cil_macro *new; + + cil_symtab_get_datum(symtab, key, &datum); + if (datum != NULL) { +- cil_tree_log(NODE(datum), CIL_ERR, "Re-declaration of %s %s", cil_node_to_string(NODE(datum)), key); +- return SEPOL_ERR; +- } +- +- cil_macro_init(&new); +- if (orig->params != NULL) { +- cil_copy_list(orig->params, &new->params); ++ if (FLAVOR(datum) != CIL_MACRO) { ++ cil_tree_log(NODE(orig), CIL_ERR, "Macro %s being copied", key); ++ cil_tree_log(NODE(datum), CIL_ERR, " Conflicts with %s already declared", cil_node_to_string(NODE(datum))); ++ return SEPOL_ERR; ++ } ++ cil_tree_log(NODE(orig), CIL_WARN, "Skipping macro %s", key); ++ cil_tree_log(NODE(datum), CIL_WARN, " Previously declared"); ++ *copy = NULL; ++ } else { ++ struct cil_macro *new; ++ cil_macro_init(&new); ++ if (orig->params != NULL) { ++ cil_copy_list(orig->params, &new->params); ++ } ++ *copy = new; + } + +- *copy = new; +- + return SEPOL_OK; + } + +@@ -1701,7 +1713,7 @@ int cil_copy_src_info(__attribute__((unused)) struct cil_db *db, void *data, voi + return SEPOL_OK; + } + +-int __cil_copy_node_helper(struct cil_tree_node *orig, __attribute__((unused)) uint32_t *finished, void *extra_args) ++int __cil_copy_node_helper(struct cil_tree_node *orig, uint32_t *finished, void *extra_args) + { + int rc = SEPOL_ERR; + struct cil_tree_node *parent = NULL; +@@ -2006,6 +2018,16 @@ int __cil_copy_node_helper(struct cil_tree_node *orig, __attribute__((unused)) u + + rc = (*copy_func)(db, orig->data, &data, symtab); + if (rc == SEPOL_OK) { ++ if (orig->flavor == CIL_MACRO && data == NULL) { ++ /* Skipping macro re-declaration */ ++ if (args->orig_dest->flavor != CIL_BLOCKINHERIT) { ++ cil_log(CIL_ERR, " Re-declaration of macro is only allowed when inheriting a block\n"); ++ return SEPOL_ERR; ++ } ++ *finished = CIL_TREE_SKIP_HEAD; ++ return SEPOL_OK; ++ } ++ + cil_tree_node_init(&new); + + new->parent = parent; +@@ -2014,7 +2036,15 @@ int __cil_copy_node_helper(struct cil_tree_node *orig, __attribute__((unused)) u + new->flavor = orig->flavor; + new->data = data; + +- if (orig->flavor >= CIL_MIN_DECLARATIVE) { ++ if (orig->flavor == CIL_BLOCK && DATUM(data)->nodes->head != NULL) { ++ /* Duplicate block */ ++ if (args->orig_dest->flavor != CIL_BLOCKINHERIT) { ++ cil_log(CIL_ERR, " Re-declaration of block is only allowed when inheriting a block\n"); ++ rc = SEPOL_ERR; ++ goto exit; ++ } ++ cil_list_append(DATUM(new->data)->nodes, CIL_NODE, new); ++ } else if (orig->flavor >= CIL_MIN_DECLARATIVE) { + /* Check the flavor of data if was found in the destination symtab */ + if (DATUM(data)->nodes->head && FLAVOR(data) != orig->flavor) { + cil_tree_log(orig, CIL_ERR, "Incompatible flavor when trying to copy %s", DATUM(data)->name); +@@ -2099,12 +2129,13 @@ int cil_copy_ast(struct cil_db *db, struct cil_tree_node *orig, struct cil_tree_ + int rc = SEPOL_ERR; + struct cil_args_copy extra_args; + ++ extra_args.orig_dest = dest; + extra_args.dest = dest; + extra_args.db = db; + + rc = cil_tree_walk(orig, __cil_copy_node_helper, NULL, __cil_copy_last_child_helper, &extra_args); + if (rc != SEPOL_OK) { +- cil_log(CIL_INFO, "cil_tree_walk failed, rc: %d\n", rc); ++ cil_tree_log(dest, CIL_ERR, "Failed to copy %s to %s", cil_node_to_string(orig), cil_node_to_string(dest)); + goto exit; + } + +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Check-for-duplicate-blocks-optionals-an.patch b/backport-libsepol-cil-Check-for-duplicate-blocks-optionals-an.patch new file mode 100644 index 0000000000000000000000000000000000000000..fb44a586a0f304c3e9f60759ab71d1f169d809ad --- /dev/null +++ b/backport-libsepol-cil-Check-for-duplicate-blocks-optionals-an.patch @@ -0,0 +1,163 @@ +From d155b410d4bbc90d28f361b966f0429598da8188 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 16 Mar 2021 10:26:28 -0400 +Subject: [PATCH] libsepol/cil: Check for duplicate blocks, optionals, and + macros + +In CIL, blocks, optionals, and macros share the same symbol table so +that the targets of "in" statements can be located. Because of this, +they cannot have the same name in the same namespace, but, because +they do not show up in the final policy, they can have the same name +as long as they are in different namespaces. Unfortunately, when +copying from one namespace to another, no check was being done to see +if there was a conflict. + +When copying blocks, optionals, and macros, if a datum is found in +the destination namespace, then there is a conflict with a previously +declared block, optional, or macro, so exit with an error. + +Reported-by: Nicolas Iooss +Reported-by: Evgeny Vereshchagin +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_copy_ast.c | 89 ++++++++++++----------------------------- + 1 file changed, 25 insertions(+), 64 deletions(-) + +diff --git a/libsepol/cil/src/cil_copy_ast.c b/libsepol/cil/src/cil_copy_ast.c +index c9aada9..ed96786 100644 +--- a/libsepol/cil/src/cil_copy_ast.c ++++ b/libsepol/cil/src/cil_copy_ast.c +@@ -100,16 +100,17 @@ int cil_copy_block(__attribute__((unused)) struct cil_db *db, void *data, void * + struct cil_block *orig = data; + char *key = orig->datum.name; + struct cil_symtab_datum *datum = NULL; ++ struct cil_block *new; + + cil_symtab_get_datum(symtab, key, &datum); +- if (datum == NULL) { +- struct cil_block *new; +- cil_block_init(&new); +- *copy = new; +- } else { +- *copy = datum;; ++ if (datum != NULL) { ++ cil_tree_log(NODE(datum), CIL_ERR, "Re-declaration of %s %s", cil_node_to_string(NODE(datum)), key); ++ return SEPOL_ERR; + } + ++ cil_block_init(&new); ++ *copy = new; ++ + return SEPOL_OK; + } + +@@ -1509,64 +1510,22 @@ int cil_copy_macro(__attribute__((unused)) struct cil_db *db, void *data, void * + struct cil_macro *orig = data; + char *key = orig->datum.name; + struct cil_symtab_datum *datum = NULL; ++ struct cil_macro *new; + + cil_symtab_get_datum(symtab, key, &datum); +- if (datum == NULL) { +- struct cil_macro *new; +- cil_macro_init(&new); +- if (orig->params != NULL) { +- cil_copy_list(orig->params, &new->params); +- } +- +- *copy = new; +- +- } else { +- struct cil_list_item *curr_orig = NULL; +- struct cil_list_item *curr_new = NULL; +- struct cil_param *param_orig = NULL; +- struct cil_param *param_new = NULL; +- +- if (((struct cil_macro*)datum)->params != NULL) { +- curr_new = ((struct cil_macro*)datum)->params->head; +- } +- +- if (orig->params != NULL) { +- curr_orig = orig->params->head; +- } +- +- if (curr_orig != NULL && curr_new != NULL) { +- while (curr_orig != NULL) { +- if (curr_new == NULL) { +- goto exit; +- } +- +- param_orig = (struct cil_param*)curr_orig->data; +- param_new = (struct cil_param*)curr_new->data; +- if (param_orig->str != param_new->str) { +- goto exit; +- } else if (param_orig->flavor != param_new->flavor) { +- goto exit; +- } +- +- curr_orig = curr_orig->next; +- curr_new = curr_new->next; +- } +- +- if (curr_new != NULL) { +- goto exit; +- } +- } else if (!(curr_orig == NULL && curr_new == NULL)) { +- goto exit; +- } ++ if (datum != NULL) { ++ cil_tree_log(NODE(datum), CIL_ERR, "Re-declaration of %s %s", cil_node_to_string(NODE(datum)), key); ++ return SEPOL_ERR; ++ } + +- *copy = datum; ++ cil_macro_init(&new); ++ if (orig->params != NULL) { ++ cil_copy_list(orig->params, &new->params); + } + +- return SEPOL_OK; ++ *copy = new; + +-exit: +- cil_log(CIL_INFO, "cil_copy_macro: macro cannot be redefined\n"); +- return SEPOL_ERR; ++ return SEPOL_OK; + } + + int cil_copy_optional(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab) +@@ -1574,16 +1533,17 @@ int cil_copy_optional(__attribute__((unused)) struct cil_db *db, void *data, voi + struct cil_optional *orig = data; + char *key = orig->datum.name; + struct cil_symtab_datum *datum = NULL; ++ struct cil_optional *new; + + cil_symtab_get_datum(symtab, key, &datum); +- if (datum == NULL) { +- struct cil_optional *new; +- cil_optional_init(&new); +- *copy = new; +- } else { +- *copy = datum; ++ if (datum != NULL) { ++ cil_tree_log(NODE(datum), CIL_ERR, "Re-declaration of %s %s", cil_node_to_string(NODE(datum)), key); ++ return SEPOL_ERR; + } + ++ cil_optional_init(&new); ++ *copy = new; ++ + return SEPOL_OK; + } + +@@ -2122,6 +2082,7 @@ int __cil_copy_node_helper(struct cil_tree_node *orig, __attribute__((unused)) u + args->dest = new; + } + } else { ++ cil_tree_log(orig, CIL_ERR, "Problem copying %s node", cil_node_to_string(orig)); + goto exit; + } + +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Check-for-empty-list-when-marking-never.patch b/backport-libsepol-cil-Check-for-empty-list-when-marking-never.patch new file mode 100644 index 0000000000000000000000000000000000000000..3e8e5a403620f801f95331e9a8cb0ad023c048fd --- /dev/null +++ b/backport-libsepol-cil-Check-for-empty-list-when-marking-never.patch @@ -0,0 +1,35 @@ +From f33745a22b4133c59059356a23dbbc229067e3c1 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Mon, 21 Jun 2021 10:56:43 -0400 +Subject: [PATCH] libsepol/cil: Check for empty list when marking neverallow + attributes + +When marking a type attribute as used in a neverallow (to help determine +whether or not it should be expanded), check if the attribute's expression +list is empty (no attributes are associated with it) before iterating +over the list. + +Signed-off-by: James Carter +Acked-by: Nicolas Iooss +--- + libsepol/cil/src/cil_post.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c +index 7bca083..7e2c2b9 100644 +--- a/libsepol/cil/src/cil_post.c ++++ b/libsepol/cil/src/cil_post.c +@@ -1494,6 +1494,10 @@ static void __mark_neverallow_attrs(struct cil_list *expr_list) + { + struct cil_list_item *curr; + ++ if (!expr_list) { ++ return; ++ } ++ + cil_list_for_each(curr, expr_list) { + if (curr->flavor == CIL_DATUM) { + if (FLAVOR(curr->data) == CIL_TYPEATTRIBUTE) { +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Cleanup-build-AST-helper-functions.patch b/backport-libsepol-cil-Cleanup-build-AST-helper-functions.patch new file mode 100644 index 0000000000000000000000000000000000000000..85421702d1de31cdd63adc5ce220d9d2b9269afd --- /dev/null +++ b/backport-libsepol-cil-Cleanup-build-AST-helper-functions.patch @@ -0,0 +1,88 @@ +From f043078f1debeb1c84d4f6943aa689c33dd9cefc Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 30 Mar 2021 13:39:13 -0400 +Subject: [PATCH] libsepol/cil: Cleanup build AST helper functions + +Since parse_current, finished, and extra_args can never be NULL, +remove the useless check and directly assign local variables from +extra_args. + +Signed-off-by: James Carter +--- + 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 eee21086b..0d6d91a7d 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -6065,28 +6065,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; +@@ -6474,20 +6462,11 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + + 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; +@@ -6516,9 +6495,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) diff --git a/backport-libsepol-cil-Create-new-first-child-helper-function-.patch b/backport-libsepol-cil-Create-new-first-child-helper-function-.patch new file mode 100644 index 0000000000000000000000000000000000000000..bd7a8020d56951b570f502412d248f800fd0a136 --- /dev/null +++ b/backport-libsepol-cil-Create-new-first-child-helper-function-.patch @@ -0,0 +1,95 @@ +From ab90cb46abd4cfc5927f48c7b61782aa97e2561f Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 30 Mar 2021 13:39:14 -0400 +Subject: [PATCH] libsepol/cil: Create new first child helper function for + building AST + +In order to find statements not allowed in tunableifs, in-statements, +macros, and booleanifs, there are tree node pointers that point to +each of these kinds of statements when its block is being parsed. +If the pointer is non-NULL, then the rule being parsed is in the block +of that kind of statement. + +The tree node pointers were being updated at the wrong point which +prevented an invalid statement from being found if it was the first +statement in the block of a tunableif, in-statement, macro, or +booleanif. + +Create a first child helper function for walking the parse tree and +in that function set the appropriate tree node pointer if the +current AST node is a tunableif, in-statement, macro, or booleanif. +This also makes the code symmetrical with the last child helper +where the tree node pointers are set to NULL. + +Signed-off-by: James Carter +--- + 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 0d6d91a7d..9836f0445 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -6429,22 +6429,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; +@@ -6460,6 +6444,30 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + 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; +@@ -6513,7 +6521,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; + } diff --git a/backport-libsepol-cil-Destroy-disabled-optional-blocks-after-.patch b/backport-libsepol-cil-Destroy-disabled-optional-blocks-after-.patch new file mode 100644 index 0000000000000000000000000000000000000000..546a9551c901595d1a20b54d438ef24eeef05191 --- /dev/null +++ b/backport-libsepol-cil-Destroy-disabled-optional-blocks-after-.patch @@ -0,0 +1,115 @@ +From 0451adebdf153eee1f69914141311114a0130982 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Mon, 8 Feb 2021 11:23:42 -0500 +Subject: [PATCH] libsepol/cil: Destroy disabled optional blocks after pass is + complete + +Nicolas Iooss reports: + I am continuing to investigate OSS-Fuzz crashes and the following one + is quite complex. Here is a CIL policy which triggers a + heap-use-after-free error in the CIL compiler: + + (class CLASS (PERM2)) + (classorder (CLASS)) + (classpermission CLSPRM) + (optional o + (mlsvalidatetrans x (domby l1 h1)) + (common CLSCOMMON (PERM1)) + (classcommon CLASS CLSCOMMON) + ) + (classpermissionset CLSPRM (CLASS (PERM1))) + + The issue is that the mlsvalidatetrans fails to resolve in pass + CIL_PASS_MISC3, which comes after the resolution of classcommon (in + pass CIL_PASS_MISC2). So: + + * In pass CIL_PASS_MISC2, the optional block still exists, the + classcommon is resolved and class CLASS is linked with common + CLSCOMMON. + * In pass CIL_PASS_MISC3, the optional block is destroyed, including + the common CLSCOMMON. + * When classpermissionset is resolved, function cil_resolve_classperms + uses "common_symtab = &class->common->perms;", which has been freed. + The use-after-free issue occurs in __cil_resolve_perms (in + libsepol/cil/src/cil_resolve_ast.c): + + // common_symtab was freed + rc = cil_symtab_get_datum(common_symtab, curr->data, &perm_datum); + +The fundamental problem here is that when the optional block is +disabled it is immediately destroyed in the middle of the pass, so +the class has not been reset and still refers to the now destroyed +common when the classpermissionset is resolved later in the same pass. + +Added a list, disabled_optionals, to struct cil_args_resolve which is +passed when resolving the tree. When optionals are disabled, they are +now added to this list and then are destroyed after the tree has been +reset between passes. + +Reported-by: Nicolas Iooss +Signed-off-by: James Carter +Acked-by: Nicolas Iooss +--- + libsepol/cil/src/cil_resolve_ast.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 208bc01..0e07856 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -51,6 +51,7 @@ struct cil_args_resolve { + struct cil_db *db; + enum cil_pass pass; + uint32_t *changed; ++ struct cil_list *disabled_optionals; + struct cil_tree_node *optstack; + struct cil_tree_node *boolif; + struct cil_tree_node *macro; +@@ -3942,7 +3943,7 @@ int __cil_resolve_ast_last_child_helper(struct cil_tree_node *current, void *ext + + if (((struct cil_optional *)parent->data)->enabled == CIL_FALSE) { + *(args->changed) = CIL_TRUE; +- cil_tree_children_destroy(parent); ++ cil_list_append(args->disabled_optionals, CIL_NODE, parent); + } + + /* pop off the stack */ +@@ -4005,6 +4006,7 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + 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); + cil_list_init(&extra_args.classorder_lists, CIL_LIST_ITEM); + cil_list_init(&extra_args.unordered_classorder_lists, CIL_LIST_ITEM); +@@ -4072,6 +4074,7 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + } + + if (changed && (pass > CIL_PASS_CALL1)) { ++ struct cil_list_item *item; + /* Need to re-resolve because an optional was disabled that contained + * one or more declarations. We only need to reset to the call1 pass + * because things done in the preceding passes aren't allowed in +@@ -4100,6 +4103,11 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + cil_log(CIL_ERR, "Failed to reset declarations\n"); + goto exit; + } ++ cil_list_for_each(item, extra_args.disabled_optionals) { ++ cil_tree_children_destroy(item->data); ++ } ++ cil_list_destroy(&extra_args.disabled_optionals, CIL_FALSE); ++ cil_list_init(&extra_args.disabled_optionals, CIL_NODE); + } + + /* reset the arguments */ +@@ -4128,6 +4136,7 @@ exit: + __cil_ordered_lists_destroy(&extra_args.catorder_lists); + __cil_ordered_lists_destroy(&extra_args.sensitivityorder_lists); + __cil_ordered_lists_destroy(&extra_args.unordered_classorder_lists); ++ cil_list_destroy(&extra_args.disabled_optionals, CIL_FALSE); + cil_list_destroy(&extra_args.in_list, CIL_FALSE); + + return rc; +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Detect-degenerate-inheritance-and-exit-.patch b/backport-libsepol-cil-Detect-degenerate-inheritance-and-exit-.patch new file mode 100644 index 0000000000000000000000000000000000000000..318b49015c46d9261faea35b4b9fbd4bcaea5bbb --- /dev/null +++ b/backport-libsepol-cil-Detect-degenerate-inheritance-and-exit-.patch @@ -0,0 +1,136 @@ +From 74d00a8decebf940d95064ff60042dcb2cbcc2c0 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Wed, 28 Apr 2021 16:07:02 -0400 +Subject: [PATCH] libsepol/cil: Detect degenerate inheritance and exit with an + error + +A CIL policy with inheritance of the form +... +(blockinherit ba) +(block ba + (block b1 + (blockinherit bb) + ) + (block bb + (block b2 + (blockinherit bc) + ) + (block bc + (block b3 + (blockinherit bd) + ) + (block bd + (block b4 + (blockinherit be) + ) + (block be + ... +will require creating 2^depth copies of the block at the bottom of +the inheritance chain. This pattern can quickly consume all the +memory of the system compiling this policy. + +The depth of the inheritance chain can be found be walking the +tree up through the parents and noting how many of the parent +blocks have been inherited. The number of times a block will be +copied is found by counting the list of nodes in the "bi_nodes" +list of the block. To minimize legitimate policies from being +falsely detected as being degenerate, both the depth and breadth +(number of copies) are checked and an error is given only if both +exceed the limits (depth >= 12 and breadth >= 4096). + +This problem was found by the secilc-fuzzer. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_internal.h | 2 ++ + libsepol/cil/src/cil_resolve_ast.c | 54 ++++++++++++++++++++++++++++++++++++++ + 2 files changed, 56 insertions(+) + +diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h +index 9bdcbdd..74e0b34 100644 +--- a/libsepol/cil/src/cil_internal.h ++++ b/libsepol/cil/src/cil_internal.h +@@ -48,6 +48,8 @@ + + #define CIL_MAX_NAME_LENGTH 2048 + ++#define CIL_DEGENERATE_INHERITANCE_DEPTH 12 ++#define CIL_DEGENERATE_INHERITANCE_BREADTH (0x1 << CIL_DEGENERATE_INHERITANCE_DEPTH) + + enum cil_pass { + CIL_PASS_INIT = 0, +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 5389df4..6890964 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -2410,6 +2410,55 @@ exit: + return rc; + } + ++/* ++ * Detect degenerate inheritance of the form: ++ * ... ++ * (blockinherit ba) ++ * (block ba ++ * (block b1 ++ * (blockinherit bb) ++ * ) ++ * (block bb ++ * (block b2 ++ * (blockinherit bc) ++ * ) ++ * (block bc ++ * ... ++ */ ++static int cil_check_for_degenerate_inheritance(struct cil_tree_node *current) ++{ ++ struct cil_block *block = current->data; ++ struct cil_tree_node *node; ++ struct cil_list_item *item; ++ unsigned depth; ++ unsigned breadth = 0; ++ ++ cil_list_for_each(item, block->bi_nodes) { ++ breadth++; ++ } ++ ++ if (breadth >= CIL_DEGENERATE_INHERITANCE_BREADTH) { ++ node = current->parent; ++ depth = 0; ++ while (node && node->flavor != CIL_ROOT) { ++ if (node->flavor == CIL_BLOCK) { ++ block = node->data; ++ if (block->bi_nodes != NULL) { ++ depth++; ++ } ++ } ++ node = node->parent; ++ } ++ ++ if (depth >= CIL_DEGENERATE_INHERITANCE_DEPTH) { ++ cil_tree_log(current, CIL_ERR, "Degenerate inheritance detected (depth=%u, breadth=%u)", depth, breadth); ++ return SEPOL_ERR; ++ } ++ } ++ ++ return SEPOL_OK; ++} ++ + int cil_resolve_blockinherit_copy(struct cil_tree_node *current, void *extra_args) + { + struct cil_block *block = current->data; +@@ -2426,6 +2475,11 @@ int cil_resolve_blockinherit_copy(struct cil_tree_node *current, void *extra_arg + + db = args->db; + ++ rc = cil_check_for_degenerate_inheritance(current); ++ if (rc != SEPOL_OK) { ++ goto exit; ++ } ++ + // Make sure this is the original block and not a merged block from a blockinherit + if (current != block->datum.nodes->head->data) { + rc = SEPOL_OK; +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Fix-heap-use-after-free-in_class-rese.patch b/backport-libsepol-cil-Fix-heap-use-after-free-in_class-rese.patch new file mode 100644 index 0000000000000000000000000000000000000000..f32ce6e669a86d8aa8358779f4e222495c9be641 --- /dev/null +++ b/backport-libsepol-cil-Fix-heap-use-after-free-in_class-rese.patch @@ -0,0 +1,90 @@ +From f0d98f83d28a0cdf437b4cafe229e27cb91eb493 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Wed, 6 Jan 2021 13:43:26 -0500 +Subject: [PATCH] libsepol/cil: Fix heap-use-after-free in + __class_reset_perm_values() + +Nicolas Iooss reports: + A few weeks ago, OSS-Fuzz got configured in order to fuzz the CIL + policy compiler (cf. + https://github.com/SELinuxProject/selinux/issues/215 and + https://github.com/google/oss-fuzz/pull/4790). It reported a bunch of + simple issues, for which I will submit patches. There are also more + subtle bugs, like the one triggered by this CIL policy: + + (class CLASS (PERM)) + (classorder (CLASS)) + (sid SID) + (sidorder (SID)) + (sensitivity SENS) + (sensitivityorder (SENS)) + (type TYPE) + (allow TYPE self (CLASS (PERM))) + + (block b + (optional o + (sensitivitycategory SENS (C)) ; Non-existing category + triggers disabling the optional + (common COMMON (PERM1)) + (classcommon CLASS COMMON) + (allow TYPE self (CLASS (PERM1))) + ) + ) + + On my computer, secilc manages to build this policy fine, but when + clang's Address Sanitizer is enabled, running secilc leads to the + following report: + + $ make -C libsepol/src CC=clang CFLAGS='-g -fsanitize=address' libsepol.a + $ clang -g -fsanitize=address secilc/secilc.c libsepol/src/libsepol.a + -o my_secilc + $ ./my_secilc -vv testcase.cil + Parsing testcase.cil + Building AST from Parse Tree + Destroying Parse Tree + Resolving AST + Failed to resolve sensitivitycategory statement at testcase.cil:12 + Disabling optional 'o' at testcase.cil:11 + Resetting declarations + ================================================================= + ==181743==ERROR: AddressSanitizer: heap-use-after-free on address + 0x6070000000c0 at pc 0x55ff7e445d24 bp 0x7ffe7eecfba0 sp + 0x7ffe7eecfb98 + READ of size 4 at 0x6070000000c0 thread T0 + #0 0x55ff7e445d23 in __class_reset_perm_values + /git/selinux-userspace/libsepol/src/../cil/src/cil_reset_ast.c:17:17 + +The problem is that the optional branch is destroyed when it is disabled, +so the common has already been destroyed when the reset code tries to +access the number of common permissions, so that it can change the +value of the class permissions back to their original values. + +The solution is to count the number of class permissions and then +calculate the number of common permissions. + +Reported-by: Nicolas Iooss +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_reset_ast.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/libsepol/cil/src/cil_reset_ast.c b/libsepol/cil/src/cil_reset_ast.c +index 43e6b88e0..52e5f6401 100644 +--- a/libsepol/cil/src/cil_reset_ast.c ++++ b/libsepol/cil/src/cil_reset_ast.c +@@ -22,11 +22,12 @@ static int __class_reset_perm_values(__attribute__((unused)) hashtab_key_t k, ha + static void cil_reset_class(struct cil_class *class) + { + if (class->common != NULL) { +- struct cil_class *common = class->common; +- cil_symtab_map(&class->perms, __class_reset_perm_values, &common->num_perms); ++ /* Must assume that the common has been destroyed */ ++ int num_common_perms = class->num_perms - class->perms.nprim; ++ cil_symtab_map(&class->perms, __class_reset_perm_values, &num_common_perms); + /* during a re-resolve, we need to reset the common, so a classcommon + * statement isn't seen as a duplicate */ +- class->num_perms -= common->num_perms; ++ class->num_perms = class->perms.nprim; + class->common = NULL; /* Must make this NULL or there will be an error when re-resolving */ + } + class->ordered = CIL_FALSE; diff --git a/backport-libsepol-cil-Fix-instances-where-an-error-returns-SE.patch b/backport-libsepol-cil-Fix-instances-where-an-error-returns-SE.patch new file mode 100644 index 0000000000000000000000000000000000000000..bfc38f3b13e5a9a7e4ef9fb70441fd2d9cde0ba6 --- /dev/null +++ b/backport-libsepol-cil-Fix-instances-where-an-error-returns-SE.patch @@ -0,0 +1,80 @@ +From 5681c6275b5ad9cf3d84af243a66b900a0628f72 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Wed, 28 Apr 2021 16:06:58 -0400 +Subject: [PATCH] libsepol/cil: Fix instances where an error returns SEPOL_OK + +There are six instances when the CIL policy is being built or +resolved where an error can be detected, but SEPOL_OK is returned +instead of SEPOL_ERR. This causes the policy compiler to continue +when it should exit with an error. + +Return SEPOL_ERR in these cases, so the compiler exits with an +error. + +Two of the instances were found by the secilc-fuzzer. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_build_ast.c | 3 +++ + libsepol/cil/src/cil_resolve_ast.c | 3 +++ + 2 files changed, 6 insertions(+) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index 5b1e282..87043a8 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -444,6 +444,7 @@ int cil_gen_class(struct cil_db *db, struct cil_tree_node *parse_current, struct + } + if (class->num_perms > CIL_PERMS_PER_CLASS) { + cil_tree_log(parse_current, CIL_ERR, "Too many permissions in class '%s'", class->datum.name); ++ rc = SEPOL_ERR; + goto exit; + } + +@@ -1018,6 +1019,7 @@ int cil_gen_common(struct cil_db *db, struct cil_tree_node *parse_current, struc + } + if (common->num_perms > CIL_PERMS_PER_CLASS) { + cil_tree_log(parse_current, CIL_ERR, "Too many permissions in common '%s'", common->datum.name); ++ rc = SEPOL_ERR; + goto exit; + } + +@@ -3209,6 +3211,7 @@ int cil_gen_expandtypeattribute(struct cil_db *db, struct cil_tree_node *parse_c + expandattr->expand = CIL_FALSE; + } else { + cil_log(CIL_ERR, "Value must be either \'true\' or \'false\'"); ++ rc = SEPOL_ERR; + goto exit; + } + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 872b679..5389df4 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -772,6 +772,7 @@ int cil_resolve_classcommon(struct cil_tree_node *current, void *extra_args) + class->num_perms += common->num_perms; + if (class->num_perms > CIL_PERMS_PER_CLASS) { + cil_tree_log(current, CIL_ERR, "Too many permissions in class '%s' when including common permissions", class->datum.name); ++ rc = SEPOL_ERR; + goto exit; + } + +@@ -1484,6 +1485,7 @@ int cil_resolve_classorder(struct cil_tree_node *current, void *extra_args) + rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_CLASSES, extra_args, &datum); + if (rc != SEPOL_OK) { + cil_log(CIL_ERR, "Failed to resolve class %s in classorder\n", (char *)curr->data); ++ rc = SEPOL_ERR; + goto exit; + } + cil_list_append(new, CIL_CLASS, datum); +@@ -2464,6 +2466,7 @@ int cil_resolve_blockabstract(struct cil_tree_node *current, void *extra_args) + block_node = NODE(block_datum); + if (block_node->flavor != CIL_BLOCK) { + cil_log(CIL_ERR, "Failed to resolve blockabstract to a block, rc: %d\n", rc); ++ rc = SEPOL_ERR; + goto exit; + } + +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Fix-potential-undefined-shifts.patch b/backport-libsepol-cil-Fix-potential-undefined-shifts.patch new file mode 100644 index 0000000000000000000000000000000000000000..74ec3d9ad98f0c5216c2f5570d1d35e7118d4cb9 --- /dev/null +++ b/backport-libsepol-cil-Fix-potential-undefined-shifts.patch @@ -0,0 +1,52 @@ +From 974da80e08d24e92e5409bb040f95d06a47776a2 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Fri, 8 Oct 2021 10:27:49 -0400 +Subject: [PATCH] libsepol/cil: Fix potential undefined shifts + +An expression of the form "1 << x" is undefined if x == 31 because +the "1" is an int and cannot be left shifted by 31. + +Instead, use "UINT32_C(1) << x" which will be an unsigned int of +at least 32 bits. + +This bug was found by the secilc-fuzzer. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_binary.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c +index ec5f01e..d8aa495 100644 +--- a/libsepol/cil/src/cil_binary.c ++++ b/libsepol/cil/src/cil_binary.c +@@ -1225,7 +1225,7 @@ int __perm_str_to_datum(char *perm_str, class_datum_t *sepol_class, uint32_t *da + goto exit; + } + } +- *datum |= 1 << (sepol_perm->s.value - 1); ++ *datum |= UINT32_C(1) << (sepol_perm->s.value - 1); + + return SEPOL_OK; + +@@ -1523,7 +1523,7 @@ int cil_avrule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_ + /* index of the u32 containing the permission */ + #define XPERM_IDX(x) (x >> 5) + /* set bits 0 through x-1 within the u32 */ +-#define XPERM_SETBITS(x) ((1U << (x & 0x1f)) - 1) ++#define XPERM_SETBITS(x) ((UINT32_C(1) << (x & 0x1f)) - 1) + /* low value for this u32 */ + #define XPERM_LOW(x) (x << 5) + /* high value for this u32 */ +@@ -4760,7 +4760,7 @@ static struct cil_list *cil_classperms_from_sepol(policydb_t *pdb, uint16_t clas + cil_list_init(&cp->perms, CIL_PERM); + for (i = 0; i < sepol_class->permissions.nprim; i++) { + struct cil_perm *perm; +- if ((data & (1 << i)) == 0) continue; ++ if ((data & (UINT32_C(1) << i)) == 0) continue; + perm = perm_value_to_cil[class][i+1]; + if (!perm) goto exit; + cil_list_append(cp->perms, CIL_PERM, perm); +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Fix-syntax-checking-of-defaultrange-rul.patch b/backport-libsepol-cil-Fix-syntax-checking-of-defaultrange-rul.patch new file mode 100644 index 0000000000000000000000000000000000000000..136f8c76a1fefda081af18291e97e93b2f32d1ac --- /dev/null +++ b/backport-libsepol-cil-Fix-syntax-checking-of-defaultrange-rul.patch @@ -0,0 +1,55 @@ +From ac8b35d910750b56d38d54f312a712a73c95749c Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Mon, 21 Jun 2021 10:34:33 -0400 +Subject: [PATCH] libsepol/cil: Fix syntax checking of defaultrange rule + +When "glblub" was added as a default for the defaultrange rule, the +syntax array was updated because the "glblub" default does not need +to specify a range of "low", "high", or "low-high". Unfortunately, +additional checking was not added for the "source" and "target" +defaults to make sure they specified a range. This means that using +the "source" or "target" defaults without specifying the range will +result in a segfault. + +When the "source" or "target" defaults are used, check that the rule +specifies a range as well. + +This bug was found by the secilc-fuzzer. + +Signed-off-by: James Carter +Acked-by: Nicolas Iooss +--- + libsepol/cil/src/cil_build_ast.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index ea665a3..baed3e5 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -5886,6 +5886,11 @@ int cil_gen_defaultrange(struct cil_tree_node *parse_current, struct cil_tree_no + + object = parse_current->next->next->data; + if (object == CIL_KEY_SOURCE) { ++ if (!parse_current->next->next->next) { ++ cil_log(CIL_ERR, "Missing 'low', 'high', or 'low-high'\n"); ++ rc = SEPOL_ERR; ++ goto exit; ++ } + range = parse_current->next->next->next->data; + if (range == CIL_KEY_LOW) { + def->object_range = CIL_DEFAULT_SOURCE_LOW; +@@ -5899,6 +5904,11 @@ int cil_gen_defaultrange(struct cil_tree_node *parse_current, struct cil_tree_no + goto exit; + } + } else if (object == CIL_KEY_TARGET) { ++ if (!parse_current->next->next->next) { ++ cil_log(CIL_ERR, "Missing 'low', 'high', or 'low-high'\n"); ++ rc = SEPOL_ERR; ++ goto exit; ++ } + range = parse_current->next->next->next->data; + if (range == CIL_KEY_LOW) { + def->object_range = CIL_DEFAULT_TARGET_LOW; +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Handle-disabled-optional-blocks-in-earl.patch b/backport-libsepol-cil-Handle-disabled-optional-blocks-in-earl.patch new file mode 100644 index 0000000000000000000000000000000000000000..343db084c39e331176c426ab4bde049b17630caf --- /dev/null +++ b/backport-libsepol-cil-Handle-disabled-optional-blocks-in-earl.patch @@ -0,0 +1,94 @@ +From 5661efd459e7aa998390ab70e3ec50125a35e9e9 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 13 May 2021 12:30:37 -0400 +Subject: [PATCH] libsepol/cil: Handle disabled optional blocks in earlier + passes + +A failed tunable resolution in a tunableif can cause an optional +to be disabled before the CIL_PASS_CALL1 phase. If this occurs, the +optional block and its subtree should be destroyed, but no reset +will be required since tunables are not allowed inside an optional +block. + +Anytime there are optional blocks in the disabled_optionals list +(changed == 1), destroy the optional block and its subtree even if +in a pass before CIL_PASS_CALL1. + +This bug was found by the secilc-fuzzer. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_resolve_ast.c | 54 ++++++++++++++++++++------------------ + 1 file changed, 28 insertions(+), 26 deletions(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 74e5b78..328add0 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -4132,35 +4132,37 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + } + } + +- if (changed && (pass > CIL_PASS_CALL1)) { ++ if (changed) { + struct cil_list_item *item; +- /* Need to re-resolve because an optional was disabled that contained +- * one or more declarations. We only need to reset to the call1 pass +- * because things done in the preceding passes aren't allowed in +- * optionals, and thus can't be disabled. +- * Note: set pass to CIL_PASS_CALL1 because the pass++ will increment +- * it to CIL_PASS_CALL2 +- */ +- cil_log(CIL_INFO, "Resetting declarations\n"); +- +- if (pass >= CIL_PASS_MISC1) { +- __cil_ordered_lists_reset(&extra_args.sidorder_lists); +- __cil_ordered_lists_reset(&extra_args.classorder_lists); +- __cil_ordered_lists_reset(&extra_args.unordered_classorder_lists); +- __cil_ordered_lists_reset(&extra_args.catorder_lists); +- __cil_ordered_lists_reset(&extra_args.sensitivityorder_lists); +- cil_list_destroy(&db->sidorder, CIL_FALSE); +- cil_list_destroy(&db->classorder, CIL_FALSE); +- cil_list_destroy(&db->catorder, CIL_FALSE); +- cil_list_destroy(&db->sensitivityorder, CIL_FALSE); +- } ++ if (pass > CIL_PASS_CALL1) { ++ /* Need to re-resolve because an optional was disabled that contained ++ * one or more declarations. We only need to reset to the call1 pass ++ * because things done in the preceding passes aren't allowed in ++ * optionals, and thus can't be disabled. ++ * Note: set pass to CIL_PASS_CALL1 because the pass++ will increment ++ * it to CIL_PASS_CALL2 ++ */ ++ cil_log(CIL_INFO, "Resetting declarations\n"); ++ ++ if (pass >= CIL_PASS_MISC1) { ++ __cil_ordered_lists_reset(&extra_args.sidorder_lists); ++ __cil_ordered_lists_reset(&extra_args.classorder_lists); ++ __cil_ordered_lists_reset(&extra_args.unordered_classorder_lists); ++ __cil_ordered_lists_reset(&extra_args.catorder_lists); ++ __cil_ordered_lists_reset(&extra_args.sensitivityorder_lists); ++ cil_list_destroy(&db->sidorder, CIL_FALSE); ++ cil_list_destroy(&db->classorder, CIL_FALSE); ++ cil_list_destroy(&db->catorder, CIL_FALSE); ++ cil_list_destroy(&db->sensitivityorder, CIL_FALSE); ++ } + +- pass = CIL_PASS_CALL1; ++ pass = CIL_PASS_CALL1; + +- rc = cil_reset_ast(current); +- if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Failed to reset declarations\n"); +- goto exit; ++ rc = cil_reset_ast(current); ++ if (rc != SEPOL_OK) { ++ cil_log(CIL_ERR, "Failed to reset declarations\n"); ++ goto exit; ++ } + } + cil_list_for_each(item, extra_args.disabled_optionals) { + cil_tree_children_destroy(item->data); +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Handle-operations-in-a-class-mapping-wh.patch b/backport-libsepol-cil-Handle-operations-in-a-class-mapping-wh.patch new file mode 100644 index 0000000000000000000000000000000000000000..50962b1904b4a4837c92186f453891065f461e1a --- /dev/null +++ b/backport-libsepol-cil-Handle-operations-in-a-class-mapping-wh.patch @@ -0,0 +1,95 @@ +From 18f8747b28f1620903c7a3aa8a6616c199c173a6 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 16 Sep 2021 16:29:00 -0400 +Subject: [PATCH] libsepol/cil: Handle operations in a class mapping when + verifying + +When checking for circular class permission declarations and a class +mapping is encountered, the class permissions for each map permission +must be checked. An assumption was made that there were no operators +in the class permissions. An operator in the class permissions would +cause a segfault. + +Example causing segault: + (classmap cm1 (mp1)) + (classmapping cm1 mp1 (CLASS (PERM))) + (classpermission cp1) + (classpermissionset cp1 (cm1 (all))) + +For map class permissions, check each item in the permission list to +see if it is an operator. If it is not, then verify the class +permissions associated with the map permission. If it is an operator +and the operator is "all", then create a list of all permissions for +that map class and verify the class permissions associated with each +map permission. If it is a different operator, then it can be skipped. + +This bug was found by the secilc-fuzzer. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_verify.c | 40 +++++++++++++++++++++++++++++++++++----- + 1 file changed, 35 insertions(+), 5 deletions(-) + +diff --git a/libsepol/cil/src/cil_verify.c b/libsepol/cil/src/cil_verify.c +index 5502c4d..dc29ea6 100644 +--- a/libsepol/cil/src/cil_verify.c ++++ b/libsepol/cil/src/cil_verify.c +@@ -1689,6 +1689,15 @@ exit: + return rc; + } + ++static int __add_perm_to_list(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args) ++{ ++ struct cil_list *perm_list = (struct cil_list *)args; ++ ++ cil_list_append(perm_list, CIL_DATUM, d); ++ ++ return SEPOL_OK; ++} ++ + static int __cil_verify_classperms(struct cil_list *classperms, + struct cil_symtab_datum *orig, + struct cil_symtab_datum *parent, +@@ -1730,13 +1739,34 @@ static int __cil_verify_classperms(struct cil_list *classperms, + if (FLAVOR(cp->class) != CIL_CLASS) { /* MAP */ + struct cil_list_item *i = NULL; + cil_list_for_each(i, cp->perms) { +- struct cil_perm *cmp = i->data; +- rc = __cil_verify_classperms(cmp->classperms, orig, &cp->class->datum, &cmp->datum, CIL_MAP_PERM, steps, limit); +- if (rc != SEPOL_OK) { +- goto exit; ++ if (i->flavor != CIL_OP) { ++ struct cil_perm *cmp = i->data; ++ rc = __cil_verify_classperms(cmp->classperms, orig, &cp->class->datum, &cmp->datum, CIL_MAP_PERM, steps, limit); ++ if (rc != SEPOL_OK) { ++ goto exit; ++ } ++ } else { ++ enum cil_flavor op = (enum cil_flavor)i->data; ++ if (op == CIL_ALL) { ++ struct cil_class *mc = cp->class; ++ struct cil_list *perm_list; ++ struct cil_list_item *j = NULL; ++ ++ cil_list_init(&perm_list, CIL_MAP_PERM); ++ cil_symtab_map(&mc->perms, __add_perm_to_list, perm_list); ++ cil_list_for_each(j, perm_list) { ++ struct cil_perm *cmp = j->data; ++ rc = __cil_verify_classperms(cmp->classperms, orig, &cp->class->datum, &cmp->datum, CIL_MAP_PERM, steps, limit); ++ if (rc != SEPOL_OK) { ++ cil_list_destroy(&perm_list, CIL_FALSE); ++ goto exit; ++ } ++ } ++ cil_list_destroy(&perm_list, CIL_FALSE); ++ } + } + } +- } ++ } + } else { /* SET */ + struct cil_classperms_set *cp_set = curr->data; + struct cil_classpermission *cp = cp_set->set; +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Improve-checking-for-bad-inheritance-pa.patch b/backport-libsepol-cil-Improve-checking-for-bad-inheritance-pa.patch new file mode 100644 index 0000000000000000000000000000000000000000..d21aef4ea1e0370bbd603cff01a389b1e4ffbf8f --- /dev/null +++ b/backport-libsepol-cil-Improve-checking-for-bad-inheritance-pa.patch @@ -0,0 +1,315 @@ +From 9af91692416d01814f4b2ac22e39d3b57993af4f Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Wed, 30 Jun 2021 15:12:16 -0400 +Subject: [PATCH] libsepol/cil: Improve checking for bad inheritance patterns + +commits 37863b0b1444c85a1ddc6c333c8bfea0c678c592 (libsepol/cil: +Improve degenerate inheritance check) and +74d00a8decebf940d95064ff60042dcb2cbcc2c0 (libsepol/cil: Detect +degenerate inheritance and exit with an error) attempted to detect +and exit with an error when compiling policies that have degenerate +inheritances. These policies result in the exponential growth of memory +usage while copying the blocks that are inherited. + +There were two problems with the previous attempts to detect this +bad inheritance problem. The first is that the quick check using +cil_possible_degenerate_inheritance() did not detect all patterns +of degenerate inheritance. The second problem is that the detection +of inheritance loops during the CIL_PASS_BLKIN_LINK pass did not +detect all inheritance loops which made it possible for the full +degenerate inheritance checking done with +cil_check_for_degenerate_inheritance() to have a stack overflow +when encountering the inheritance loops. Both the degenerate and +loop inheritance checks need to be done at the same time and done +after the CIL_PASS_BLKIN_LINK pass. Otherwise, if loops are being +detected first, then a degenerate policy can cause the consumption +of all system memory and if degenerate policy is being detected +first, then an inheritance loop can cause a stack overflow. + +With the new approach, the quick check is eliminated and the full +check is always done after the CIL_PASS_BLKIN_LINK pass. Because +of this the "inheritance_check" field in struct cil_resolve_args +is not needed and removed and the functions +cil_print_recursive_blockinherit(), cil_check_recursive_blockinherit(), +and cil_possible_degenerate_inheritance() have been deleted. The +function cil_count_potential() is renamed cil_check_inheritances() +and has checks for both degenerate inheritance and inheritance loops. +The inheritance checking is improved and uses an approach similar +to commit c28525a26fa145cb5fd911fd2a3b9125a275677f (libsepol/cil: +Properly check for loops in sets). + +As has been the case with these degenerate inheritance patches, +these issues were discovered by the secilc-fuzzer. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_resolve_ast.c | 172 +++++++++---------------------------- + 1 file changed, 42 insertions(+), 130 deletions(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 9a02e38..145d4e7 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -64,7 +64,6 @@ struct cil_args_resolve { + struct cil_list *sensitivityorder_lists; + struct cil_list *in_list; + struct cil_stack *disabled_optionals; +- int *inheritance_check; + }; + + static struct cil_name * __cil_insert_name(struct cil_db *db, hashtab_key_t key, struct cil_tree_node *ast_node) +@@ -2309,100 +2308,8 @@ exit: + return rc; + } + +-static void cil_print_recursive_blockinherit(struct cil_tree_node *bi_node, struct cil_tree_node *terminating_node) +-{ +- struct cil_list *trace = NULL; +- struct cil_list_item *item = NULL; +- struct cil_tree_node *curr = NULL; +- +- cil_list_init(&trace, CIL_NODE); +- +- for (curr = bi_node; curr != terminating_node; curr = curr->parent) { +- if (curr->flavor == CIL_BLOCK) { +- cil_list_prepend(trace, CIL_NODE, curr); +- } else if (curr->flavor == CIL_BLOCKINHERIT) { +- if (curr != bi_node) { +- cil_list_prepend(trace, CIL_NODE, NODE(((struct cil_blockinherit *)curr->data)->block)); +- } +- cil_list_prepend(trace, CIL_NODE, curr); +- } else { +- cil_list_prepend(trace, CIL_NODE, curr); +- } +- } +- cil_list_prepend(trace, CIL_NODE, terminating_node); +- +- cil_list_for_each(item, trace) { +- curr = item->data; +- if (curr->flavor == CIL_BLOCK) { +- cil_tree_log(curr, CIL_ERR, "block %s", DATUM(curr->data)->name); +- } else if (curr->flavor == CIL_BLOCKINHERIT) { +- cil_tree_log(curr, CIL_ERR, "blockinherit %s", ((struct cil_blockinherit *)curr->data)->block_str); +- } else if (curr->flavor == CIL_OPTIONAL) { +- cil_tree_log(curr, CIL_ERR, "optional %s", DATUM(curr->data)->name); +- } else { +- cil_tree_log(curr, CIL_ERR, "%s", cil_node_to_string(curr)); +- } +- } +- +- cil_list_destroy(&trace, CIL_FALSE); +-} +- +-static int cil_check_recursive_blockinherit(struct cil_tree_node *bi_node) +-{ +- struct cil_tree_node *curr = NULL; +- struct cil_blockinherit *bi = NULL; +- struct cil_block *block = NULL; +- int rc = SEPOL_ERR; +- +- bi = bi_node->data; +- +- for (curr = bi_node->parent; curr != NULL; curr = curr->parent) { +- if (curr->flavor != CIL_BLOCK) { +- continue; +- } +- +- block = curr->data; +- +- if (block != bi->block) { +- continue; +- } +- +- cil_log(CIL_ERR, "Recursive blockinherit found:\n"); +- cil_print_recursive_blockinherit(bi_node, curr); +- +- rc = SEPOL_ERR; +- goto exit; +- } +- +- rc = SEPOL_OK; +- +-exit: +- return rc; +-} +- +-static int cil_possible_degenerate_inheritance(struct cil_tree_node *node) +-{ +- unsigned depth = 1; +- +- node = node->parent; +- while (node && node->flavor != CIL_ROOT) { +- if (node->flavor == CIL_BLOCK) { +- if (((struct cil_block *)(node->data))->bi_nodes != NULL) { +- depth++; +- if (depth >= CIL_DEGENERATE_INHERITANCE_DEPTH) { +- return CIL_TRUE; +- } +- } +- } +- node = node->parent; +- } +- +- return CIL_FALSE; +-} +- + int cil_resolve_blockinherit_link(struct cil_tree_node *current, void *extra_args) + { +- struct cil_args_resolve *args = extra_args; + struct cil_blockinherit *inherit = current->data; + struct cil_symtab_datum *block_datum = NULL; + struct cil_tree_node *node = NULL; +@@ -2423,20 +2330,11 @@ int cil_resolve_blockinherit_link(struct cil_tree_node *current, void *extra_arg + + inherit->block = (struct cil_block *)block_datum; + +- rc = cil_check_recursive_blockinherit(current); +- if (rc != SEPOL_OK) { +- goto exit; +- } +- + if (inherit->block->bi_nodes == NULL) { + cil_list_init(&inherit->block->bi_nodes, CIL_NODE); + } + cil_list_append(inherit->block->bi_nodes, CIL_NODE, current); + +- if (*(args->inheritance_check) == CIL_FALSE) { +- *(args->inheritance_check) = cil_possible_degenerate_inheritance(node); +- } +- + return SEPOL_OK; + + exit: +@@ -2466,11 +2364,6 @@ int cil_resolve_blockinherit_copy(struct cil_tree_node *current, void *extra_arg + } + + cil_list_for_each(item, block->bi_nodes) { +- rc = cil_check_recursive_blockinherit(item->data); +- if (rc != SEPOL_OK) { +- goto exit; +- } +- + rc = cil_copy_ast(db, current, item->data); + if (rc != SEPOL_OK) { + cil_log(CIL_ERR, "Failed to copy block contents into blockinherit\n"); +@@ -3611,34 +3504,58 @@ static unsigned cil_count_actual(struct cil_tree_node *node) + return count; + } + +-static unsigned cil_count_potential(struct cil_tree_node *node, unsigned max) ++static int cil_check_inheritances(struct cil_tree_node *node, unsigned max, unsigned *count, struct cil_stack *stack, unsigned *loop) + { +- unsigned count = 0; ++ int rc; + + if (node->flavor == CIL_BLOCKINHERIT) { + struct cil_blockinherit *bi = node->data; +- count += 1; ++ *count += 1; ++ if (*count > max) { ++ cil_tree_log(node, CIL_ERR, "Degenerate inheritance detected"); ++ return SEPOL_ERR; ++ } + if (bi->block) { +- count += cil_count_potential(NODE(bi->block), max); +- if (count > max) { +- return count; ++ struct cil_tree_node *block_node = NODE(bi->block); ++ struct cil_stack_item *item; ++ int i = 0; ++ cil_stack_for_each(stack, i, item) { ++ if (block_node == (struct cil_tree_node *)item->data) { ++ *loop = CIL_TRUE; ++ cil_tree_log(block_node, CIL_ERR, "Block inheritance loop found"); ++ cil_tree_log(node, CIL_ERR, " blockinherit"); ++ return SEPOL_ERR; ++ } ++ } ++ cil_stack_push(stack, CIL_BLOCK, block_node); ++ rc = cil_check_inheritances(block_node, max, count, stack, loop); ++ cil_stack_pop(stack); ++ if (rc != SEPOL_OK) { ++ if (*loop == CIL_TRUE) { ++ cil_tree_log(node, CIL_ERR, " blockinherit"); ++ } ++ return SEPOL_ERR; + } + } + } + + for (node = node->cl_head; node; node = node->next) { +- count += cil_count_potential(node, max); +- if (count > max) { +- return count; ++ rc = cil_check_inheritances(node, max, count, stack, loop); ++ if (rc != SEPOL_OK) { ++ return SEPOL_ERR; + } + } + +- return count; ++ return SEPOL_OK; + } + +-static int cil_check_for_degenerate_inheritance(struct cil_tree_node *node) ++static int cil_check_for_bad_inheritance(struct cil_tree_node *node) + { +- uint64_t num_actual, num_potential, max; ++ unsigned num_actual, max; ++ unsigned num_potential = 0; ++ unsigned loop = CIL_FALSE; ++ struct cil_stack *stack; ++ int rc; + + num_actual = cil_count_actual(node); + +@@ -3647,13 +3564,11 @@ static int cil_check_for_degenerate_inheritance(struct cil_tree_node *node) + max = CIL_DEGENERATE_INHERITANCE_MINIMUM; + } + +- num_potential = cil_count_potential(node, max); ++ cil_stack_init(&stack); ++ rc = cil_check_inheritances(node, max, &num_potential, stack, &loop); ++ cil_stack_destroy(&stack); + +- if (num_potential > max) { +- return SEPOL_ERR; +- } +- +- return SEPOL_OK; ++ return rc; + } + + int __cil_resolve_ast_node(struct cil_tree_node *node, void *extra_args) +@@ -4127,7 +4042,6 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + struct cil_args_resolve extra_args; + enum cil_pass pass = CIL_PASS_TIF; + uint32_t changed = 0; +- int inheritance_check = 0; + + if (db == NULL || current == NULL) { + return rc; +@@ -4147,7 +4061,6 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + extra_args.sensitivityorder_lists = NULL; + extra_args.in_list = NULL; + extra_args.disabled_optionals = NULL; +- extra_args.inheritance_check = &inheritance_check; + + cil_list_init(&extra_args.to_destroy, CIL_NODE); + cil_list_init(&extra_args.sidorder_lists, CIL_LIST_ITEM); +@@ -4174,10 +4087,9 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + cil_list_destroy(&extra_args.in_list, CIL_FALSE); + } + +- if (pass == CIL_PASS_BLKIN_LINK && inheritance_check == CIL_TRUE) { +- rc = cil_check_for_degenerate_inheritance(current); ++ if (pass == CIL_PASS_BLKIN_LINK) { ++ rc = cil_check_for_bad_inheritance(current); + if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Degenerate inheritance detected\n"); + rc = SEPOL_ERR; + goto exit; + } +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Improve-degenerate-inheritance-check.patch b/backport-libsepol-cil-Improve-degenerate-inheritance-check.patch new file mode 100644 index 0000000000000000000000000000000000000000..de6d60ce10b294cd9ea9cfa0d91349d489834f91 --- /dev/null +++ b/backport-libsepol-cil-Improve-degenerate-inheritance-check.patch @@ -0,0 +1,362 @@ +From 37863b0b1444c85a1ddc6c333c8bfea0c678c592 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Mon, 21 Jun 2021 10:56:55 -0400 +Subject: [PATCH] libsepol/cil: Improve degenerate inheritance check + +The commit 74d00a8decebf940d95064ff60042dcb2cbcc2c0 (libsepol/cil: +Detect degenerate inheritance and exit with an error) detects the +use of inheritance (mostly by the secilc-fuzzer and not in any real +policies) that results in the exponential growth of the policy through +the copying of blocks that takes place with inheritance in CIL. +Unfortunately, the check takes place during the pass when all the +blocks are being copied, so it is possible to consume all of a system's +memory before an error is produced. + +The new check happens in two parts. First, a check is made while the +block inheritance is being linked to the block it will inherit. In +this check, all of the parent nodes of the inheritance rule up to the +root node are checked and if enough of these blocks are being inherited +(>= CIL_DEGENERATE_INHERITANCE_DEPTH), then a flag is set for a more +in-depth check after the pass. This in-depth check will determine the +number of potential inheritances that will occur when resolving the +all of the inheritance rules. If this value is greater than +CIL_DEGENERATE_INHERITANCE_GROWTH * the original number of inheritance +rules and greater than CIL_DEGENERATE_INHERITANCE_MINIMUM (which is +set to 0x1 << CIL_DEGENERATE_INHERITANCE_DEPTH), then degenerate +inheritance is determined to have occurred and an error result will +be returned. + +Since the potential number of inheritances can quickly be an extremely +large number, the count of potential inheritances is aborted as soon +as the threshold for degenerate inheritance has been exceeded. + +Normal policies should rarely, if ever, have the in-depth check occur. + +Signed-off-by: James Carter +Acked-by: Nicolas Iooss +--- + libsepol/cil/src/cil_internal.h | 5 +- + libsepol/cil/src/cil_resolve_ast.c | 226 ++++++++++++++++++++++++------------- + 2 files changed, 151 insertions(+), 80 deletions(-) + +diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h +index 24be09a..8b9aeab 100644 +--- a/libsepol/cil/src/cil_internal.h ++++ b/libsepol/cil/src/cil_internal.h +@@ -48,8 +48,9 @@ + + #define CIL_MAX_NAME_LENGTH 2048 + +-#define CIL_DEGENERATE_INHERITANCE_DEPTH 12 +-#define CIL_DEGENERATE_INHERITANCE_BREADTH (0x1 << CIL_DEGENERATE_INHERITANCE_DEPTH) ++#define CIL_DEGENERATE_INHERITANCE_DEPTH 10UL ++#define CIL_DEGENERATE_INHERITANCE_MINIMUM (0x01 << CIL_DEGENERATE_INHERITANCE_DEPTH) ++#define CIL_DEGENERATE_INHERITANCE_GROWTH 10UL + + enum cil_pass { + CIL_PASS_INIT = 0, +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 6d13544..5245cc1 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -64,6 +64,7 @@ struct cil_args_resolve { + struct cil_list *sensitivityorder_lists; + struct cil_list *in_list; + struct cil_stack *disabled_optionals; ++ int *inheritance_check; + }; + + static struct cil_name * __cil_insert_name(struct cil_db *db, hashtab_key_t key, struct cil_tree_node *ast_node) +@@ -2308,40 +2309,7 @@ exit: + return rc; + } + +-int cil_resolve_blockinherit_link(struct cil_tree_node *current, void *extra_args) +-{ +- struct cil_blockinherit *inherit = current->data; +- struct cil_symtab_datum *block_datum = NULL; +- struct cil_tree_node *node = NULL; +- int rc = SEPOL_ERR; +- +- rc = cil_resolve_name(current, inherit->block_str, CIL_SYM_BLOCKS, extra_args, &block_datum); +- if (rc != SEPOL_OK) { +- goto exit; +- } +- +- node = NODE(block_datum); +- +- if (node->flavor != CIL_BLOCK) { +- cil_log(CIL_ERR, "%s is not a block\n", cil_node_to_string(node)); +- rc = SEPOL_ERR; +- goto exit; +- } +- +- inherit->block = (struct cil_block *)block_datum; +- +- if (inherit->block->bi_nodes == NULL) { +- cil_list_init(&inherit->block->bi_nodes, CIL_NODE); +- } +- cil_list_append(inherit->block->bi_nodes, CIL_NODE, current); +- +- return SEPOL_OK; +- +-exit: +- return rc; +-} +- +-void cil_print_recursive_blockinherit(struct cil_tree_node *bi_node, struct cil_tree_node *terminating_node) ++static void cil_print_recursive_blockinherit(struct cil_tree_node *bi_node, struct cil_tree_node *terminating_node) + { + struct cil_list *trace = NULL; + struct cil_list_item *item = NULL; +@@ -2379,7 +2347,7 @@ void cil_print_recursive_blockinherit(struct cil_tree_node *bi_node, struct cil_ + cil_list_destroy(&trace, CIL_FALSE); + } + +-int cil_check_recursive_blockinherit(struct cil_tree_node *bi_node) ++static int cil_check_recursive_blockinherit(struct cil_tree_node *bi_node) + { + struct cil_tree_node *curr = NULL; + struct cil_blockinherit *bi = NULL; +@@ -2412,53 +2380,67 @@ exit: + return rc; + } + +-/* +- * Detect degenerate inheritance of the form: +- * ... +- * (blockinherit ba) +- * (block ba +- * (block b1 +- * (blockinherit bb) +- * ) +- * (block bb +- * (block b2 +- * (blockinherit bc) +- * ) +- * (block bc +- * ... +- */ +-static int cil_check_for_degenerate_inheritance(struct cil_tree_node *current) ++static int cil_possible_degenerate_inheritance(struct cil_tree_node *node) + { +- struct cil_block *block = current->data; +- struct cil_tree_node *node; +- struct cil_list_item *item; +- unsigned depth; +- unsigned breadth = 0; ++ unsigned depth = 1; + +- cil_list_for_each(item, block->bi_nodes) { +- breadth++; +- } +- +- if (breadth >= CIL_DEGENERATE_INHERITANCE_BREADTH) { +- node = current->parent; +- depth = 0; +- while (node && node->flavor != CIL_ROOT) { +- if (node->flavor == CIL_BLOCK) { +- block = node->data; +- if (block->bi_nodes != NULL) { +- depth++; ++ node = node->parent; ++ while (node && node->flavor != CIL_ROOT) { ++ if (node->flavor == CIL_BLOCK) { ++ if (((struct cil_block *)(node->data))->bi_nodes != NULL) { ++ depth++; ++ if (depth >= CIL_DEGENERATE_INHERITANCE_DEPTH) { ++ return CIL_TRUE; + } + } +- node = node->parent; + } ++ node = node->parent; ++ } + +- if (depth >= CIL_DEGENERATE_INHERITANCE_DEPTH) { +- cil_tree_log(current, CIL_ERR, "Degenerate inheritance detected (depth=%u, breadth=%u)", depth, breadth); +- return SEPOL_ERR; +- } ++ return CIL_FALSE; ++} ++ ++int cil_resolve_blockinherit_link(struct cil_tree_node *current, void *extra_args) ++{ ++ struct cil_args_resolve *args = extra_args; ++ struct cil_blockinherit *inherit = current->data; ++ struct cil_symtab_datum *block_datum = NULL; ++ struct cil_tree_node *node = NULL; ++ int rc = SEPOL_ERR; ++ ++ rc = cil_resolve_name(current, inherit->block_str, CIL_SYM_BLOCKS, extra_args, &block_datum); ++ if (rc != SEPOL_OK) { ++ goto exit; ++ } ++ ++ node = NODE(block_datum); ++ ++ if (node->flavor != CIL_BLOCK) { ++ cil_log(CIL_ERR, "%s is not a block\n", cil_node_to_string(node)); ++ rc = SEPOL_ERR; ++ goto exit; ++ } ++ ++ inherit->block = (struct cil_block *)block_datum; ++ ++ rc = cil_check_recursive_blockinherit(current); ++ if (rc != SEPOL_OK) { ++ goto exit; ++ } ++ ++ if (inherit->block->bi_nodes == NULL) { ++ cil_list_init(&inherit->block->bi_nodes, CIL_NODE); ++ } ++ cil_list_append(inherit->block->bi_nodes, CIL_NODE, current); ++ ++ if (*(args->inheritance_check) == CIL_FALSE) { ++ *(args->inheritance_check) = cil_possible_degenerate_inheritance(node); + } + + return SEPOL_OK; ++ ++exit: ++ return rc; + } + + int cil_resolve_blockinherit_copy(struct cil_tree_node *current, void *extra_args) +@@ -2477,11 +2459,6 @@ int cil_resolve_blockinherit_copy(struct cil_tree_node *current, void *extra_arg + + db = args->db; + +- rc = cil_check_for_degenerate_inheritance(current); +- if (rc != SEPOL_OK) { +- goto exit; +- } +- + // Make sure this is the original block and not a merged block from a blockinherit + if (current != block->datum.nodes->head->data) { + rc = SEPOL_OK; +@@ -3597,6 +3574,88 @@ exit: + return rc; + } + ++/* ++ * Degenerate inheritance leads to exponential growth of the policy ++ * It can take many forms, but here is one example. ++ * ... ++ * (blockinherit ba) ++ * (block b0 ++ * (block b1 ++ * (block b2 ++ * (block b3 ++ * ... ++ * ) ++ * (blockinherit b3) ++ * ) ++ * (blockinherit b2) ++ * ) ++ * (blockinherit b1) ++ * ) ++ * (blockinherit b0) ++ * ... ++ * This leads to 2^4 copies of the content of block b3, 2^3 copies of the ++ * contents of block b2, etc. ++ */ ++static unsigned cil_count_actual(struct cil_tree_node *node) ++{ ++ unsigned count = 0; ++ ++ if (node->flavor == CIL_BLOCKINHERIT) { ++ count += 1; ++ } ++ ++ for (node = node->cl_head; node; node = node->next) { ++ count += cil_count_actual(node); ++ } ++ ++ return count; ++} ++ ++static unsigned cil_count_potential(struct cil_tree_node *node, unsigned max) ++{ ++ unsigned count = 0; ++ ++ if (node->flavor == CIL_BLOCKINHERIT) { ++ struct cil_blockinherit *bi = node->data; ++ count += 1; ++ if (bi->block) { ++ count += cil_count_potential(NODE(bi->block), max); ++ if (count > max) { ++ return count; ++ } ++ } ++ } ++ ++ for (node = node->cl_head; node; node = node->next) { ++ count += cil_count_potential(node, max); ++ if (count > max) { ++ return count; ++ } ++ } ++ ++ return count; ++} ++ ++static int cil_check_for_degenerate_inheritance(struct cil_tree_node *node) ++{ ++ uint64_t num_actual, num_potential, max; ++ ++ num_actual = cil_count_actual(node); ++ ++ max = num_actual * CIL_DEGENERATE_INHERITANCE_GROWTH; ++ if (max < CIL_DEGENERATE_INHERITANCE_MINIMUM) { ++ max = CIL_DEGENERATE_INHERITANCE_MINIMUM; ++ } ++ ++ num_potential = cil_count_potential(node, max); ++ ++ if (num_potential > max) { ++ return SEPOL_ERR; ++ } ++ ++ return SEPOL_OK; ++} ++ + int __cil_resolve_ast_node(struct cil_tree_node *node, void *extra_args) + { + int rc = SEPOL_OK; +@@ -4068,6 +4127,7 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + struct cil_args_resolve extra_args; + enum cil_pass pass = CIL_PASS_TIF; + uint32_t changed = 0; ++ int inheritance_check = 0; + + if (db == NULL || current == NULL) { + return rc; +@@ -4087,6 +4147,7 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + extra_args.sensitivityorder_lists = NULL; + extra_args.in_list = NULL; + extra_args.disabled_optionals = NULL; ++ extra_args.inheritance_check = &inheritance_check; + + cil_list_init(&extra_args.to_destroy, CIL_NODE); + cil_list_init(&extra_args.sidorder_lists, CIL_LIST_ITEM); +@@ -4113,6 +4174,15 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) + cil_list_destroy(&extra_args.in_list, CIL_FALSE); + } + ++ if (pass == CIL_PASS_BLKIN_LINK && inheritance_check == CIL_TRUE) { ++ rc = cil_check_for_degenerate_inheritance(current); ++ if (rc != SEPOL_OK) { ++ cil_log(CIL_ERR, "Degenerate inheritance detected\n"); ++ rc = SEPOL_ERR; ++ goto exit; ++ } ++ } ++ + if (pass == CIL_PASS_MISC1) { + db->sidorder = __cil_ordered_lists_merge_all(&extra_args.sidorder_lists, NULL); + if (db->sidorder == NULL) { +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Limit-the-number-of-open-parenthesis-al.patch b/backport-libsepol-cil-Limit-the-number-of-open-parenthesis-al.patch new file mode 100644 index 0000000000000000000000000000000000000000..537c293afb475ba75990ba97747a7a1c86857714 --- /dev/null +++ b/backport-libsepol-cil-Limit-the-number-of-open-parenthesis-al.patch @@ -0,0 +1,48 @@ +From 69fc31d1fb5d3bc1d4a919285284d1fb9d679a6e Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 13 May 2021 12:37:59 -0400 +Subject: [PATCH] libsepol/cil: Limit the number of open parenthesis allowed + +When parsing a CIL policy, the number of open parenthesis is tracked +to verify that each has a matching close parenthesis. If there are +too many open parenthesis, a stack overflow could occur during later +processing. + +Exit with an error if the number of open parenthesis exceeds 4096 +(which should be enough for any policy.) + +This bug was found by the secilc-fuzzer. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_parser.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_parser.c b/libsepol/cil/src/cil_parser.c +index a930621..fb95f40 100644 +--- a/libsepol/cil/src/cil_parser.c ++++ b/libsepol/cil/src/cil_parser.c +@@ -42,6 +42,8 @@ + #include "cil_strpool.h" + #include "cil_stack.h" + ++#define CIL_PARSER_MAX_EXPR_DEPTH (0x1 << 12) ++ + char *CIL_KEY_HLL_LMS; + char *CIL_KEY_HLL_LMX; + char *CIL_KEY_HLL_LME; +@@ -245,7 +247,10 @@ int cil_parser(const char *_path, char *buffer, uint32_t size, struct cil_tree * + break; + case OPAREN: + paren_count++; +- ++ if (paren_count > CIL_PARSER_MAX_EXPR_DEPTH) { ++ cil_log(CIL_ERR, "Number of open parenthesis exceeds limit of %d at line %d of %s\n", CIL_PARSER_MAX_EXPR_DEPTH, tok.line, path); ++ goto exit; ++ } + create_node(&node, current, tok.line, hll_lineno, NULL); + insert_node(node, current); + current = node; +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Properly-check-for-parameter-when-inser.patch b/backport-libsepol-cil-Properly-check-for-parameter-when-inser.patch new file mode 100644 index 0000000000000000000000000000000000000000..b764c8f06efe23bb04ea1672edc642e1544b52d0 --- /dev/null +++ b/backport-libsepol-cil-Properly-check-for-parameter-when-inser.patch @@ -0,0 +1,39 @@ +From 05d1c66aaae2b1ce3eaac7d241f24be121fddb39 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Fri, 27 Aug 2021 10:12:42 -0400 +Subject: [PATCH] libsepol/cil: Properly check for parameter when inserting + name + +File names for typetransition rules are stored in their own datums. +This allows them to be passed as a parameter, but there needs to be +a check in __cil_insert_name() so that parameter names are not +mistaken for file name strings. This check did not verify that a +matching parameter name had the flavor of CIL_NAME. + +Check that the parameter flavor is CIL_NAME and that the paramter +name matches the file name to be stored in the datum. + +This bug was found by the secilc-fuzzer. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_resolve_ast.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 1800732..a4de1c7 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -87,7 +87,8 @@ static struct cil_name * __cil_insert_name(struct cil_db *db, hashtab_key_t key, + if (macro != NULL && macro->params != NULL) { + struct cil_list_item *item; + cil_list_for_each(item, macro->params) { +- if (((struct cil_param*)item->data)->str == key) { ++ struct cil_param *param = item->data; ++ if (param->flavor == CIL_NAME && param->str == key) { + return NULL; + } + } +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Refactor-helper-function-for-cil_gen_no.patch b/backport-libsepol-cil-Refactor-helper-function-for-cil_gen_no.patch new file mode 100644 index 0000000000000000000000000000000000000000..33b99d02f68dc4ce4ece7e2290102ed9221b19bb --- /dev/null +++ b/backport-libsepol-cil-Refactor-helper-function-for-cil_gen_no.patch @@ -0,0 +1,74 @@ +From 63ce05ba07fc3517900fac22efe1c761d856762f Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Thu, 8 Apr 2021 13:32:16 -0400 +Subject: [PATCH] libsepol/cil: Refactor helper function for cil_gen_node() + +Change the name of cil_is_datum_multiple_decl() to +cil_allow_multiple_decls() and make it static. The new function +takes the CIL db and the flavors of the old and new datum as +arguments. Also, put all of the logic of determining if multiple +declarations are allowed into the new function. Finally, update +the call from cil_gen_node(). + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_build_ast.c | 27 ++++++++++----------------- + 1 file changed, 10 insertions(+), 17 deletions(-) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index e57de66..14cdce1 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -82,30 +82,24 @@ exit: + return rc; + } + +-/* +- * Determine whether or not multiple declarations of the same key can share a +- * datum, given the new datum and the one already present in a given symtab. +- */ +-int cil_is_datum_multiple_decl(__attribute__((unused)) struct cil_symtab_datum *cur, +- struct cil_symtab_datum *old, +- enum cil_flavor f) ++static int cil_allow_multiple_decls(struct cil_db *db, enum cil_flavor f_new, enum cil_flavor f_old) + { +- int rc = CIL_FALSE; ++ if (f_new != f_old) { ++ return CIL_FALSE; ++ } + +- switch (f) { ++ switch (f_new) { + case CIL_TYPE: + case CIL_TYPEATTRIBUTE: +- if (!old || f != FLAVOR(old)) { +- rc = CIL_FALSE; +- } else { +- /* type and typeattribute statements insert empty datums */ +- rc = CIL_TRUE; ++ if (db->multiple_decls) { ++ return CIL_TRUE; + } + break; + default: + break; + } +- return rc; ++ ++ return CIL_FALSE; + } + + int cil_gen_node(struct cil_db *db, struct cil_tree_node *ast_node, struct cil_symtab_datum *datum, hashtab_key_t key, enum cil_sym_index sflavor, enum cil_flavor nflavor) +@@ -135,8 +129,7 @@ int cil_gen_node(struct cil_db *db, struct cil_tree_node *ast_node, struct cil_s + cil_log(CIL_ERR, "Re-declaration of %s %s, but previous declaration could not be found\n",cil_node_to_string(ast_node), key); + goto exit; + } +- if (!db->multiple_decls || +- !cil_is_datum_multiple_decl(datum, prev, nflavor)) { ++ if (!cil_allow_multiple_decls(db, nflavor, FLAVOR(prev))) { + /* multiple_decls not ok, ret error */ + struct cil_tree_node *node = NODE(prev); + cil_log(CIL_ERR, "Re-declaration of %s %s\n", +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Remove-unused-field-from-struct-cil_arg.patch b/backport-libsepol-cil-Remove-unused-field-from-struct-cil_arg.patch new file mode 100644 index 0000000000000000000000000000000000000000..393c797e71b854ca2c7bf28e0e20d80cf711a7a8 --- /dev/null +++ b/backport-libsepol-cil-Remove-unused-field-from-struct-cil_arg.patch @@ -0,0 +1,47 @@ +From 9b9761cfaa09958ead2bcad256dd0f1706e8b5b3 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Mon, 16 Nov 2020 17:06:59 -0500 +Subject: [PATCH] libsepol/cil: Remove unused field from struct + cil_args_resolve + +When resolving names, the struct cil_args_resolve is passed to the +various resolve functions. The field last_resolved_name is not used. + +Remove the last_resolved_name field from struct cil_args_resolve. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_resolve_ast.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index daf873b..410b8c8 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -51,7 +51,6 @@ struct cil_args_resolve { + struct cil_db *db; + enum cil_pass pass; + uint32_t *changed; +- char *last_resolved_name; + struct cil_tree_node *optstack; + struct cil_tree_node *boolif; + struct cil_tree_node *macro; +@@ -3905,7 +3904,6 @@ 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.last_resolved_name = NULL; + extra_args.optstack = NULL; + extra_args.boolif= NULL; + extra_args.macro = NULL; +@@ -4234,7 +4232,5 @@ exit: + *datum = NULL; + } + +- args->last_resolved_name = name; +- + return rc; + } +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Reorder-checks-for-invalid-rules-when-b.patch b/backport-libsepol-cil-Reorder-checks-for-invalid-rules-when-b.patch new file mode 100644 index 0000000000000000000000000000000000000000..51ce88c52f0e3f3c9e23add76b8b85478aa865b4 --- /dev/null +++ b/backport-libsepol-cil-Reorder-checks-for-invalid-rules-when-b.patch @@ -0,0 +1,216 @@ +From 69bfe64cdf659cc47c544e6b376f0a653ff06f6f Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 30 Mar 2021 13:39:12 -0400 +Subject: [PATCH] libsepol/cil: Reorder checks for invalid rules when building + AST + +Reorder checks for invalid rules in the blocks of tunableifs, +in-statements, macros, and booleanifs when building the AST for +consistency. + +Order the checks in the same order the blocks will be resolved in, +so tuanbleif, in-statement, macro, booleanif, and then non-block +rules. + +Signed-off-by: James Carter +--- + 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 a4a2baa0f..eee21086b 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) +@@ -6069,10 +6069,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) { +@@ -6082,10 +6082,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 */ +@@ -6102,13 +6102,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; +@@ -6116,15 +6134,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) { +@@ -6138,24 +6156,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; +@@ -6441,14 +6441,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; + } +@@ -6457,6 +6449,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; +@@ -6492,14 +6492,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; + } +@@ -6508,6 +6500,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 +@@ -6532,10 +6532,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) { diff --git a/backport-libsepol-cil-Reorder-checks-for-invalid-rules-when-r.patch b/backport-libsepol-cil-Reorder-checks-for-invalid-rules-when-r.patch new file mode 100644 index 0000000000000000000000000000000000000000..7409e33f887f51dfe25f20bd44b9b2a607bf9f91 --- /dev/null +++ b/backport-libsepol-cil-Reorder-checks-for-invalid-rules-when-r.patch @@ -0,0 +1,175 @@ +From ef533c8fd941bfb0c9a729b757d8a5b68fe3d080 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 30 Mar 2021 13:39:16 -0400 +Subject: [PATCH] libsepol/cil: Reorder checks for invalid rules when resolving + AST + +Reorder checks for invalid rules in the blocks of tunableifs, +in-statements, macros, and booleanifs when resolving the AST for +consistency. + +Order the checks in the same order the blocks will be resolved in, +so tuanbleif, in-statement, macro, booleanif, and then non-block +rules. + +Signed-off-by: James Carter +--- + 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 a61462d..93fc0d6 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; +@@ -3777,50 +3777,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 { +@@ -3886,12 +3888,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; +@@ -3913,7 +3915,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; +@@ -3931,16 +3943,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; +@@ -3964,9 +3966,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; +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Reset-expandtypeattribute-rules-when-re.patch b/backport-libsepol-cil-Reset-expandtypeattribute-rules-when-re.patch new file mode 100644 index 0000000000000000000000000000000000000000..7803327e65bb599664508e02550784c61773a2ef --- /dev/null +++ b/backport-libsepol-cil-Reset-expandtypeattribute-rules-when-re.patch @@ -0,0 +1,57 @@ +From b57535318af6f3f5e79c90caed06423b1f50abb1 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Fri, 27 Aug 2021 10:11:19 -0400 +Subject: [PATCH] libsepol/cil: Reset expandtypeattribute rules when resetting + AST + +A list is created to store type attribute datums when resolving an +expandtypeattribute rule and that list needs to be destroyed if the +AST is reset or a memory leak will occur. + +Destroy the list storing type attributes datums when resetting +expandtypeattribute rules. + +This bug was found by the secilc-fuzzer. + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_reset_ast.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_reset_ast.c b/libsepol/cil/src/cil_reset_ast.c +index 6d1d2da..0ba075c 100644 +--- a/libsepol/cil/src/cil_reset_ast.c ++++ b/libsepol/cil/src/cil_reset_ast.c +@@ -208,6 +208,11 @@ static void cil_reset_typeattributeset(struct cil_typeattributeset *tas) + cil_list_destroy(&tas->datum_expr, CIL_FALSE); + } + ++static void cil_reset_expandtypeattribute(struct cil_expandtypeattribute *expandattr) ++{ ++ cil_list_destroy(&expandattr->attr_datums, CIL_FALSE); ++} ++ + static void cil_reset_avrule(struct cil_avrule *rule) + { + cil_reset_classperms_list(rule->perms.classperms); +@@ -531,6 +536,9 @@ int __cil_reset_node(struct cil_tree_node *node, __attribute__((unused)) uint32 + case CIL_TYPEATTRIBUTESET: + cil_reset_typeattributeset(node->data); + break; ++ case CIL_EXPANDTYPEATTRIBUTE: ++ cil_reset_expandtypeattribute(node->data); ++ break; + case CIL_RANGETRANSITION: + cil_reset_rangetransition(node->data); + break; +@@ -630,7 +638,6 @@ int __cil_reset_node(struct cil_tree_node *node, __attribute__((unused)) uint32 + case CIL_CLASSORDER: + case CIL_CATORDER: + case CIL_SENSITIVITYORDER: +- case CIL_EXPANDTYPEATTRIBUTE: + break; /* Nothing to reset */ + default: + break; +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Use-AST-to-track-blocks-and-optionals-w.patch b/backport-libsepol-cil-Use-AST-to-track-blocks-and-optionals-w.patch new file mode 100644 index 0000000000000000000000000000000000000000..5048dc1b7a4714d1c6d850ef9a71a91e8ed92d66 --- /dev/null +++ b/backport-libsepol-cil-Use-AST-to-track-blocks-and-optionals-w.patch @@ -0,0 +1,249 @@ +From 525f0312d51d3afd48f5e0cd8a58cced3532cfdf Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 30 Mar 2021 13:39:15 -0400 +Subject: [PATCH] libsepol/cil: Use AST to track blocks and optionals when + resolving + +When resolving the AST, block and optional stacks are used to +determine if the current rule being resolved is in a block or +an optional. There is no need to do this since the parent node +pointers can be used when exiting a block or an optional to +determine if resolution is still within a block or an optional. + +When entering either a block or an optional, update the appropriate +tree node pointer. When finished with the last child of a block or +optional, set the appropriate pointer to NULL. If a parent of the +same kind is found when the parent node pointers are followed back +to the root node, then set the pointer to that tree node. + +Signed-off-by: James Carter +--- + 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 63beed9..a61462d 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; +@@ -3777,16 +3777,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)); +@@ -3795,7 +3795,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; +@@ -3849,11 +3849,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)); +@@ -3876,39 +3876,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) { +@@ -3927,7 +3906,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; +@@ -3938,30 +3916,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; +@@ -3970,16 +3949,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; +@@ -3994,7 +3963,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; +@@ -4003,7 +3973,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); +@@ -4107,17 +4076,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; + } + } + +@@ -4128,8 +4087,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); +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Use-CIL_ERR-for-error-messages-in-cil_c.patch b/backport-libsepol-cil-Use-CIL_ERR-for-error-messages-in-cil_c.patch new file mode 100644 index 0000000000000000000000000000000000000000..4f40e353a9657495164b7341ed64cc48a12564fa --- /dev/null +++ b/backport-libsepol-cil-Use-CIL_ERR-for-error-messages-in-cil_c.patch @@ -0,0 +1,58 @@ +From 8314076cd9cd71ee7ee3c5e668c1f0472ea8b815 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Tue, 30 Mar 2021 13:40:02 -0400 +Subject: [PATCH] libsepol/cil: Use CIL_ERR for error messages in cil_compile() + +In cil_compile(), CIL_INFO is being used as the priority for +error messages. This can make it difficult to tell when the error +occurred. + +Instead, use CIL_ERR as the priority for the error messages in +cil_compile(). + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c +index 99c8e28..b971922 100644 +--- a/libsepol/cil/src/cil.c ++++ b/libsepol/cil/src/cil.c +@@ -539,7 +539,7 @@ int cil_compile(struct cil_db *db) + cil_log(CIL_INFO, "Building AST from Parse Tree\n"); + rc = cil_build_ast(db, db->parse->root, db->ast->root); + if (rc != SEPOL_OK) { +- cil_log(CIL_INFO, "Failed to build ast\n"); ++ cil_log(CIL_ERR, "Failed to build AST\n"); + goto exit; + } + +@@ -549,21 +549,21 @@ int cil_compile(struct cil_db *db) + cil_log(CIL_INFO, "Resolving AST\n"); + rc = cil_resolve_ast(db, db->ast->root); + if (rc != SEPOL_OK) { +- cil_log(CIL_INFO, "Failed to resolve ast\n"); ++ cil_log(CIL_ERR, "Failed to resolve AST\n"); + goto exit; + } + + cil_log(CIL_INFO, "Qualifying Names\n"); + rc = cil_fqn_qualify(db->ast->root); + if (rc != SEPOL_OK) { +- cil_log(CIL_INFO, "Failed to qualify names\n"); ++ cil_log(CIL_ERR, "Failed to qualify names\n"); + goto exit; + } + + cil_log(CIL_INFO, "Compile post process\n"); + rc = cil_post_process(db); + if (rc != SEPOL_OK ) { +- cil_log(CIL_INFO, "Post process failed\n"); ++ cil_log(CIL_ERR, "Post process failed\n"); + goto exit; + } + +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Use-the-macro-FLAVOR-whenever-possible.patch b/backport-libsepol-cil-Use-the-macro-FLAVOR-whenever-possible.patch new file mode 100644 index 0000000000000000000000000000000000000000..be565790df7ed2465f6b0e37580a0e9d91d128e9 --- /dev/null +++ b/backport-libsepol-cil-Use-the-macro-FLAVOR-whenever-possible.patch @@ -0,0 +1,101 @@ +From d16a1e4647a5ef2da5238f3d7829e73ceb37e5ff Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Mon, 16 Nov 2020 17:07:02 -0500 +Subject: [PATCH] libsepol/cil: Use the macro FLAVOR() whenever possible + +In cil_symtab.h, the macro FLAVOR() is defined. It refers to the +flavor of the first node in the list of nodes that declare the datum. +(The flavors of every node should be the same.) While the macro was +used in many places, it was not used everywhere that it could be. + +Change all the remaining places to use FLAVOR(). + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil_find.c | 8 ++++---- + libsepol/cil/src/cil_post.c | 2 +- + libsepol/cil/src/cil_resolve_ast.c | 8 ++++---- + 3 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/libsepol/cil/src/cil_find.c b/libsepol/cil/src/cil_find.c +index c182406..638b675 100644 +--- a/libsepol/cil/src/cil_find.c ++++ b/libsepol/cil/src/cil_find.c +@@ -44,8 +44,8 @@ struct cil_args_find { + + static int cil_type_match_any(struct cil_symtab_datum *d1, struct cil_symtab_datum *d2) + { +- enum cil_flavor f1 = ((struct cil_tree_node*)d1->nodes->head->data)->flavor; +- enum cil_flavor f2 = ((struct cil_tree_node*)d2->nodes->head->data)->flavor; ++ enum cil_flavor f1 = FLAVOR(d1); ++ enum cil_flavor f2 = FLAVOR(d2); + + if (f1 != CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) { + struct cil_type *t1 = (struct cil_type *)d1; +@@ -81,8 +81,8 @@ static int cil_type_match_any(struct cil_symtab_datum *d1, struct cil_symtab_dat + static int cil_type_matches(ebitmap_t *matches, struct cil_symtab_datum *d1, struct cil_symtab_datum *d2) + { + int rc = SEPOL_OK; +- enum cil_flavor f1 = ((struct cil_tree_node*)d1->nodes->head->data)->flavor; +- enum cil_flavor f2 = ((struct cil_tree_node*)d2->nodes->head->data)->flavor; ++ enum cil_flavor f1 = FLAVOR(d1); ++ enum cil_flavor f2 = FLAVOR(d2); + + if (f1 != CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) { + struct cil_type *t1 = (struct cil_type *)d1; +diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c +index a0cadfd..37a4441 100644 +--- a/libsepol/cil/src/cil_post.c ++++ b/libsepol/cil/src/cil_post.c +@@ -1482,7 +1482,7 @@ static void __mark_neverallow_attrs(struct cil_list *expr_list) + + cil_list_for_each(curr, expr_list) { + if (curr->flavor == CIL_DATUM) { +- if (NODE(curr->data)->flavor == CIL_TYPEATTRIBUTE) { ++ if (FLAVOR(curr->data) == CIL_TYPEATTRIBUTE) { + struct cil_typeattribute *attr = curr->data; + if (strstr(DATUM(attr)->name, TYPEATTR_INFIX)) { + __mark_neverallow_attrs(attr->expr_list); +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 060bc0d..f6deb10 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -505,7 +505,7 @@ int cil_resolve_aliasactual(struct cil_tree_node *current, void *extra_args, enu + if (rc != SEPOL_OK) { + goto exit; + } +- if (NODE(alias_datum)->flavor != alias_flavor) { ++ if (FLAVOR(alias_datum) != alias_flavor) { + cil_log(CIL_ERR, "%s is not an alias\n",alias_datum->name); + rc = SEPOL_ERR; + goto exit; +@@ -516,7 +516,7 @@ int cil_resolve_aliasactual(struct cil_tree_node *current, void *extra_args, enu + goto exit; + } + +- if (NODE(actual_datum)->flavor != flavor && NODE(actual_datum)->flavor != alias_flavor) { ++ if (FLAVOR(actual_datum) != flavor && FLAVOR(actual_datum) != alias_flavor) { + cil_log(CIL_ERR, "%s is a %s, but aliases a %s\n", alias_datum->name, cil_node_to_string(NODE(alias_datum)), cil_node_to_string(NODE(actual_datum))); + rc = SEPOL_ERR; + goto exit; +@@ -2573,7 +2573,7 @@ int cil_resolve_bounds(struct cil_tree_node *current, void *extra_args, enum cil + if (rc != SEPOL_OK) { + goto exit; + } +- if (NODE(parent_datum)->flavor == attr_flavor) { ++ if (FLAVOR(parent_datum) == attr_flavor) { + cil_log(CIL_ERR, "Bounds parent %s is an attribute\n", bounds->parent_str); + rc = SEPOL_ERR; + goto exit; +@@ -2584,7 +2584,7 @@ int cil_resolve_bounds(struct cil_tree_node *current, void *extra_args, enum cil + if (rc != SEPOL_OK) { + goto exit; + } +- if (NODE(child_datum)->flavor == attr_flavor) { ++ if (FLAVOR(child_datum) == attr_flavor) { + cil_log(CIL_ERR, "Bounds child %s is an attribute\n", bounds->child_str); + rc = SEPOL_ERR; + goto exit; +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-Use-the-macro-NODE-whenever-possible.patch b/backport-libsepol-cil-Use-the-macro-NODE-whenever-possible.patch new file mode 100644 index 0000000000000000000000000000000000000000..24fd8da80ae09eeda3ccc89d75a6c8f0735d6693 --- /dev/null +++ b/backport-libsepol-cil-Use-the-macro-NODE-whenever-possible.patch @@ -0,0 +1,305 @@ +From 2aac859a9542f9f7a05b3763ee2ef7071760f401 Mon Sep 17 00:00:00 2001 +From: James Carter +Date: Mon, 16 Nov 2020 17:07:01 -0500 +Subject: [PATCH] libsepol/cil: Use the macro NODE() whenever possible + +In cil_symtab.h, the macro NODE() is defined. It refers to the first +node in the list of nodes that declare that datum. (It is rare for +a datum to have more than one node in this list.) While the macro was +used in many places, it was not used everywhere that it could be. + +Change all the remaining places to use NODE(). + +Signed-off-by: James Carter +--- + libsepol/cil/src/cil.c | 2 +- + libsepol/cil/src/cil_binary.c | 12 ++++++------ + libsepol/cil/src/cil_find.c | 2 +- + libsepol/cil/src/cil_resolve_ast.c | 40 +++++++++++++++++++------------------- + libsepol/cil/src/cil_tree.c | 2 +- + 5 files changed, 29 insertions(+), 29 deletions(-) + +diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c +index 95bdb5e..bb7f06d 100644 +--- a/libsepol/cil/src/cil.c ++++ b/libsepol/cil/src/cil.c +@@ -1380,7 +1380,7 @@ static int cil_cats_to_ebitmap(struct cil_cats *cats, struct ebitmap* cats_ebitm + } + + cil_list_for_each(i, cats->datum_expr) { +- node = DATUM(i->data)->nodes->head->data; ++ node = NODE(i->data); + if (node->flavor == CIL_CATSET) { + cs = (struct cil_catset*)i->data; + cil_list_for_each(j, cs->cats->datum_expr) { +diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c +index e417c5c..3b01ade 100644 +--- a/libsepol/cil/src/cil_binary.c ++++ b/libsepol/cil/src/cil_binary.c +@@ -147,7 +147,7 @@ static int __cil_get_sepol_level_datum(policydb_t *pdb, struct cil_symtab_datum + + static int __cil_expand_user(struct cil_symtab_datum *datum, ebitmap_t *new) + { +- struct cil_tree_node *node = datum->nodes->head->data; ++ struct cil_tree_node *node = NODE(datum); + struct cil_user *user = NULL; + struct cil_userattribute *attr = NULL; + +@@ -175,7 +175,7 @@ exit: + + static int __cil_expand_role(struct cil_symtab_datum *datum, ebitmap_t *new) + { +- struct cil_tree_node *node = datum->nodes->head->data; ++ struct cil_tree_node *node = NODE(datum); + + if (node->flavor == CIL_ROLEATTRIBUTE) { + struct cil_roleattribute *attr = (struct cil_roleattribute *)datum; +@@ -201,7 +201,7 @@ exit: + + static int __cil_expand_type(struct cil_symtab_datum *datum, ebitmap_t *new) + { +- struct cil_tree_node *node = datum->nodes->head->data; ++ struct cil_tree_node *node = NODE(datum); + + if (node->flavor == CIL_TYPEATTRIBUTE) { + struct cil_typeattribute *attr = (struct cil_typeattribute *)datum; +@@ -2943,7 +2943,7 @@ int __cil_cats_to_mls_level(policydb_t *pdb, struct cil_cats *cats, mls_level_t + cat_datum_t *sepol_cat = NULL; + + cil_list_for_each(i, cats->datum_expr) { +- struct cil_tree_node *node = DATUM(i->data)->nodes->head->data; ++ struct cil_tree_node *node = NODE(i->data); + if (node->flavor == CIL_CATSET) { + struct cil_list_item *j; + struct cil_catset *cs = i->data; +@@ -3701,7 +3701,7 @@ int __cil_node_to_policydb(struct cil_tree_node *node, void *extra_args) + type_value_to_cil = args->type_value_to_cil; + + if (node->flavor >= CIL_MIN_DECLARATIVE) { +- if (node != DATUM(node->data)->nodes->head->data) { ++ if (node != NODE(node->data)) { + goto exit; + } + } +@@ -4450,7 +4450,7 @@ static void __cil_init_sepol_type_set(type_set_t *t) + static int __cil_add_sepol_type(policydb_t *pdb, const struct cil_db *db, struct cil_symtab_datum *datum, ebitmap_t *map) + { + int rc = SEPOL_ERR; +- struct cil_tree_node *n = datum->nodes->head->data; ++ struct cil_tree_node *n = NODE(datum); + type_datum_t *sepol_datum = NULL; + + if (n->flavor == CIL_TYPEATTRIBUTE) { +diff --git a/libsepol/cil/src/cil_find.c b/libsepol/cil/src/cil_find.c +index 4134242..c182406 100644 +--- a/libsepol/cil/src/cil_find.c ++++ b/libsepol/cil/src/cil_find.c +@@ -118,7 +118,7 @@ static int cil_type_matches(ebitmap_t *matches, struct cil_symtab_datum *d1, str + static int cil_self_match_any(struct cil_symtab_datum *s1, struct cil_symtab_datum *s2, struct cil_symtab_datum *t2) + { + int rc; +- struct cil_tree_node *n1 = s1->nodes->head->data; ++ struct cil_tree_node *n1 = NODE(s1); + if (n1->flavor != CIL_TYPEATTRIBUTE) { + rc = cil_type_match_any(s1, t2); + } else { +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 9e6afca..060bc0d 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -393,7 +393,7 @@ int cil_resolve_type_rule(struct cil_tree_node *current, void *extra_args) + goto exit; + } + +- result_node = result_datum->nodes->head->data; ++ result_node = NODE(result_datum); + + if (result_node->flavor != CIL_TYPE) { + cil_log(CIL_ERR, "Type rule result must be a type [%d]\n",result_node->flavor); +@@ -421,7 +421,7 @@ int cil_resolve_typeattributeset(struct cil_tree_node *current, void *extra_args + goto exit; + } + +- attr_node = attr_datum->nodes->head->data; ++ attr_node = NODE(attr_datum); + + if (attr_node->flavor != CIL_TYPEATTRIBUTE) { + rc = SEPOL_ERR; +@@ -470,7 +470,7 @@ int cil_resolve_expandtypeattribute(struct cil_tree_node *current, void *extra_a + goto exit; + } + +- attr_node = attr_datum->nodes->head->data; ++ attr_node = NODE(attr_datum); + + if (attr_node->flavor != CIL_TYPEATTRIBUTE) { + rc = SEPOL_ERR; +@@ -594,7 +594,7 @@ int cil_resolve_typepermissive(struct cil_tree_node *current, void *extra_args) + goto exit; + } + +- type_node = type_datum->nodes->head->data; ++ type_node = NODE(type_datum); + + if (type_node->flavor != CIL_TYPE && type_node->flavor != CIL_TYPEALIAS) { + cil_log(CIL_ERR, "Typepermissive must be a type or type alias\n"); +@@ -654,7 +654,7 @@ int cil_resolve_nametypetransition(struct cil_tree_node *current, void *extra_ar + goto exit; + } + +- result_node = result_datum->nodes->head->data; ++ result_node = NODE(result_datum); + + if (result_node->flavor != CIL_TYPE && result_node->flavor != CIL_TYPEALIAS) { + cil_log(CIL_ERR, "typetransition result is not a type or type alias\n"); +@@ -855,7 +855,7 @@ int cil_resolve_userlevel(struct cil_tree_node *current, void *extra_args) + goto exit; + } + +- user_node = user_datum->nodes->head->data; ++ user_node = NODE(user_datum); + + if (user_node->flavor != CIL_USER) { + cil_log(CIL_ERR, "Userlevel must be a user\n"); +@@ -908,7 +908,7 @@ int cil_resolve_userrange(struct cil_tree_node *current, void *extra_args) + goto exit; + } + +- user_node = user_datum->nodes->head->data; ++ user_node = NODE(user_datum); + + if (user_node->flavor != CIL_USER) { + cil_log(CIL_ERR, "Userrange must be a user: %s\n", user_datum->fqn); +@@ -959,7 +959,7 @@ int cil_resolve_userprefix(struct cil_tree_node *current, void *extra_args) + goto exit; + } + +- user_node = user_datum->nodes->head->data; ++ user_node = NODE(user_datum); + + if (user_node->flavor != CIL_USER) { + cil_log(CIL_ERR, "Userprefix must be a user: %s\n", user_datum->fqn); +@@ -986,7 +986,7 @@ int cil_resolve_selinuxuser(struct cil_tree_node *current, void *extra_args) + goto exit; + } + +- user_node = user_datum->nodes->head->data; ++ user_node = NODE(user_datum); + + if (user_node->flavor != CIL_USER) { + cil_log(CIL_ERR, "Selinuxuser must be a user: %s\n", user_datum->fqn); +@@ -1079,7 +1079,7 @@ int cil_resolve_roletransition(struct cil_tree_node *current, void *extra_args) + if (rc != SEPOL_OK) { + goto exit; + } +- node = result_datum->nodes->head->data; ++ node = NODE(result_datum); + if (node->flavor != CIL_ROLE) { + rc = SEPOL_ERR; + printf("%i\n", node->flavor); +@@ -1131,7 +1131,7 @@ int cil_resolve_roleattributeset(struct cil_tree_node *current, void *extra_args + if (rc != SEPOL_OK) { + goto exit; + } +- attr_node = attr_datum->nodes->head->data; ++ attr_node = NODE(attr_datum); + + if (attr_node->flavor != CIL_ROLEATTRIBUTE) { + rc = SEPOL_ERR; +@@ -1569,7 +1569,7 @@ int cil_resolve_catorder(struct cil_tree_node *current, void *extra_args) + cil_log(CIL_ERR, "Failed to resolve category %s in categoryorder\n", (char *)curr->data); + goto exit; + } +- node = cat_datum->nodes->head->data; ++ node = NODE(cat_datum); + if (node->flavor != CIL_CAT) { + cil_log(CIL_ERR, "%s is not a category. Only categories are allowed in categoryorder statements\n", cat_datum->name); + rc = SEPOL_ERR; +@@ -1832,7 +1832,7 @@ int cil_resolve_context(struct cil_tree_node *current, struct cil_context *conte + goto exit; + } + +- node = user_datum->nodes->head->data; ++ node = NODE(user_datum); + + if (node->flavor != CIL_USER) { + cil_log(CIL_ERR, "Context user must be a user: %s\n", user_datum->fqn); +@@ -1847,7 +1847,7 @@ int cil_resolve_context(struct cil_tree_node *current, struct cil_context *conte + goto exit; + } + +- node = role_datum->nodes->head->data; ++ node = NODE(role_datum); + if (node->flavor != CIL_ROLE) { + rc = SEPOL_ERR; + cil_log(CIL_ERR, "Context role not a role: %s\n", role_datum->fqn); +@@ -1861,7 +1861,7 @@ int cil_resolve_context(struct cil_tree_node *current, struct cil_context *conte + goto exit; + } + +- node = type_datum->nodes->head->data; ++ node = NODE(type_datum); + + if (node->flavor != CIL_TYPE && node->flavor != CIL_TYPEALIAS) { + rc = SEPOL_ERR; +@@ -2311,7 +2311,7 @@ int cil_resolve_blockinherit_link(struct cil_tree_node *current, void *extra_arg + goto exit; + } + +- node = block_datum->nodes->head->data; ++ node = NODE(block_datum); + + if (node->flavor != CIL_BLOCK) { + cil_log(CIL_ERR, "%s is not a block\n", cil_node_to_string(node)); +@@ -2450,7 +2450,7 @@ int cil_resolve_blockabstract(struct cil_tree_node *current, void *extra_args) + goto exit; + } + +- block_node = block_datum->nodes->head->data; ++ block_node = NODE(block_datum); + if (block_node->flavor != CIL_BLOCK) { + cil_log(CIL_ERR, "Failed to resolve blockabstract to a block, rc: %d\n", rc); + goto exit; +@@ -2482,7 +2482,7 @@ int cil_resolve_in(struct cil_tree_node *current, void *extra_args) + goto exit; + } + +- block_node = block_datum->nodes->head->data; ++ block_node = NODE(block_datum); + + rc = cil_copy_ast(db, current, block_node); + if (rc != SEPOL_OK) { +@@ -2774,7 +2774,7 @@ int cil_resolve_call1(struct cil_tree_node *current, void *extra_args) + goto exit; + } + +- macro_node = macro_datum->nodes->head->data; ++ macro_node = NODE(macro_datum); + + if (macro_node->flavor != CIL_MACRO) { + printf("Failed to resolve %s to a macro\n", new_call->macro_str); +@@ -3367,7 +3367,7 @@ int cil_resolve_userattributeset(struct cil_tree_node *current, void *extra_args + if (rc != SEPOL_OK) { + goto exit; + } +- attr_node = attr_datum->nodes->head->data; ++ attr_node = NODE(attr_datum); + + if (attr_node->flavor != CIL_USERATTRIBUTE) { + rc = SEPOL_ERR; +diff --git a/libsepol/cil/src/cil_tree.c b/libsepol/cil/src/cil_tree.c +index b1cbda9..3ab5e86 100644 +--- a/libsepol/cil/src/cil_tree.c ++++ b/libsepol/cil/src/cil_tree.c +@@ -1688,7 +1688,7 @@ void cil_tree_print_node(struct cil_tree_node *node) + struct cil_symtab_datum *datum = ((struct cil_args*)item->data)->arg; + if (datum != NULL) { + if (datum->nodes != NULL && datum->nodes->head != NULL) { +- cil_tree_print_node((struct cil_tree_node*)datum->nodes->head->data); ++ cil_tree_print_node(NODE(datum)); + } + } else if (((struct cil_args*)item->data)->arg_str != NULL) { + switch (item->flavor) { +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-always-destroy-the-lexer-state.patch b/backport-libsepol-cil-always-destroy-the-lexer-state.patch new file mode 100644 index 0000000000000000000000000000000000000000..76bb5ef99a0b4d1e2a22c2fc7c73b5946e4e4e57 --- /dev/null +++ b/backport-libsepol-cil-always-destroy-the-lexer-state.patch @@ -0,0 +1,112 @@ +From 90809674c13c03e324dff560654d0e686c5fc46b Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Sun, 6 Dec 2020 23:29:22 +0100 +Subject: [PATCH] libsepol/cil: always destroy the lexer state + +It was found in https://github.com/google/oss-fuzz/pull/4790: +``` +Invalid token '' at line 2 of fuzz + NEW_FUNC[1/2]: 0x67fff0 in yy_get_previous_state /src/selinux/libsepol/src/../cil/src/cil_lexer.c:1143 + NEW_FUNC[2/2]: 0x6803e0 in yy_try_NUL_trans /src/selinux/libsepol/src/../cil/src/cil_lexer.c:1176 +================================================================= +==12==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000007992 at pc 0x000000681800 bp 0x7ffccddee530 sp 0x7ffccddee528 +WRITE of size 1 at 0x602000007992 thread T0 +SCARINESS: 41 (1-byte-write-heap-use-after-free) + #0 0x6817ff in cil_yy_switch_to_buffer /src/selinux/libsepol/src/../cil/src/cil_lexer.c:1315:17 + #1 0x6820cc in cil_yy_scan_buffer /src/selinux/libsepol/src/../cil/src/cil_lexer.c:1571:2 + #2 0x682662 in cil_lexer_setup /src/selinux/libsepol/src/../cil/src/cil_lexer.l:73:6 + #3 0x5cf2ae in cil_parser /src/selinux/libsepol/src/../cil/src/cil_parser.c:220:2 + #4 0x56d5e2 in cil_add_file /src/selinux/libsepol/src/../cil/src/cil.c:514:7 + #5 0x556e91 in LLVMFuzzerTestOneInput /src/secilc-fuzzer.c:434:7 + #6 0x459ab1 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:599:15 + #7 0x45a755 in fuzzer::Fuzzer::TryDetectingAMemoryLeak(unsigned char const*, unsigned long, bool) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:675:3 + #8 0x45acd9 in fuzzer::Fuzzer::MutateAndTestOne() /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:747:5 + #9 0x45b875 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector >&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:883:5 + #10 0x4499fb in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:906:6 + #11 0x473a32 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10 + #12 0x7f982296d83f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2083f) + #13 0x41e758 in _start (/out/secilc-fuzzer+0x41e758) + +DEDUP_TOKEN: cil_yy_switch_to_buffer--cil_yy_scan_buffer--cil_lexer_setup +0x602000007992 is located 2 bytes inside of 4-byte region [0x602000007990,0x602000007994) +freed by thread T0 here: + #0 0x521ef2 in free /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:127:3 + #1 0x56d630 in cil_add_file /src/selinux/libsepol/src/../cil/src/cil.c:526:2 + #2 0x556e91 in LLVMFuzzerTestOneInput /src/secilc-fuzzer.c:434:7 + #3 0x459ab1 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:599:15 + #4 0x458fba in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:505:3 + #5 0x45acc7 in fuzzer::Fuzzer::MutateAndTestOne() /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:745:19 + #6 0x45b875 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector >&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:883:5 + #7 0x4499fb in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:906:6 + #8 0x473a32 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10 + #9 0x7f982296d83f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2083f) + +DEDUP_TOKEN: free--cil_add_file--LLVMFuzzerTestOneInput +previously allocated by thread T0 here: + #0 0x52215d in malloc /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:145:3 + #1 0x5cecb8 in cil_malloc /src/selinux/libsepol/src/../cil/src/cil_mem.c:39:14 + #2 0x56d584 in cil_add_file /src/selinux/libsepol/src/../cil/src/cil.c:510:11 + #3 0x556e91 in LLVMFuzzerTestOneInput /src/secilc-fuzzer.c:434:7 + #4 0x459ab1 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:599:15 + #5 0x458fba in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:505:3 + #6 0x45acc7 in fuzzer::Fuzzer::MutateAndTestOne() /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:745:19 + #7 0x45b875 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector >&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:883:5 + #8 0x4499fb in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:906:6 + #9 0x473a32 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10 + #10 0x7f982296d83f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2083f) + +DEDUP_TOKEN: malloc--cil_malloc--cil_add_file +SUMMARY: AddressSanitizer: heap-use-after-free /src/selinux/libsepol/src/../cil/src/cil_lexer.c:1315:17 in cil_yy_switch_to_buffer +Shadow bytes around the buggy address: + 0x0c047fff8ee0: fa fa fd fa fa fa fd fd fa fa fd fa fa fa fd fd + 0x0c047fff8ef0: fa fa fd fa fa fa fd fd fa fa fd fa fa fa fd fd + 0x0c047fff8f00: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fd + 0x0c047fff8f10: fa fa fd fa fa fa fd fd fa fa fd fa fa fa fd fd + 0x0c047fff8f20: fa fa fd fa fa fa fd fd fa fa fd fa fa fa fd fa +=>0x0c047fff8f30: fa fa[fd]fa fa fa fd fa fa fa fd fa fa fa fd fa + 0x0c047fff8f40: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa + 0x0c047fff8f50: fa fa fd fa fa fa fd fd fa fa fd fa fa fa fd fa + 0x0c047fff8f60: fa fa fd fd fa fa fd fa fa fa fd fd fa fa fd fa + 0x0c047fff8f70: fa fa 00 00 fa fa 02 fa fa fa 02 fa fa fa 00 fa + 0x0c047fff8f80: fa fa 03 fa fa fa 00 fa fa fa 03 fa fa fa 00 fa +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 + Shadow gap: cc +==12==ABORTING +``` + +Signed-off-by: Evgeny Vereshchagin +Acked-by: Nicolas Iooss +--- + libsepol/cil/src/cil_parser.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/libsepol/cil/src/cil_parser.c b/libsepol/cil/src/cil_parser.c +index 585ea7704..a8af1dce2 100644 +--- a/libsepol/cil/src/cil_parser.c ++++ b/libsepol/cil/src/cil_parser.c +@@ -310,6 +310,7 @@ int cil_parser(char *_path, char *buffer, uint32_t size, struct cil_tree **parse + while (!cil_stack_is_empty(stack)) { + pop_hll_info(stack, &hll_lineno, &hll_expand); + } ++ cil_lexer_destroy(); + cil_stack_destroy(&stack); + + return SEPOL_ERR; diff --git a/backport-libsepol-cil-be-more-robust-when-encountering-src_in.patch b/backport-libsepol-cil-be-more-robust-when-encountering-src_in.patch new file mode 100644 index 0000000000000000000000000000000000000000..189c77e5765617005debb1dececc13fed56704cd --- /dev/null +++ b/backport-libsepol-cil-be-more-robust-when-encountering-src_in.patch @@ -0,0 +1,53 @@ +From 4662bdc11c8f505716f8da361a07ad13083b0618 Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Fri, 5 Feb 2021 10:45:38 +0100 +Subject: [PATCH] libsepol/cil: be more robust when encountering + +OSS-Fuzz found a Null-dereference READ in the CIL compiler when trying +to compile the following policy: + + () + +In cil_gen_src_info(), parse_current->next is NULL even though the code +expects that both parse_current->next and parse_current->next->next +exists. + +Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28457 +Signed-off-by: Nicolas Iooss +--- + libsepol/cil/src/cil_build_ast.c | 5 +++++ + libsepol/cil/src/cil_tree.c | 2 +- + 2 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index 5094d62..726f46c 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -6070,6 +6070,11 @@ int cil_gen_src_info(struct cil_tree_node *parse_current, struct cil_tree_node * + /* No need to check syntax, because this is auto generated */ + struct cil_src_info *info = NULL; + ++ if (parse_current->next == NULL || parse_current->next->next == NULL) { ++ cil_tree_log(parse_current, CIL_ERR, "Bad "); ++ return SEPOL_ERR; ++ } ++ + cil_src_info_init(&info); + + info->is_cil = (parse_current->next->data == CIL_KEY_SRC_CIL) ? CIL_TRUE : CIL_FALSE; +diff --git a/libsepol/cil/src/cil_tree.c b/libsepol/cil/src/cil_tree.c +index 886412d..3da972e 100644 +--- a/libsepol/cil/src/cil_tree.c ++++ b/libsepol/cil/src/cil_tree.c +@@ -69,7 +69,7 @@ struct cil_tree_node *cil_tree_get_next_path(struct cil_tree_node *node, char ** + + while (node) { + if (node->flavor == CIL_NODE && node->data == NULL) { +- if (node->cl_head->data == CIL_KEY_SRC_INFO) { ++ if (node->cl_head->data == CIL_KEY_SRC_INFO && node->cl_head->next != NULL && node->cl_head->next->next != NULL) { + /* Parse Tree */ + *path = node->cl_head->next->next->data; + *is_cil = (node->cl_head->next->data == CIL_KEY_SRC_CIL); +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-destroy-perm_datums-when-_cil_resolve_.patch b/backport-libsepol-cil-destroy-perm_datums-when-_cil_resolve_.patch new file mode 100644 index 0000000000000000000000000000000000000000..657be190513b6a4efc02b9c6df33411be93c1579 --- /dev/null +++ b/backport-libsepol-cil-destroy-perm_datums-when-_cil_resolve_.patch @@ -0,0 +1,36 @@ +From b7ea65f547c67bfbae4ae133052583b090747e5a Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Wed, 30 Dec 2020 11:07:46 +0100 +Subject: [PATCH] libsepol/cil: destroy perm_datums when __cil_resolve_perms + fails + +When __cil_resolve_perms fails, it does not destroy perm_datums, which +leads to a memory leak reported by OSS-Fuzz with the following CIL +policy: + + (class cl01()) + (classorder(cl01)) + (type at02) + (type tpr3) + (allow at02 tpr3(cl01((s)))) + +Calling cil_list_destroy() fixes the issue. + +Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28466 +Signed-off-by: Nicolas Iooss +--- + libsepol/cil/src/cil_resolve_ast.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 68b590bcc..0c85eabe5 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -146,6 +146,7 @@ static int __cil_resolve_perms(symtab_t *class_symtab, symtab_t *common_symtab, + return SEPOL_OK; + + exit: ++ cil_list_destroy(perm_datums, CIL_FALSE); + return rc; + } + diff --git a/backport-libsepol-cil-do-not-add-a-stack-variable-to-a-list.patch b/backport-libsepol-cil-do-not-add-a-stack-variable-to-a-list.patch new file mode 100644 index 0000000000000000000000000000000000000000..079cc11a2cf1a0062250946776bde5b727802037 --- /dev/null +++ b/backport-libsepol-cil-do-not-add-a-stack-variable-to-a-list.patch @@ -0,0 +1,39 @@ +From 6c8fca10452e445edf52daffc69f2e9dfcdac54c Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Wed, 30 Dec 2020 21:11:40 +0100 +Subject: [PATCH] libsepol/cil: do not add a stack variable to a list + +OSS-Fuzz found a heap use-after-free when the CIL compiler destroys its +database after failing to compile the following policy: + + (validatetrans x (eq t3 (a))) + +This is caused by the fact that the validatetrans AST object references +a stack variable local to __cil_fill_constraint_leaf_expr, when parsing +the list "(a)": + + struct cil_list *sub_list; + cil_fill_list(current->next->next->cl_head, leaf_expr_flavor, &sub_list); + cil_list_append(*leaf_expr, CIL_LIST, &sub_list); + +Drop the & sign to really add the list like it is supposed to be. + +Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28507 +Signed-off-by: Nicolas Iooss +--- + libsepol/cil/src/cil_build_ast.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index 67801def0..d5b9977c0 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -2714,7 +2714,7 @@ static int __cil_fill_constraint_leaf_expr(struct cil_tree_node *current, enum c + } else if (r_flavor == CIL_LIST) { + struct cil_list *sub_list; + cil_fill_list(current->next->next->cl_head, leaf_expr_flavor, &sub_list); +- cil_list_append(*leaf_expr, CIL_LIST, &sub_list); ++ cil_list_append(*leaf_expr, CIL_LIST, sub_list); + } else { + cil_list_append(*leaf_expr, CIL_CONS_OPERAND, (void *)r_flavor); + } diff --git a/backport-libsepol-cil-do-not-allow-0-in-quoted-strings.patch b/backport-libsepol-cil-do-not-allow-0-in-quoted-strings.patch new file mode 100644 index 0000000000000000000000000000000000000000..e0d60bf9ddff6003e2d929ec05e22f9db6986927 --- /dev/null +++ b/backport-libsepol-cil-do-not-allow-0-in-quoted-strings.patch @@ -0,0 +1,41 @@ +From af29a235531f66882e5a027e1348658b8d8c1e68 Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Mon, 12 Jul 2021 10:44:28 +0200 +Subject: [PATCH] libsepol/cil: do not allow \0 in quoted strings + +Using the '\0' character in strings in a CIL policy is not expected to +happen, and makes the flex tokenizer very slow. For example when +generating a file with: + + python -c 'print("\"" + "\0"*100000 + "\"")' > policy.cil + +secilc fails after 26 seconds, on my desktop computer. Increasing the +numbers of \0 makes this time increase significantly. But replacing \0 +with another character makes secilc fail in only few milliseconds. + +Fix this "possible denial of service" issue by forbidding \0 in strings +in CIL policies. + +Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=36016 + +Signed-off-by: Nicolas Iooss +--- + libsepol/cil/src/cil_lexer.l | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_lexer.l b/libsepol/cil/src/cil_lexer.l +index e28c33e..8bf2b6e 100644 +--- a/libsepol/cil/src/cil_lexer.l ++++ b/libsepol/cil/src/cil_lexer.l +@@ -49,7 +49,7 @@ spec_char [\[\]\.\@\=\/\*\-\_\$\%\+\-\!\|\&\^\:\~\`\#\{\}\'\<\>\?\,] + symbol ({digit}|{alpha}|{spec_char})+ + white [ \t] + newline [\n\r] +-qstring \"[^"\n]*\" ++qstring \"[^"\n\0]*\" + hll_lm ^;;\* + comment ; + +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-fix-NULL-pointer-dereference-in-__cil_i.patch b/backport-libsepol-cil-fix-NULL-pointer-dereference-in-__cil_i.patch new file mode 100644 index 0000000000000000000000000000000000000000..7b2b46dfaeb846e316c7c1a2ba9325f56ba4286f --- /dev/null +++ b/backport-libsepol-cil-fix-NULL-pointer-dereference-in-__cil_i.patch @@ -0,0 +1,42 @@ +From c5e6153720e713e72a65614f625a51ad44d1fc07 Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Sun, 14 Mar 2021 19:25:58 +0100 +Subject: [PATCH] libsepol/cil: fix NULL pointer dereference in + __cil_insert_name + +OSS-Fuzz found a Null-dereference in __cil_insert_name when trying to +compile the following policy: + + (macro MACRO () + (classmap CLASS (PERM)) + (type TYPE) + (typetransition TYPE TYPE CLASS "name" TYPE) + ) + (call MACRO) + +When using a macro with no argument, macro->params is NULL and +cil_list_for_each(item, macro->params) dereferenced a NULL pointer. +Fix this by checking that macro->params is not NULL before using it. + +Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28565 +Signed-off-by: Nicolas Iooss +--- + libsepol/cil/src/cil_resolve_ast.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 2ea106d..63beed9 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -82,7 +82,7 @@ static struct cil_name * __cil_insert_name(struct cil_db *db, hashtab_key_t key, + } else if (parent->flavor == CIL_MACRO) { + macro = parent->data; + } +- if (macro != NULL) { ++ if (macro != NULL && macro->params != NULL) { + struct cil_list_item *item; + cil_list_for_each(item, macro->params) { + if (((struct cil_param*)item->data)->str == key) { +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-fix-NULL-pointer-dereference-in-cil_fil.patch b/backport-libsepol-cil-fix-NULL-pointer-dereference-in-cil_fil.patch new file mode 100644 index 0000000000000000000000000000000000000000..7d8a1e215971438cec8e7a514148154a30ba46d1 --- /dev/null +++ b/backport-libsepol-cil-fix-NULL-pointer-dereference-in-cil_fil.patch @@ -0,0 +1,33 @@ +From 6238e025714b18db41354629dd40e70e27b7c37e Mon Sep 17 00:00:00 2001 +From: lutianxiong +Date: Thu, 25 Feb 2021 18:40:02 +0800 +Subject: [PATCH] libsepol/cil: fix NULL pointer dereference in cil_fill_ipaddr + +Found a NULL pointer dereference by fuzzing, reproducing: + $ echo "(nodecon(())o(e()))" > tmp.cil + $ secilc tmp.cil + Segmentation fault (core dumped) + +Add NULL check for addr_node->data in cil_fill_ipaddr. + +Signed-off-by: lutianxiong +--- + libsepol/cil/src/cil_build_ast.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index 726f46cd..4e53f06a 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -5660,7 +5660,7 @@ int cil_fill_ipaddr(struct cil_tree_node *addr_node, struct cil_ipaddr *addr) + { + int rc = SEPOL_ERR; + +- if (addr_node == NULL || addr == NULL) { ++ if (addr_node == NULL || addr_node->data == NULL || addr == NULL) { + goto exit; + } + +-- +2.27.0 + diff --git a/backport-libsepol-cil-fix-NULL-pointer-dereference-when-parsi.patch b/backport-libsepol-cil-fix-NULL-pointer-dereference-when-parsi.patch new file mode 100644 index 0000000000000000000000000000000000000000..7b475e8b9be87a0678fede7e731578998c95fef8 --- /dev/null +++ b/backport-libsepol-cil-fix-NULL-pointer-dereference-when-parsi.patch @@ -0,0 +1,82 @@ +From bdf4e332b41ff358b7e8539c3d6ee6277f0be762 Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Wed, 6 Jan 2021 09:13:19 +0100 +Subject: [PATCH] libsepol/cil: fix NULL pointer dereference when parsing an + improper integer + +OSS-Fuzz found a NULL pointer dereference when the CIL compiler tries to +compile a policy with an invalid integer: + + $ echo '(ioportcon(2())n)' > tmp.cil + $ secilc tmp.cil + Segmentation fault (core dumped) + +This is because strtol() is called with a NULL pointer, in +cil_fill_integer(). + +Fix this by checking that int_node->data is not NULL. While at it, use +strtoul() instead of strtol() to parse an unsigned integer. + +When using "val > UINT32_MAX" with "unsigned long val;", it is expected +that some compilers emit a warning when the size of "unsigned long" is +32 bits. In theory gcc could be such a compiler (with warning +-Wtype-limits, which is included in -Wextra). Nevertheless this is +currently broken, according to +https://gcc.gnu.org/pipermail/gcc-help/2021-January/139755.html and +https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89126 (this bug was +opened in January 2019). + +In order to prevent this warning from appearing, introduce some +preprocessor macros around the bound check. + +Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28456 +Signed-off-by: Nicolas Iooss +Acked-by: James Carter +--- + libsepol/cil/src/cil_build_ast.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index be10d61b1..02481558a 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -5570,19 +5570,27 @@ int cil_fill_integer(struct cil_tree_node *int_node, uint32_t *integer, int base + { + int rc = SEPOL_ERR; + char *endptr = NULL; +- int val; ++ unsigned long val; + +- if (int_node == NULL || integer == NULL) { ++ if (int_node == NULL || int_node->data == NULL || integer == NULL) { + goto exit; + } + + errno = 0; +- val = strtol(int_node->data, &endptr, base); ++ val = strtoul(int_node->data, &endptr, base); + if (errno != 0 || endptr == int_node->data || *endptr != '\0') { + rc = SEPOL_ERR; + goto exit; + } + ++ /* Ensure that the value fits a 32-bit integer without triggering -Wtype-limits */ ++#if ULONG_MAX > UINT32_MAX ++ if (val > UINT32_MAX) { ++ rc = SEPOL_ERR; ++ goto exit; ++ } ++#endif ++ + *integer = val; + + return SEPOL_OK; +@@ -5598,7 +5606,7 @@ int cil_fill_integer64(struct cil_tree_node *int_node, uint64_t *integer, int ba + char *endptr = NULL; + uint64_t val; + +- if (int_node == NULL || integer == NULL) { ++ if (int_node == NULL || int_node->data == NULL || integer == NULL) { + goto exit; + } + diff --git a/backport-libsepol-cil-fix-NULL-pointer-dereference-when-using.patch b/backport-libsepol-cil-fix-NULL-pointer-dereference-when-using.patch new file mode 100644 index 0000000000000000000000000000000000000000..140c6b3a9e9f05eda7e1aa6d17f3d1c0d88dfde8 --- /dev/null +++ b/backport-libsepol-cil-fix-NULL-pointer-dereference-when-using.patch @@ -0,0 +1,41 @@ +From 38a09b74024bbe1c78639821f3cff3a5ceb73d0d Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Wed, 30 Dec 2020 21:11:39 +0100 +Subject: [PATCH] libsepol/cil: fix NULL pointer dereference when using an + unused alias + +OSS-Fuzz found a NULL pointer dereference when the CIL compiler tries to +compile a policy where a categoryalias references an unused +categoryalias: + + $ echo '(categoryalias c0)(categoryalias c1)(categoryaliasactual c0 c1)' > tmp.cil + $ secil tmp.cil + Segmentation fault (core dumped) + +In such a case, a1 can become NULL in cil_resolve_alias_to_actual(). +Add a check to report an error when this occurs. Now the error message +is: + + Alias c0 references an unused alias c1 at tmp.cil:1 + +Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28471 +Signed-off-by: Nicolas Iooss +--- + libsepol/cil/src/cil_resolve_ast.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index f6deb1002..affa7657b 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -555,6 +555,10 @@ int cil_resolve_alias_to_actual(struct cil_tree_node *current, enum cil_flavor f + a1_node = a1->datum.nodes->head->data; + + while (flavor != a1_node->flavor) { ++ if (a1->actual == NULL) { ++ cil_tree_log(current, CIL_ERR, "Alias %s references an unused alias %s", alias->datum.name, a1->datum.name); ++ return SEPOL_ERR; ++ } + a1 = a1->actual; + a1_node = a1->datum.nodes->head->data; + steps += 1; diff --git a/backport-libsepol-cil-fix-out-of-bound-read-in-cil_print_recu.patch b/backport-libsepol-cil-fix-out-of-bound-read-in-cil_print_recu.patch new file mode 100644 index 0000000000000000000000000000000000000000..84fe45784c25468f40015b4e1f57628110c664d5 --- /dev/null +++ b/backport-libsepol-cil-fix-out-of-bound-read-in-cil_print_recu.patch @@ -0,0 +1,57 @@ +From 228c06d97a8a33b60b89ded17acbd0e92cca9cfe Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Wed, 30 Dec 2020 11:07:45 +0100 +Subject: [PATCH] libsepol/cil: fix out-of-bound read in + cil_print_recursive_blockinherit + +OSS-Fuzz found a heap buffer overflow (out-of-bound reads) when the CIL +compiler tries to report a recursive blockinherit with an optional +block: + + $ echo '(block b (optional o (blockinherit b)))' > tmp.cil + $ secilc tmp.cil + Segmentation fault (core dumped) + +This is because cil_print_recursive_blockinherit() assumes that all +nodes are either CIL_BLOCK or CIL_BLOCKINHERIT. Add support for other +block kinds, using cil_node_to_string() to show them. + +Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28462 +Signed-off-by: Nicolas Iooss +--- + libsepol/cil/src/cil_resolve_ast.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index affa7657b..68b590bcc 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -2347,11 +2347,13 @@ void cil_print_recursive_blockinherit(struct cil_tree_node *bi_node, struct cil_ + for (curr = bi_node; curr != terminating_node; curr = curr->parent) { + if (curr->flavor == CIL_BLOCK) { + cil_list_prepend(trace, CIL_NODE, curr); +- } else { ++ } else if (curr->flavor == CIL_BLOCKINHERIT) { + if (curr != bi_node) { + cil_list_prepend(trace, CIL_NODE, NODE(((struct cil_blockinherit *)curr->data)->block)); + } + cil_list_prepend(trace, CIL_NODE, curr); ++ } else { ++ cil_list_prepend(trace, CIL_NODE, curr); + } + } + cil_list_prepend(trace, CIL_NODE, terminating_node); +@@ -2360,8 +2362,12 @@ void cil_print_recursive_blockinherit(struct cil_tree_node *bi_node, struct cil_ + curr = item->data; + if (curr->flavor == CIL_BLOCK) { + cil_tree_log(curr, CIL_ERR, "block %s", DATUM(curr->data)->name); +- } else { ++ } else if (curr->flavor == CIL_BLOCKINHERIT) { + cil_tree_log(curr, CIL_ERR, "blockinherit %s", ((struct cil_blockinherit *)curr->data)->block_str); ++ } else if (curr->flavor == CIL_OPTIONAL) { ++ cil_tree_log(curr, CIL_ERR, "optional %s", DATUM(curr->data)->name); ++ } else { ++ cil_tree_log(curr, CIL_ERR, "%s", cil_node_to_string(curr)); + } + } + diff --git a/backport-libsepol-cil-fix-signed-overflow-caused-by-using-1-3.patch b/backport-libsepol-cil-fix-signed-overflow-caused-by-using-1-3.patch new file mode 100644 index 0000000000000000000000000000000000000000..6ab6707f0b9a893675fc04fcafb822c24ee1eae2 --- /dev/null +++ b/backport-libsepol-cil-fix-signed-overflow-caused-by-using-1-3.patch @@ -0,0 +1,92 @@ +From 521e6a2f478a4c7a7c198c017d4d12e8667d89e7 Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Sat, 3 Oct 2020 15:19:08 +0200 +Subject: [PATCH] libsepol/cil: fix signed overflow caused by using (1 << 31) - + 1 + +When compiling SELinux userspace tools with -ftrapv (this option +generates traps for signed overflow on addition, subtraction, +multiplication operations, instead of silently wrapping around), +semodule crashes when running the tests from +scripts/ci/fedora-test-runner.sh in a Fedora 32 virtual machine: + + [root@localhost selinux-testsuite]# make test + make -C policy load + make[1]: Entering directory '/root/selinux-testsuite/policy' + # Test for "expand-check = 0" in /etc/selinux/semanage.conf + # General policy build + make[2]: Entering directory '/root/selinux-testsuite/policy/test_policy' + Compiling targeted test_policy module + Creating targeted test_policy.pp policy package + rm tmp/test_policy.mod.fc + make[2]: Leaving directory '/root/selinux-testsuite/policy/test_policy' + # General policy load + domain_fd_use --> off + /usr/sbin/semodule -i test_policy/test_policy.pp test_mlsconstrain.cil test_overlay_defaultrange.cil test_add_levels.cil test_glblub.cil + make[1]: *** [Makefile:174: load] Aborted (core dumped) + +Using "coredumpctl gdb" leads to the following strack trace: + + (gdb) bt + #0 0x00007f608fe4fa25 in raise () from /lib64/libc.so.6 + #1 0x00007f608fe38895 in abort () from /lib64/libc.so.6 + #2 0x00007f6090028aca in __addvsi3.cold () from /lib64/libsepol.so.1 + #3 0x00007f6090096f59 in __avrule_xperm_setrangebits (low=30, high=30, xperms=0x8b9eea0) + at ../cil/src/cil_binary.c:1551 + #4 0x00007f60900970dd in __cil_permx_bitmap_to_sepol_xperms_list (xperms=0xb650a30, xperms_list=0x7ffce2653b18) + at ../cil/src/cil_binary.c:1596 + #5 0x00007f6090097286 in __cil_avrulex_ioctl_to_policydb (k=0xb8ec200 "@\023\214\022\006", datum=0xb650a30, + args=0x239a640) at ../cil/src/cil_binary.c:1649 + #6 0x00007f609003f1e5 in hashtab_map (h=0x41f8710, apply=0x7f60900971da <__cil_avrulex_ioctl_to_policydb>, + args=0x239a640) at hashtab.c:234 + #7 0x00007f609009ea19 in cil_binary_create_allocated_pdb (db=0x2394f10, policydb=0x239a640) + at ../cil/src/cil_binary.c:4969 + #8 0x00007f609009d19d in cil_binary_create (db=0x2394f10, policydb=0x7ffce2653d30) at ../cil/src/cil_binary.c:4329 + #9 0x00007f609008ec23 in cil_build_policydb_create_pdb (db=0x2394f10, sepol_db=0x7ffce2653d30) + at ../cil/src/cil.c:631 + #10 0x00007f608fff4bf3 in semanage_direct_commit () from /lib64/libsemanage.so.1 + #11 0x00007f608fff9fae in semanage_commit () from /lib64/libsemanage.so.1 + #12 0x0000000000403e2b in main (argc=7, argv=0x7ffce2655058) at semodule.c:753 + + (gdb) f 3 + #3 0x00007f6090096f59 in __avrule_xperm_setrangebits (low=30, high=30, xperms=0x8b9eea0) + at ../cil/src/cil_binary.c:1551 + 1551 xperms->perms[i] |= XPERM_SETBITS(h) - XPERM_SETBITS(low); + +A signed integer overflow therefore occurs in XPERM_SETBITS(h): + + #define XPERM_SETBITS(x) ((1 << (x & 0x1f)) - 1) + +This macro is expanded with h=31, so "(1 << 31) - 1" is computed: + +* (1 << 31) = -0x80000000 is the lowest signed 32-bit integer value +* (1 << 31) - 1 overflows the capacity of a signed 32-bit integer and + results in 0x7fffffff (which is unsigned) + +Using unsigned integers (with "1U") fixes the crash, as +(1U << 31) = 0x80000000U has no overflowing issues. + +Signed-off-by: Nicolas Iooss +Acked-by: Petr Lautrbach + +Conflict:remove contents of checkpolicy/policy_define.c +--- + libsepol/cil/src/cil_binary.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c +index 36720ed..e417c5c 100644 +--- a/libsepol/cil/src/cil_binary.c ++++ b/libsepol/cil/src/cil_binary.c +@@ -1526,7 +1526,7 @@ int cil_avrule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_ + /* index of the u32 containing the permission */ + #define XPERM_IDX(x) (x >> 5) + /* set bits 0 through x-1 within the u32 */ +-#define XPERM_SETBITS(x) ((1 << (x & 0x1f)) - 1) ++#define XPERM_SETBITS(x) ((1U << (x & 0x1f)) - 1) + /* low value for this u32 */ + #define XPERM_LOW(x) (x << 5) + /* high value for this u32 */ +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-follow-declaration-after-statement.patch b/backport-libsepol-cil-follow-declaration-after-statement.patch new file mode 100644 index 0000000000000000000000000000000000000000..35ad6cfce1298fe33dd0957ee3867a638fbbd360 --- /dev/null +++ b/backport-libsepol-cil-follow-declaration-after-statement.patch @@ -0,0 +1,189 @@ +From 852c4398a9a227e0eb4de42d45c0c2845ed92bc7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 8 Jun 2021 17:58:57 +0200 +Subject: [PATCH] libsepol/cil: follow declaration-after-statement +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Follow the project style of no declaration after statement. + +Found by the gcc warning -Wdeclaration-after-statement + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/cil/src/cil_binary.c | 5 +++-- + libsepol/cil/src/cil_build_ast.c | 5 +++-- + libsepol/cil/src/cil_fqn.c | 3 ++- + libsepol/cil/src/cil_list.c | 7 ++++--- + libsepol/cil/src/cil_post.c | 2 +- + libsepol/cil/src/cil_resolve_ast.c | 6 +++--- + libsepol/cil/src/cil_strpool.c | 3 ++- + 7 files changed, 18 insertions(+), 13 deletions(-) + +diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c +index 18532aa..85094b0 100644 +--- a/libsepol/cil/src/cil_binary.c ++++ b/libsepol/cil/src/cil_binary.c +@@ -593,11 +593,11 @@ exit: + int __cil_typeattr_bitmap_init(policydb_t *pdb) + { + int rc = SEPOL_ERR; ++ uint32_t i; + + pdb->type_attr_map = cil_malloc(pdb->p_types.nprim * sizeof(ebitmap_t)); + pdb->attr_type_map = cil_malloc(pdb->p_types.nprim * sizeof(ebitmap_t)); + +- uint32_t i = 0; + for (i = 0; i < pdb->p_types.nprim; i++) { + ebitmap_init(&pdb->type_attr_map[i]); + ebitmap_init(&pdb->attr_type_map[i]); +@@ -2657,6 +2657,7 @@ int __cil_constrain_expr_to_sepol_expr_helper(policydb_t *pdb, const struct cil_ + int rc = SEPOL_ERR; + struct cil_list_item *item; + enum cil_flavor flavor; ++ enum cil_flavor cil_op; + constraint_expr_t *op, *h1, *h2, *t1, *t2; + int is_leaf = CIL_FALSE; + +@@ -2673,7 +2674,7 @@ int __cil_constrain_expr_to_sepol_expr_helper(policydb_t *pdb, const struct cil_ + goto exit; + } + +- enum cil_flavor cil_op = (enum cil_flavor)(uintptr_t)item->data; ++ cil_op = (enum cil_flavor)(uintptr_t)item->data; + switch (cil_op) { + case CIL_NOT: + op->expr_type = CEXPR_NOT; +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index 96c9726..908b033 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -5173,6 +5173,7 @@ int cil_gen_macro(struct cil_db *db, struct cil_tree_node *parse_current, struct + char *key = NULL; + struct cil_macro *macro = NULL; + struct cil_tree_node *macro_content = NULL; ++ struct cil_tree_node *current_item; + enum cil_syntax syntax[] = { + CIL_SYN_STRING, + CIL_SYN_STRING, +@@ -5195,7 +5196,7 @@ int cil_gen_macro(struct cil_db *db, struct cil_tree_node *parse_current, struct + + key = parse_current->next->data; + +- struct cil_tree_node *current_item = parse_current->next->next->cl_head; ++ current_item = parse_current->next->next->cl_head; + while (current_item != NULL) { + enum cil_syntax param_syntax[] = { + CIL_SYN_STRING, +@@ -5205,6 +5206,7 @@ int cil_gen_macro(struct cil_db *db, struct cil_tree_node *parse_current, struct + int param_syntax_len = sizeof(param_syntax)/sizeof(*param_syntax); + char *kind = NULL; + struct cil_param *param = NULL; ++ struct cil_list_item *curr_param; + + rc =__cil_verify_syntax(current_item->cl_head, param_syntax, param_syntax_len); + if (rc != SEPOL_OK) { +@@ -5263,7 +5265,6 @@ int cil_gen_macro(struct cil_db *db, struct cil_tree_node *parse_current, struct + } + + //walk current list and check for duplicate parameters +- struct cil_list_item *curr_param; + cil_list_for_each(curr_param, macro->params) { + if (param->str == ((struct cil_param*)curr_param->data)->str) { + cil_log(CIL_ERR, "Duplicate parameter\n"); +diff --git a/libsepol/cil/src/cil_fqn.c b/libsepol/cil/src/cil_fqn.c +index 097222a..46db069 100644 +--- a/libsepol/cil/src/cil_fqn.c ++++ b/libsepol/cil/src/cil_fqn.c +@@ -78,12 +78,13 @@ static int __cil_fqn_qualify_blocks(__attribute__((unused)) hashtab_key_t k, has + struct cil_tree_node *node = NODE(datum); + int i; + int rc = SEPOL_OK; ++ int newlen; + + if (node->flavor != CIL_BLOCK) { + goto exit; + } + +- int newlen = fqn_args->len + strlen(datum->name) + 1; ++ newlen = fqn_args->len + strlen(datum->name) + 1; + if (newlen >= CIL_MAX_NAME_LENGTH) { + cil_log(CIL_INFO, "Fully qualified name for block %s is too long\n", datum->name); + rc = SEPOL_ERR; +diff --git a/libsepol/cil/src/cil_list.c b/libsepol/cil/src/cil_list.c +index 4e7843c..8a426f1 100644 +--- a/libsepol/cil/src/cil_list.c ++++ b/libsepol/cil/src/cil_list.c +@@ -55,15 +55,16 @@ void cil_list_init(struct cil_list **list, enum cil_flavor flavor) + + void cil_list_destroy(struct cil_list **list, unsigned destroy_data) + { ++ struct cil_list_item *item; ++ + if (*list == NULL) { + return; + } + +- struct cil_list_item *item = (*list)->head; +- struct cil_list_item *next = NULL; ++ item = (*list)->head; + while (item != NULL) + { +- next = item->next; ++ struct cil_list_item *next = item->next; + if (item->flavor == CIL_LIST) { + cil_list_destroy((struct cil_list**)&(item->data), destroy_data); + free(item); +diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c +index 05842b6..7bca083 100644 +--- a/libsepol/cil/src/cil_post.c ++++ b/libsepol/cil/src/cil_post.c +@@ -213,8 +213,8 @@ int cil_post_filecon_compare(const void *a, const void *b) + struct fc_data *a_data = cil_malloc(sizeof(*a_data)); + struct fc_data *b_data = cil_malloc(sizeof(*b_data)); + char *a_path = cil_malloc(strlen(a_filecon->path_str) + 1); +- a_path[0] = '\0'; + char *b_path = cil_malloc(strlen(b_filecon->path_str) + 1); ++ a_path[0] = '\0'; + b_path[0] = '\0'; + strcat(a_path, a_filecon->path_str); + strcat(b_path, b_filecon->path_str); +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 92a4d29..b5199ba 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -3956,10 +3956,10 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + enum cil_log_level lvl = CIL_ERR; + + if (optional != NULL) { +- lvl = CIL_INFO; +- + struct cil_optional *opt = (struct cil_optional *)optional->data; +- struct cil_tree_node *opt_node = NODE(opt);; ++ struct cil_tree_node *opt_node = NODE(opt); ++ ++ lvl = CIL_INFO; + /* 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)); +diff --git a/libsepol/cil/src/cil_strpool.c b/libsepol/cil/src/cil_strpool.c +index 2598bbf..70bca36 100644 +--- a/libsepol/cil/src/cil_strpool.c ++++ b/libsepol/cil/src/cil_strpool.c +@@ -75,9 +75,10 @@ char *cil_strpool_add(const char *str) + + strpool_ref = hashtab_search(cil_strpool_tab, (hashtab_key_t)str); + if (strpool_ref == NULL) { ++ int rc; + strpool_ref = cil_malloc(sizeof(*strpool_ref)); + strpool_ref->str = cil_strdup(str); +- int rc = hashtab_insert(cil_strpool_tab, (hashtab_key_t)strpool_ref->str, strpool_ref); ++ rc = hashtab_insert(cil_strpool_tab, (hashtab_key_t)strpool_ref->str, strpool_ref); + if (rc != SEPOL_OK) { + pthread_mutex_unlock(&cil_strpool_mutex); + cil_log(CIL_ERR, "Failed to allocate memory\n"); +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-introduce-intermediate-cast-to-silence-.patch b/backport-libsepol-cil-introduce-intermediate-cast-to-silence-.patch new file mode 100644 index 0000000000000000000000000000000000000000..262a8ffdba20cf23aa052dbd1864845f319822bf --- /dev/null +++ b/backport-libsepol-cil-introduce-intermediate-cast-to-silence-.patch @@ -0,0 +1,171 @@ +From 32f8ed3d6b0bba44f2f211ff630f61f6a17cf578 Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Fri, 5 Feb 2021 10:45:39 +0100 +Subject: [PATCH] libsepol/cil: introduce intermediate cast to silence + -Wvoid-pointer-to-enum-cast + +clang 11.0.0 reports the following warning several times (when building +with "make CC=clang" from libsepol directory, in the default +configuration of the git repository): + + ../cil/src/cil_binary.c:1980:8: error: cast to smaller integer type + 'enum cil_flavor' from 'void *' [-Werror,-Wvoid-pointer-to-enum-cast] + op = (enum cil_flavor)curr->data; + ^~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Silence this warning by casting the pointer to an integer the cast to +enum cil_flavor. + +Signed-off-by: Nicolas Iooss +--- + libsepol/cil/src/cil_binary.c | 12 ++++++------ + libsepol/cil/src/cil_policy.c | 12 ++++++------ + libsepol/cil/src/cil_post.c | 2 +- + libsepol/cil/src/cil_resolve_ast.c | 2 +- + 4 files changed, 14 insertions(+), 14 deletions(-) + +diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c +index 7ba2098..f80d846 100644 +--- a/libsepol/cil/src/cil_binary.c ++++ b/libsepol/cil/src/cil_binary.c +@@ -1977,7 +1977,7 @@ static void __cil_expr_to_string(struct cil_list *expr, enum cil_flavor flavor, + curr = expr->head; + + if (curr->flavor == CIL_OP) { +- op = (enum cil_flavor)curr->data; ++ op = (enum cil_flavor)(uintptr_t)curr->data; + + if (op == CIL_ALL) { + *out = cil_strdup(CIL_KEY_ALL); +@@ -2076,7 +2076,7 @@ static int __cil_cond_expr_to_sepol_expr_helper(policydb_t *pdb, struct cil_list + if (item == NULL) { + goto exit; + } else if (item->flavor == CIL_OP) { +- enum cil_flavor cil_op = (enum cil_flavor)item->data; ++ enum cil_flavor cil_op = (enum cil_flavor)(uintptr_t)item->data; + + op = cil_malloc(sizeof(*op)); + op->bool = 0; +@@ -2562,7 +2562,7 @@ int __cil_constrain_expr_leaf_to_sepol_expr(policydb_t *pdb, const struct cil_db + struct cil_list_item *l_item = op_item->next; + struct cil_list_item *r_item = op_item->next->next; + +- enum cil_flavor l_operand = (enum cil_flavor)l_item->data; ++ enum cil_flavor l_operand = (enum cil_flavor)(uintptr_t)l_item->data; + + switch (l_operand) { + case CIL_CONS_U1: +@@ -2593,7 +2593,7 @@ int __cil_constrain_expr_leaf_to_sepol_expr(policydb_t *pdb, const struct cil_db + expr->attr = CEXPR_TYPE | CEXPR_XTARGET; + break; + case CIL_CONS_L1: { +- enum cil_flavor r_operand = (enum cil_flavor)r_item->data; ++ enum cil_flavor r_operand = (enum cil_flavor)(uintptr_t)r_item->data; + + if (r_operand == CIL_CONS_L2) { + expr->attr = CEXPR_L1L2; +@@ -2608,7 +2608,7 @@ int __cil_constrain_expr_leaf_to_sepol_expr(policydb_t *pdb, const struct cil_db + expr->attr = CEXPR_L2H2; + break; + case CIL_CONS_H1: { +- enum cil_flavor r_operand = (enum cil_flavor)r_item->data; ++ enum cil_flavor r_operand = (enum cil_flavor)(uintptr_t)r_item->data; + if (r_operand == CIL_CONS_L2) { + expr->attr = CEXPR_H1L2; + } else { +@@ -2672,7 +2672,7 @@ int __cil_constrain_expr_to_sepol_expr_helper(policydb_t *pdb, const struct cil_ + goto exit; + } + +- enum cil_flavor cil_op = (enum cil_flavor)item->data; ++ enum cil_flavor cil_op = (enum cil_flavor)(uintptr_t)item->data; + switch (cil_op) { + case CIL_NOT: + op->expr_type = CEXPR_NOT; +diff --git a/libsepol/cil/src/cil_policy.c b/libsepol/cil/src/cil_policy.c +index 74edb34..30d507f 100644 +--- a/libsepol/cil/src/cil_policy.c ++++ b/libsepol/cil/src/cil_policy.c +@@ -285,7 +285,7 @@ static void cil_cond_expr_to_policy(FILE *out, struct cil_list *expr, int first) + struct cil_list_item *i1 = expr->head; + + if (i1->flavor == CIL_OP) { +- enum cil_flavor op = (enum cil_flavor)i1->data; ++ enum cil_flavor op = (enum cil_flavor)(uintptr_t)i1->data; + fprintf(out, "("); + switch (op) { + case CIL_NOT: +@@ -385,7 +385,7 @@ static size_t __cil_cons_leaf_operand_len(struct cil_db *db, struct cil_list_ite + + static size_t __cil_cons_leaf_op_len(struct cil_list_item *op) + { +- enum cil_flavor flavor = (enum cil_flavor)op->data; ++ enum cil_flavor flavor = (enum cil_flavor)(uintptr_t)op->data; + size_t len; + + switch (flavor) { +@@ -420,7 +420,7 @@ static size_t cil_cons_expr_len(struct cil_db *db, struct cil_list *cons_expr) + + i1 = cons_expr->head; + +- op = (enum cil_flavor)i1->data; ++ op = (enum cil_flavor)(uintptr_t)i1->data; + switch (op) { + case CIL_NOT: + len = 6; /* "(not )" */ +@@ -472,7 +472,7 @@ static char *__cil_cons_leaf_operand_to_string(struct cil_db *db, struct cil_lis + size_t o_len; + + if (flavor == CIL_CONS_OPERAND) { +- enum cil_flavor o_flavor = (enum cil_flavor)operand->data; ++ enum cil_flavor o_flavor = (enum cil_flavor)(uintptr_t)operand->data; + switch (o_flavor) { + case CIL_CONS_U1: + o_str = "u1"; +@@ -555,7 +555,7 @@ static char *__cil_cons_leaf_operand_to_string(struct cil_db *db, struct cil_lis + + static char *__cil_cons_leaf_op_to_string(struct cil_list_item *op, char *new) + { +- enum cil_flavor flavor = (enum cil_flavor)op->data; ++ enum cil_flavor flavor = (enum cil_flavor)(uintptr_t)op->data; + const char *op_str; + size_t len; + +@@ -599,7 +599,7 @@ static char *__cil_cons_expr_to_string(struct cil_db *db, struct cil_list *cons_ + + i1 = cons_expr->head; + +- op = (enum cil_flavor)i1->data; ++ op = (enum cil_flavor)(uintptr_t)i1->data; + switch (op) { + case CIL_NOT: + *new++ = '('; +diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c +index 37a4441..a55df1e 100644 +--- a/libsepol/cil/src/cil_post.c ++++ b/libsepol/cil/src/cil_post.c +@@ -1301,7 +1301,7 @@ static int __cil_expr_to_bitmap(struct cil_list *expr, ebitmap_t *out, int max, + flavor = expr->flavor; + + if (curr->flavor == CIL_OP) { +- enum cil_flavor op = (enum cil_flavor)curr->data; ++ enum cil_flavor op = (enum cil_flavor)(uintptr_t)curr->data; + + if (op == CIL_ALL) { + ebitmap_init(&b1); /* all zeros */ +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 9300cd2..208bc01 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -3355,7 +3355,7 @@ static int __cil_evaluate_tunable_expr(struct cil_list_item *curr) + return CIL_FALSE; + } else if (curr->flavor == CIL_OP) { + uint16_t v1, v2; +- enum cil_flavor op_flavor = (enum cil_flavor)curr->data; ++ enum cil_flavor op_flavor = (enum cil_flavor)(uintptr_t)curr->data; + + v1 = __cil_evaluate_tunable_expr_helper(curr->next); + +-- +1.8.3.1 + diff --git a/backport-libsepol-cil-propagate-failure-of-cil_fill_list.patch b/backport-libsepol-cil-propagate-failure-of-cil_fill_list.patch new file mode 100644 index 0000000000000000000000000000000000000000..7caf5df54f16882ed40d9387b414e72060220e4f --- /dev/null +++ b/backport-libsepol-cil-propagate-failure-of-cil_fill_list.patch @@ -0,0 +1,49 @@ +From e2d018423d5910e88947bba3b96d2f301d890c62 Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Wed, 30 Dec 2020 21:11:41 +0100 +Subject: [PATCH] libsepol/cil: propagate failure of cil_fill_list() + +OSS-Fuzz found a Null-dereference READ in the CIL compiler when trying +to compile the following policy: + + (optional o (validatetrans x (eq t3 (a ())))) + +With some logs, secilc reports: + + Invalid syntax + Destroying Parse Tree + Resolving AST + Failed to resolve validatetrans statement at fuzz:1 + Disabling optional 'o' at tmp.cil:1 + +So there is an "Invalid syntax" error, but the compilation continues. +Fix this issue by stopping the compilation when cil_fill_list() reports +an error: + + Invalid syntax + Bad expression tree for constraint + Bad validatetrans declaration at tmp.cil:1 + +Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=29061 +Signed-off-by: Nicolas Iooss +--- + libsepol/cil/src/cil_build_ast.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c +index d5b9977c0..be10d61b1 100644 +--- a/libsepol/cil/src/cil_build_ast.c ++++ b/libsepol/cil/src/cil_build_ast.c +@@ -2713,7 +2713,11 @@ static int __cil_fill_constraint_leaf_expr(struct cil_tree_node *current, enum c + cil_list_append(*leaf_expr, CIL_STRING, current->next->next->data); + } else if (r_flavor == CIL_LIST) { + struct cil_list *sub_list; +- cil_fill_list(current->next->next->cl_head, leaf_expr_flavor, &sub_list); ++ rc = cil_fill_list(current->next->next->cl_head, leaf_expr_flavor, &sub_list); ++ if (rc != SEPOL_OK) { ++ cil_list_destroy(leaf_expr, CIL_TRUE); ++ goto exit; ++ } + cil_list_append(*leaf_expr, CIL_LIST, sub_list); + } else { + cil_list_append(*leaf_expr, CIL_CONS_OPERAND, (void *)r_flavor); diff --git a/backport-libsepol-cil-replace-printf-with-proper-cil_tree_log.patch b/backport-libsepol-cil-replace-printf-with-proper-cil_tree_log.patch new file mode 100644 index 0000000000000000000000000000000000000000..36a4c0d8cd8071606c6548f6ceb52ab8b4492b55 --- /dev/null +++ b/backport-libsepol-cil-replace-printf-with-proper-cil_tree_log.patch @@ -0,0 +1,39 @@ +From 68e8871cfcbe1267ff0234a0dc78b207acc26af8 Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Sun, 14 Mar 2021 18:04:04 +0100 +Subject: [PATCH] libsepol/cil: replace printf with proper cil_tree_log + +All functions of the CIL compiler use cil_log or cil_tree_log to report +errors, but in two places which still uses printf. Replace these printf +invocation with cil_tree_log. + +Signed-off-by: Nicolas Iooss +--- + libsepol/cil/src/cil_resolve_ast.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c +index 47cdf0e..2ea106d 100644 +--- a/libsepol/cil/src/cil_resolve_ast.c ++++ b/libsepol/cil/src/cil_resolve_ast.c +@@ -2497,7 +2497,7 @@ int cil_resolve_in(struct cil_tree_node *current, void *extra_args) + + rc = cil_copy_ast(db, current, block_node); + if (rc != SEPOL_OK) { +- printf("Failed to copy in, rc: %d\n", rc); ++ cil_tree_log(current, CIL_ERR, "Failed to copy in-statement"); + goto exit; + } + +@@ -2788,7 +2788,7 @@ int cil_resolve_call1(struct cil_tree_node *current, void *extra_args) + macro_node = NODE(macro_datum); + + if (macro_node->flavor != CIL_MACRO) { +- printf("Failed to resolve %s to a macro\n", new_call->macro_str); ++ cil_tree_log(current, CIL_ERR, "Failed to resolve %s to a macro", new_call->macro_str); + rc = SEPOL_ERR; + goto exit; + } +-- +1.8.3.1 + diff --git a/backport-libsepol-do-not-modify-policy-during-write.patch b/backport-libsepol-do-not-modify-policy-during-write.patch new file mode 100644 index 0000000000000000000000000000000000000000..c2f03664f59f1447de8ae4f36d31278bc381b30a --- /dev/null +++ b/backport-libsepol-do-not-modify-policy-during-write.patch @@ -0,0 +1,49 @@ +From 2651989d3b94dd15459fbef4384f114b24850665 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Thu, 30 Jun 2022 19:03:01 +0200 +Subject: [PATCH] libsepol: do not modify policy during write +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Do not modify the in memory default_range value of a class datum while +writing a policy. + +While on it fix indentation. + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/src/write.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +diff --git a/libsepol/src/write.c b/libsepol/src/write.c +index 48ed21ea6..a9fdf93a8 100644 +--- a/libsepol/src/write.c ++++ b/libsepol/src/write.c +@@ -1097,16 +1097,18 @@ static int class_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) + p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) || + (p->policy_type == POLICY_BASE && + p->policyvers >= MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS)) { ++ char default_range = cladatum->default_range; ++ + buf[0] = cpu_to_le32(cladatum->default_user); + buf[1] = cpu_to_le32(cladatum->default_role); +- if (!glblub_version && cladatum->default_range == DEFAULT_GLBLUB) { ++ if (!glblub_version && default_range == DEFAULT_GLBLUB) { + WARN(fp->handle, +- "class %s default_range set to GLBLUB but policy version is %d (%d required), discarding", +- p->p_class_val_to_name[cladatum->s.value - 1], p->policyvers, +- p->policy_type == POLICY_KERN? POLICYDB_VERSION_GLBLUB:MOD_POLICYDB_VERSION_GLBLUB); +- cladatum->default_range = 0; +- } +- buf[2] = cpu_to_le32(cladatum->default_range); ++ "class %s default_range set to GLBLUB but policy version is %d (%d required), discarding", ++ p->p_class_val_to_name[cladatum->s.value - 1], p->policyvers, ++ p->policy_type == POLICY_KERN? POLICYDB_VERSION_GLBLUB:MOD_POLICYDB_VERSION_GLBLUB); ++ default_range = 0; ++ } ++ buf[2] = cpu_to_le32(default_range); + items = put_entry(buf, sizeof(uint32_t), 3, fp); + if (items != 3) + return POLICYDB_ERROR; diff --git a/backport-libsepol-enclose-macro-parameters-and-replacement-lists-in-parentheses.patch b/backport-libsepol-enclose-macro-parameters-and-replacement-lists-in-parentheses.patch new file mode 100644 index 0000000000000000000000000000000000000000..797f15bfdac8e15b414113db3e538d7aa4cfdb96 --- /dev/null +++ b/backport-libsepol-enclose-macro-parameters-and-replacement-lists-in-parentheses.patch @@ -0,0 +1,113 @@ +From 65b3f695be306ad8f525d4db2befd55336bd0a09 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Wed, 13 Jul 2022 15:43:43 +0200 +Subject: [PATCH] libsepol: enclose macro parameters and replacement lists in + parentheses +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libsepol/include/sepol/errcodes.h | 13 ++++++------- + libsepol/include/sepol/policydb/policydb.h | 10 +++++----- + libsepol/src/kernel_to_cil.c | 2 +- + libsepol/src/module_to_cil.c | 2 +- + libsepol/src/util.c | 2 +- + 5 files changed, 14 insertions(+), 15 deletions(-) + +diff --git a/libsepol/include/sepol/errcodes.h b/libsepol/include/sepol/errcodes.h +index 6e9ff3161..e5fe71e36 100644 +--- a/libsepol/include/sepol/errcodes.h ++++ b/libsepol/include/sepol/errcodes.h +@@ -16,15 +16,14 @@ extern "C" { + * codes that don't map to system error codes should be defined + * outside of the range of system error codes. + */ +-#define SEPOL_ERR -1 +-#define SEPOL_ENOTSUP -2 /* feature not supported in module language */ +-#define SEPOL_EREQ -3 /* requirements not met */ ++#define SEPOL_ERR (-1) ++#define SEPOL_ENOTSUP (-2) /* feature not supported in module language */ ++#define SEPOL_EREQ (-3) /* requirements not met */ + + /* Error codes that map to system error codes */ +-#define SEPOL_ENOMEM -ENOMEM +-#define SEPOL_ERANGE -ERANGE +-#define SEPOL_EEXIST -EEXIST +-#define SEPOL_ENOENT -ENOENT ++#define SEPOL_ENOMEM (-ENOMEM) ++#define SEPOL_EEXIST (-EEXIST) ++#define SEPOL_ENOENT (-ENOENT) + + #ifdef __cplusplus + } +diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h +index de0068a6c..ef1a014a5 100644 +--- a/libsepol/include/sepol/policydb/policydb.h ++++ b/libsepol/include/sepol/policydb/policydb.h +@@ -251,9 +251,9 @@ typedef struct class_perm_node { + struct class_perm_node *next; + } class_perm_node_t; + +-#define xperm_test(x, p) (1 & (p[x >> 5] >> (x & 0x1f))) +-#define xperm_set(x, p) (p[x >> 5] |= (1 << (x & 0x1f))) +-#define xperm_clear(x, p) (p[x >> 5] &= ~(1 << (x & 0x1f))) ++#define xperm_test(x, p) (1 & ((p)[(x) >> 5] >> ((x) & 0x1f))) ++#define xperm_set(x, p) ((p)[(x) >> 5] |= (1 << ((x) & 0x1f))) ++#define xperm_clear(x, p) ((p)[(x) >> 5] &= ~(1 << ((x) & 0x1f))) + #define EXTENDED_PERMS_LEN 8 + + typedef struct av_extended_perms { +@@ -795,9 +795,9 @@ extern int policydb_set_target_platform(policydb_t *p, int platform); + + #define policydb_has_boundary_feature(p) \ + (((p)->policy_type == POLICY_KERN \ +- && p->policyvers >= POLICYDB_VERSION_BOUNDARY) || \ ++ && (p)->policyvers >= POLICYDB_VERSION_BOUNDARY) || \ + ((p)->policy_type != POLICY_KERN \ +- && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY)) ++ && (p)->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY)) + + /* the config flags related to unknown classes/perms are bits 2 and 3 */ + #define DENY_UNKNOWN SEPOL_DENY_UNKNOWN +diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c +index 9128ac553..5a1336a33 100644 +--- a/libsepol/src/kernel_to_cil.c ++++ b/libsepol/src/kernel_to_cil.c +@@ -1626,7 +1626,7 @@ static int write_type_permissive_rules_to_cil(FILE *out, struct policydb *pdb) + return rc; + } + +-#define next_bit_in_range(i, p) ((i + 1 < sizeof(p)*8) && xperm_test((i + 1), p)) ++#define next_bit_in_range(i, p) (((i) + 1 < sizeof(p)*8) && xperm_test(((i) + 1), p)) + + static char *xperms_to_str(avtab_extended_perms_t *xperms) + { +diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c +index b35bf055f..b900290a7 100644 +--- a/libsepol/src/module_to_cil.c ++++ b/libsepol/src/module_to_cil.c +@@ -624,7 +624,7 @@ static int avrule_to_cil(int indent, struct policydb *pdb, uint32_t type, const + return rc; + } + +-#define next_bit_in_range(i, p) ((i + 1 < sizeof(p)*8) && xperm_test((i + 1), p)) ++#define next_bit_in_range(i, p) (((i) + 1 < sizeof(p)*8) && xperm_test(((i) + 1), p)) + + static int xperms_to_cil(const av_extended_perms_t *xperms) + { +diff --git a/libsepol/src/util.c b/libsepol/src/util.c +index 1cd1308d1..0a2edc852 100644 +--- a/libsepol/src/util.c ++++ b/libsepol/src/util.c +@@ -124,7 +124,7 @@ char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass, + return avbuf; + } + +-#define next_bit_in_range(i, p) ((i + 1 < sizeof(p)*8) && xperm_test((i + 1), p)) ++#define next_bit_in_range(i, p) (((i) + 1 < sizeof(p)*8) && xperm_test(((i) + 1), p)) + + char *sepol_extended_perms_to_string(avtab_extended_perms_t *xperms) + { diff --git a/backport-libsepol-fix-missing-double-quotes-in-typetransition-CIL-rule.patch b/backport-libsepol-fix-missing-double-quotes-in-typetransition-CIL-rule.patch new file mode 100644 index 0000000000000000000000000000000000000000..26774c53bc530740a809c30e4ea88cdbde59ee0b --- /dev/null +++ b/backport-libsepol-fix-missing-double-quotes-in-typetransition-CIL-rule.patch @@ -0,0 +1,33 @@ +From eca72d8e47ac8b962f87c46aa77fb893aa0df0f8 Mon Sep 17 00:00:00 2001 +From: Juraj Marcin +Date: Thu, 25 Aug 2022 15:27:18 +0200 +Subject: [PATCH] libsepol: fix missing double quotes in typetransition CIL + rule + +CIL Reference Guide defines typetransition rule with double quotes +around object name, but those are not present in the format string. + +This patch fixes this issue, so the CIL output produced by +sepol_kernel_policydb_to_cil() is in the correct format. + +Signed-off-by: Juraj Marcin +--- + libsepol/src/kernel_to_cil.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c +index 5a1336a330..ad4121d50a 100644 +--- a/libsepol/src/kernel_to_cil.c ++++ b/libsepol/src/kernel_to_cil.c +@@ -1854,7 +1854,7 @@ static int map_filename_trans_to_str(hashtab_key_t key, void *data, void *arg) + filename = ft->name; + new = pdb->p_type_val_to_name[datum->otype - 1]; + +- return strs_create_and_add(strs, "(typetransition %s %s %s %s %s)", 5, ++ return strs_create_and_add(strs, "(typetransition %s %s %s \"%s\" %s)", 5, + src, tgt, class, filename, new); + } + +-- +2.27.0 + diff --git a/libsepol-2.9.tar.gz b/libsepol-2.9.tar.gz deleted file mode 100644 index a914ba6f7386abaf4561e545c785574847ecb4e1..0000000000000000000000000000000000000000 Binary files a/libsepol-2.9.tar.gz and /dev/null differ diff --git a/libsepol-3.1.tar.gz b/libsepol-3.1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..f3a0710ab99b066b38f17cc1e95087a46ae5f1d8 Binary files /dev/null and b/libsepol-3.1.tar.gz differ diff --git a/libsepol.spec b/libsepol.spec index a72b59b9c57a42a62aea4d2348d66a6ed71d43b5..d7411ca9bb14b90ea05bf2010726a4d5a4d80904 100644 --- a/libsepol.spec +++ b/libsepol.spec @@ -1,10 +1,65 @@ Name: libsepol -Version: 2.9 -Release: 1 +Version: 3.1 +Release: 10 Summary: SELinux binary policy manipulation library License: LGPLv2+ URL: https://github.com/SELinuxProject/selinux/wiki/Releases -Source0: https://github.com/SELinuxProject/selinux/releases/download/20190315/libsepol-2.9.tar.gz +Source0: https://github.com/SELinuxProject/selinux/releases/download/20200710/libsepol-3.1.tar.gz + +Patch1: backport-libsepol-cil-fix-NULL-pointer-dereference-in-cil_fil.patch +Patch2: backport-libsepol-cil-always-destroy-the-lexer-state.patch +Patch3: backport-libsepol-cil-destroy-perm_datums-when-_cil_resolve_.patch +Patch4: backport-libsepol-cil-do-not-add-a-stack-variable-to-a-list.patch +Patch5: backport-libsepol-cil-Fix-heap-use-after-free-in_class-rese.patch +Patch6: backport-libsepol-cil-fix-NULL-pointer-dereference-when-parsi.patch +Patch7: backport-libsepol-cil-fix-NULL-pointer-dereference-when-using.patch +Patch8: backport-libsepol-cil-fix-out-of-bound-read-in-cil_print_recu.patch +Patch9: backport-libsepol-cil-propagate-failure-of-cil_fill_list.patch + +Patch10: backport-libsepol-cil-Use-CIL_ERR-for-error-messages-in-cil_c.patch +Patch11: backport-libsepol-cil-Detect-degenerate-inheritance-and-exit-.patch +Patch12: backport-libsepol-cil-Use-the-macro-NODE-whenever-possible.patch +Patch13: backport-libsepol-cil-Check-for-duplicate-blocks-optionals-an.patch +Patch14: backport-libsepol-cil-Refactor-helper-function-for-cil_gen_no.patch +Patch15: backport-libsepol-cil-Remove-unused-field-from-struct-cil_arg.patch +Patch16: backport-libsepol-cil-Destroy-disabled-optional-blocks-after-.patch +Patch17: backport-libsepol-cil-Use-AST-to-track-blocks-and-optionals-w.patch +Patch18: backport-libsepol-cil-Reorder-checks-for-invalid-rules-when-r.patch +Patch19: backport-libsepol-cil-replace-printf-with-proper-cil_tree_log.patch +Patch20: backport-libsepol-cil-introduce-intermediate-cast-to-silence-.patch +Patch21: backport-libsepol-cil-follow-declaration-after-statement.patch +Patch22: backport-libsepol-cil-Handle-disabled-optional-blocks-in-earl.patch +Patch23: backport-libsepol-cil-Allow-duplicate-optional-blocks-in-most.patch +Patch24: backport-libsepol-cil-Improve-degenerate-inheritance-check.patch +Patch25: backport-libsepol-cil-Improve-checking-for-bad-inheritance-pa.patch +Patch26: backport-libsepol-cil-Use-the-macro-FLAVOR-whenever-possible.patch +Patch27: backport-libsepol-cil-Check-for-empty-list-when-marking-never.patch +Patch28: backport-libsepol-cil-Fix-instances-where-an-error-returns-SE.patch +Patch29: backport-libsepol-cil-Limit-the-number-of-open-parenthesis-al.patch +Patch30: backport-libsepol-cil-Fix-syntax-checking-of-defaultrange-rul.patch +Patch31: backport-libsepol-cil-Allow-some-duplicate-macro-and-block-de.patch +Patch32: backport-libsepol-cil-fix-signed-overflow-caused-by-using-1-3.patch +Patch33: backport-libsepol-cil-Fix-potential-undefined-shifts.patch +Patch34: backport-libsepol-cil-be-more-robust-when-encountering-src_in.patch +Patch35: backport-libsepol-cil-Handle-operations-in-a-class-mapping-wh.patch +Patch36: backport-libsepol-cil-Allow-permission-expressions-when-using.patch +Patch37: backport-libsepol-cil-fix-NULL-pointer-dereference-in-__cil_i.patch +Patch38: backport-libsepol-cil-Properly-check-for-parameter-when-inser.patch +Patch39: backport-libsepol-cil-Reset-expandtypeattribute-rules-when-re.patch +Patch40: backport-libsepol-cil-do-not-allow-0-in-quoted-strings.patch +Patch41: backport-CVE-2021-36084.patch +Patch42: backport-CVE-2021-36085.patch +Patch43: backport-CVE-2021-36086.patch +Patch44: backport-libsepol-cil-Reorder-checks-for-invalid-rules-when-b.patch +Patch45: backport-libsepol-cil-Cleanup-build-AST-helper-functions.patch +Patch46: backport-libsepol-cil-Create-new-first-child-helper-function-.patch +Patch47: backport-CVE-2021-36087.patch +Patch48: backport-libsepol-avoid-potential-NULL-dereference-on-optional-parameter.patch +Patch49: backport-libsepol-check-correct-pointer-for-oom.patch +Patch50: backport-libsepol-do-not-modify-policy-during-write.patch +Patch51: backport-libsepol-enclose-macro-parameters-and-replacement-lists-in-parentheses.patch +Patch52: backport-libsepol-fix-missing-double-quotes-in-typetransition-CIL-rule.patch +Patch53: backport-libsepol-add-missing-oom-checks.patch BuildRequires: gcc flex @@ -26,7 +81,7 @@ Header files and libraries for %{name} %package_help %prep -%autosetup -n %{name}-%{version} -p1 +%autosetup -n %{name}-%{version} -p2 %build make clean @@ -40,12 +95,9 @@ make DESTDIR="%{buildroot}" LIBDIR="%{_libdir}" SHLIBDIR="%{_libdir}" install %preun -%post -/sbin/ldconfig -[ -x /sbin/telinit ] && [ -p /dev/initctl ] && /sbin/telinit U -exit 0 +%post -p /sbin/ldconfig -%postun -p /sbin/ldconfig +%postun -p /sbin/ldconfig %files %defattr(-,root,root) @@ -67,5 +119,37 @@ exit 0 %{_mandir}/man3/* %changelog +* Wed Feb 15 2023 jinlun - 3.1-10 +- backport bugfix from upstream + +* Thu Dec 15 2022 jinlun - 3.1-9 +- fix CVE-2021-36084 CVE-2021-36085 CVE-2021-36087 + +* Thu Jul 7 2022 panxiaohe - 3.1-8 +- fix CVE-2021-36086 + +* Tue Feb 15 2022 panxiaohe - 3.1-7 +- libsepol/cil: do not allow \0 in quoted strings + +* Fri Dec 10 2021 panxiaohe - 3.1-6 +- fix secilc-fuzzer issues + +* Fri Sep 10 2021 panxiaohe - 3.1-5 +- fix secilc-fuzzer issues + +* Fri May 28 2021 panxiaohe - 3.1-4 +- Drop unnecessary telinit + +* Mon Mar 15 2021 yangzhuangzhuang - 3.1-3 +- fix heap-use-after-free in cil_yy_switch_to_buffer +- fix heap-use-after-free in __class_reset_perm_values() +- fix heap-buffer-overflow in cil_print_recursive_blockinherit + +* Thu Mar 4 2021 Lirui - 3.1-2 +- fix NULL pointer dereference in cil_fill_ipaddr + +* Thu Aug 27 2020 Hugel - 3.1-1 +- update to 3.1 + * Tue Sep 10 2019 openEuler Buildteam - 2.9-1 - Package init