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 <jwcart2@gmail.com>
This commit is contained in:
James Carter 2021-09-16 16:29:00 -04:00 committed by Petr Lautrbach
parent 34f7a55d7e
commit 18f8747b28

View File

@ -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;