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 <jwcart2@xxxxxxxxx> --- 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 5502c4d5..dc29ea66 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; -- 2.31.1