diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h index 9bdcbdd0..74e0b34d 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 5389df43..68909647 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;