From d9a1b8200535387e5fb26619650a6adb06b858f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Thu, 21 Jul 2022 15:14:44 +0200 Subject: [PATCH] libsepol/cil: add support for segregate attributes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support the compile time constraint with the following syntax: (disjointattributes (attr1 attr2 [...])) and reports like: ... Qualifying Names Compile post process Building policy binary Checking Neverallows Checking Segregate Attributes Disjoint Attributes Rule violation, type test_type associated with attributes attr1 attr2 Checking User Bounds Checking Role Bounds Checking Type Bounds Failed to generate binary Failed to build policydb Signed-off-by: Christian Göttsche --- v4: rename to disjointattributes --- libsepol/cil/src/cil.c | 17 +++++++ libsepol/cil/src/cil_binary.c | 75 ++++++++++++++++++++++++++++++ libsepol/cil/src/cil_build_ast.c | 58 +++++++++++++++++++++++ libsepol/cil/src/cil_build_ast.h | 2 + libsepol/cil/src/cil_copy_ast.c | 18 +++++++ libsepol/cil/src/cil_flavor.h | 1 + libsepol/cil/src/cil_internal.h | 8 ++++ libsepol/cil/src/cil_policy.c | 26 +++++++++++ libsepol/cil/src/cil_reset_ast.c | 8 ++++ libsepol/cil/src/cil_resolve_ast.c | 38 +++++++++++++++ libsepol/cil/src/cil_resolve_ast.h | 1 + libsepol/cil/src/cil_write_ast.c | 11 +++++ libsepol/src/kernel_to_cil.c | 32 +++++++++++++ secilc/docs/README.md | 1 + secilc/docs/cil_type_statements.md | 50 ++++++++++++++++++++ 15 files changed, 346 insertions(+) diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c index 067e28a6a1..cdd4f3fc57 100644 --- a/libsepol/cil/src/cil.c +++ b/libsepol/cil/src/cil.c @@ -228,6 +228,7 @@ char *CIL_KEY_SRC_HLL_LMS; char *CIL_KEY_SRC_HLL_LMX; char *CIL_KEY_SRC_HLL_LME; char *CIL_KEY_DENY_RULE; +char *CIL_KEY_DISJOINTATTRIBUTES; static void cil_init_keys(void) { @@ -400,6 +401,7 @@ static void cil_init_keys(void) CIL_KEY_SRC_HLL_LMX = cil_strpool_add("lmx"); CIL_KEY_SRC_HLL_LME = cil_strpool_add("lme"); CIL_KEY_DENY_RULE = cil_strpool_add("deny"); + CIL_KEY_DISJOINTATTRIBUTES = cil_strpool_add("disjointattributes"); } void cil_db_init(struct cil_db **db) @@ -432,6 +434,7 @@ void cil_db_init(struct cil_db **db) cil_list_init(&(*db)->userprefixes, CIL_LIST_ITEM); cil_list_init(&(*db)->selinuxusers, CIL_LIST_ITEM); cil_list_init(&(*db)->declared_strings, CIL_LIST_ITEM); + cil_list_init(&(*db)->disjointattributes, CIL_LIST_ITEM); cil_type_init(&(*db)->selftype); (*db)->selftype->datum.name = CIL_KEY_SELF; @@ -504,6 +507,7 @@ void cil_db_destroy(struct cil_db **db) cil_sort_destroy(&(*db)->fsuse); cil_list_destroy(&(*db)->userprefixes, CIL_FALSE); cil_list_destroy(&(*db)->selinuxusers, CIL_FALSE); + cil_list_destroy(&(*db)->disjointattributes, CIL_FALSE); cil_declared_strings_list_destroy(&(*db)->declared_strings); @@ -1084,6 +1088,9 @@ void cil_destroy_data(void **data, enum cil_flavor flavor) case CIL_SRC_INFO: cil_destroy_src_info(*data); break; + case CIL_DISJOINTATTRIBUTES: + cil_destroy_disjointattributes(*data); + break; case CIL_OP: case CIL_CONS_OPERAND: break; @@ -1492,6 +1499,8 @@ const char * cil_node_to_string(struct cil_tree_node *node) return CIL_KEY_CONS_H1; case CIL_CONS_H2: return CIL_KEY_CONS_H2; + case CIL_DISJOINTATTRIBUTES: + return CIL_KEY_DISJOINTATTRIBUTES; default: break; @@ -2984,3 +2993,11 @@ void cil_src_info_init(struct cil_src_info **info) (*info)->hll_line = 0; (*info)->path = NULL; } + +void cil_disjointattributes_init(struct cil_disjointattributes **dattrs) +{ + *dattrs = cil_malloc(sizeof(**dattrs)); + + (*dattrs)->str_expr = NULL; + (*dattrs)->datum_expr = NULL; +} diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c index 95bd18baaa..96031cbe23 100644 --- a/libsepol/cil/src/cil_binary.c +++ b/libsepol/cil/src/cil_binary.c @@ -3896,6 +3896,38 @@ static int cil_defaultrange_to_policydb(policydb_t *pdb, struct cil_defaultrange return SEPOL_ERR; } +static int cil_disjointattributes_to_policydb(policydb_t *pdb, const struct cil_disjointattributes *dattrs) +{ + disjoint_attributes_rule_t *dattr; + struct cil_list_item *curr; + type_datum_t *sepol_type; + int rc = SEPOL_ERR; + + dattr = cil_malloc(sizeof(disjoint_attributes_rule_t)); + ebitmap_init(&dattr->attrs); + + cil_list_for_each(curr, dattrs->datum_expr) { + rc = __cil_get_sepol_type_datum(pdb, DATUM(curr->data), &sepol_type); + if (rc != SEPOL_OK) goto exit; + + if (ebitmap_set_bit(&dattr->attrs, sepol_type->s.value - 1, 1)) { + goto exit; + } + } + + dattr->next = pdb->disjoint_attributes; + pdb->disjoint_attributes = dattr; + + return SEPOL_OK; + +exit: + if (dattr) { + ebitmap_destroy(&dattr->attrs); + free(dattr); + } + return rc; +} + static int __cil_node_to_policydb(struct cil_tree_node *node, void *extra_args) { int rc = SEPOL_OK; @@ -4038,6 +4070,9 @@ static int __cil_node_to_policydb(struct cil_tree_node *node, void *extra_args) case CIL_DEFAULTRANGE: rc = cil_defaultrange_to_policydb(pdb, node->data); break; + case CIL_DISJOINTATTRIBUTES: + rc = cil_disjointattributes_to_policydb(pdb, node->data); + break; default: break; } @@ -4976,6 +5011,42 @@ static int cil_check_neverallows(const struct cil_db *db, policydb_t *pdb, struc return rc; } +static int cil_check_disjointattributes(const policydb_t *pdb, int *violation) +{ + const disjoint_attributes_rule_t *dattr; + + for (dattr = pdb->disjoint_attributes; dattr; dattr = dattr->next) { + ebitmap_node_t *first_node; + unsigned int first_bit; + + ebitmap_for_each_positive_bit(&dattr->attrs, first_node, first_bit) { + ebitmap_node_t *second_node; + unsigned int second_bit; + + ebitmap_for_each_positive_bit_after(&dattr->attrs, second_node, second_bit, first_node, first_bit) { + ebitmap_t attr_union; + ebitmap_node_t *type_node; + unsigned int type_bit; + + if (ebitmap_and(&attr_union, &pdb->attr_type_map[first_bit], &pdb->attr_type_map[second_bit])) + return SEPOL_ERR; + + ebitmap_for_each_positive_bit(&attr_union, type_node, type_bit) { + cil_log(CIL_ERR, "Disjoint Attributes Rule violation, type %s associated with attributes %s and %s\n", + pdb->p_type_val_to_name[type_bit], + pdb->p_type_val_to_name[first_bit], + pdb->p_type_val_to_name[second_bit]); + *violation = CIL_TRUE; + } + + ebitmap_destroy(&attr_union); + } + } + } + + return SEPOL_OK; +} + static struct cil_list *cil_classperms_from_sepol(policydb_t *pdb, uint16_t class, uint32_t data, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[]) { struct cil_classperms *cp; @@ -5246,6 +5317,10 @@ int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *p rc = cil_check_neverallows(db, pdb, neverallows, &violation); if (rc != SEPOL_OK) goto exit; + cil_log(CIL_INFO, "Checking Disjoint Attributes Rules\n"); + rc = cil_check_disjointattributes(pdb, &violation); + if (rc != SEPOL_OK) goto exit; + cil_log(CIL_INFO, "Checking User Bounds\n"); rc = bounds_check_users(NULL, pdb); if (rc) { diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c index 56dac8916f..7a155f742d 100644 --- a/libsepol/cil/src/cil_build_ast.c +++ b/libsepol/cil/src/cil_build_ast.c @@ -6108,6 +6108,62 @@ void cil_destroy_src_info(struct cil_src_info *info) free(info); } +int cil_gen_disjointattributes(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node) +{ + enum cil_syntax syntax[] = { + CIL_SYN_STRING, + CIL_SYN_LIST, + CIL_SYN_END + }; + size_t syntax_len = sizeof(syntax)/sizeof(*syntax); + struct cil_disjointattributes *dattrs = NULL; + int rc = SEPOL_ERR; + + if (db == NULL || parse_current == NULL || ast_node == NULL) { + goto exit; + } + + rc = __cil_verify_syntax(parse_current, syntax, syntax_len); + if (rc != SEPOL_OK) { + goto exit; + } + + cil_disjointattributes_init(&dattrs); + + rc = cil_gen_expr(parse_current->next, CIL_TYPEATTRIBUTE, &dattrs->str_expr); + if (rc != SEPOL_OK) { + goto exit; + } + + /* require at least two attributes */ + if (dattrs->str_expr->head == dattrs->str_expr->tail) { + rc = SEPOL_ERR; + goto exit; + } + + ast_node->data = dattrs; + ast_node->flavor = CIL_DISJOINTATTRIBUTES; + + return SEPOL_OK; + +exit: + cil_tree_log(parse_current, CIL_ERR, "Bad disjoint attributes rule declaration"); + cil_destroy_disjointattributes(dattrs); + return rc; +} + +void cil_destroy_disjointattributes(struct cil_disjointattributes *dattrs) +{ + if (dattrs == NULL) { + return; + } + + cil_list_destroy(&dattrs->str_expr, CIL_TRUE); + cil_list_destroy(&dattrs->datum_expr, CIL_FALSE); + + free(dattrs); +} + static int check_for_illegal_statement(struct cil_tree_node *parse_current, struct cil_args_build *args) { if (args->tunif != NULL) { @@ -6401,6 +6457,8 @@ static struct cil_tree_node * parse_statement(struct cil_db *db, struct cil_tree rc = cil_gen_mls(parse_current, new_ast_node); } else if (parse_current->data == CIL_KEY_SRC_INFO) { rc = cil_gen_src_info(parse_current, new_ast_node); + } else if (parse_current->data == CIL_KEY_DISJOINTATTRIBUTES) { + rc = cil_gen_disjointattributes(db, parse_current, new_ast_node); } else { cil_log(CIL_ERR, "Error: Unknown keyword %s\n", (char *)parse_current->data); rc = SEPOL_ERR; diff --git a/libsepol/cil/src/cil_build_ast.h b/libsepol/cil/src/cil_build_ast.h index 7fa4299c9e..f7d71981ab 100644 --- a/libsepol/cil/src/cil_build_ast.h +++ b/libsepol/cil/src/cil_build_ast.h @@ -222,6 +222,8 @@ int cil_gen_defaultrange(struct cil_tree_node *parse_current, struct cil_tree_no void cil_destroy_defaultrange(struct cil_defaultrange *def); int cil_gen_src_info(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node); void cil_destroy_src_info(struct cil_src_info *info); +int cil_gen_disjointattributes(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node); +void cil_destroy_disjointattributes(struct cil_disjointattributes *dattrs); int cil_fill_cats(struct cil_tree_node *curr, struct cil_cats **cats); void cil_destroy_cats(struct cil_cats *cats); diff --git a/libsepol/cil/src/cil_copy_ast.c b/libsepol/cil/src/cil_copy_ast.c index 1507edb447..d1c296ebd5 100644 --- a/libsepol/cil/src/cil_copy_ast.c +++ b/libsepol/cil/src/cil_copy_ast.c @@ -1681,6 +1681,21 @@ static int cil_copy_src_info(__attribute__((unused)) struct cil_db *db, void *da return SEPOL_OK; } +static int cil_copy_disjointattributes(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) +{ + struct cil_disjointattributes *orig = data; + struct cil_disjointattributes *new = NULL; + + cil_disjointattributes_init(&new); + + cil_copy_expr(db, orig->str_expr, &new->str_expr); + cil_copy_expr(db, orig->datum_expr, &new->datum_expr); + + *copy = new; + + return SEPOL_OK; +} + static int __cil_copy_node_helper(struct cil_tree_node *orig, uint32_t *finished, void *extra_args) { int rc = SEPOL_ERR; @@ -1977,6 +1992,9 @@ static int __cil_copy_node_helper(struct cil_tree_node *orig, uint32_t *finished case CIL_SRC_INFO: copy_func = &cil_copy_src_info; break; + case CIL_DISJOINTATTRIBUTES: + copy_func = &cil_copy_disjointattributes; + break; default: goto exit; } diff --git a/libsepol/cil/src/cil_flavor.h b/libsepol/cil/src/cil_flavor.h index 155d7c8008..e58bb7fdea 100644 --- a/libsepol/cil/src/cil_flavor.h +++ b/libsepol/cil/src/cil_flavor.h @@ -116,6 +116,7 @@ enum cil_flavor { CIL_SRC_INFO, CIL_IBPKEYCON, CIL_IBENDPORTCON, + CIL_DISJOINTATTRIBUTES, /* * boolean constraint set catset diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h index 47b67c89d9..883892184a 100644 --- a/libsepol/cil/src/cil_internal.h +++ b/libsepol/cil/src/cil_internal.h @@ -245,6 +245,7 @@ extern char *CIL_KEY_SRC_HLL_LMS; extern char *CIL_KEY_SRC_HLL_LMX; extern char *CIL_KEY_SRC_HLL_LME; extern char *CIL_KEY_DENY_RULE; +extern char *CIL_KEY_DISJOINTATTRIBUTES; /* Symbol Table Array Indices @@ -314,6 +315,7 @@ struct cil_db { struct cil_list *userprefixes; struct cil_list *selinuxusers; struct cil_list *declared_strings; + struct cil_list *disjointattributes; int num_types_and_attrs; int num_classes; int num_cats; @@ -992,6 +994,11 @@ struct cil_src_info { char *path; }; +struct cil_disjointattributes { + struct cil_list *str_expr; + struct cil_list *datum_expr; +}; + void cil_db_init(struct cil_db **db); void cil_db_destroy(struct cil_db **db); @@ -1099,5 +1106,6 @@ void cil_mls_init(struct cil_mls **mls); void cil_src_info_init(struct cil_src_info **info); void cil_userattribute_init(struct cil_userattribute **attribute); void cil_userattributeset_init(struct cil_userattributeset **attrset); +void cil_disjointattributes_init(struct cil_disjointattributes **dattrs); #endif diff --git a/libsepol/cil/src/cil_policy.c b/libsepol/cil/src/cil_policy.c index e9a8f75d82..04671f2703 100644 --- a/libsepol/cil/src/cil_policy.c +++ b/libsepol/cil/src/cil_policy.c @@ -69,6 +69,7 @@ enum cil_statement_list { CIL_LIST_USER, CIL_LIST_CONSTRAINT, CIL_LIST_VALIDATETRANS, + CIL_LIST_DISJOINTATTRIBUTES, CIL_LIST_NUM_LISTS }; @@ -168,6 +169,9 @@ static int __cil_gather_statements_helper(struct cil_tree_node *node, uint32_t * case CIL_VALIDATETRANS: kind = CIL_LIST_VALIDATETRANS; break; + case CIL_DISJOINTATTRIBUTES: + kind = CIL_LIST_DISJOINTATTRIBUTES; + break; default: break; } @@ -1910,6 +1914,27 @@ static void cil_devicetreecons_to_policy(FILE *out, struct cil_sort *devicetreec } } +static void cil_disjointattributes_to_policy(FILE *out, struct cil_list *dattrs_list) +{ + struct cil_list_item *curr_dattrs, *curr_attr; + struct cil_disjointattributes *dattrs; + int first = 1; + + cil_list_for_each(curr_dattrs, dattrs_list) { + dattrs = curr_dattrs->data; + fprintf(out, "disjoint_attributes "); + cil_list_for_each(curr_attr, dattrs->datum_expr) { + if (!first) { + first = 0; + } else { + fprintf(out, ", "); + } + fprintf(out, "%s", DATUM(curr_attr->data)->fqn); + } + fprintf(out, ";\n"); + } +} + void cil_gen_policy(FILE *out, struct cil_db *db) { unsigned i; @@ -1955,6 +1980,7 @@ void cil_gen_policy(FILE *out, struct cil_db *db) cil_typebounds_to_policy(out, lists[CIL_LIST_TYPE]); cil_typeattributes_to_policy(out, lists[CIL_LIST_TYPE], lists[CIL_LIST_TYPEATTRIBUTE]); cil_te_rules_to_policy(out, head, db->mls); + cil_disjointattributes_to_policy(out, db->disjointattributes); cil_roles_to_policy(out, lists[CIL_LIST_ROLE]); cil_role_types_to_policy(out, lists[CIL_LIST_ROLE], lists[CIL_LIST_TYPE]); diff --git a/libsepol/cil/src/cil_reset_ast.c b/libsepol/cil/src/cil_reset_ast.c index fa312c6f09..5352a76fcf 100644 --- a/libsepol/cil/src/cil_reset_ast.c +++ b/libsepol/cil/src/cil_reset_ast.c @@ -486,6 +486,11 @@ static void cil_reset_booleanif(struct cil_booleanif *bif) cil_list_destroy(&bif->datum_expr, CIL_FALSE); } +static void cil_reset_disjointattributes(struct cil_disjointattributes *dattrs) +{ + cil_list_destroy(&dattrs->datum_expr, CIL_FALSE); +} + static int __cil_reset_node(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, __attribute__((unused)) void *extra_args) { switch (node->flavor) { @@ -644,6 +649,9 @@ static int __cil_reset_node(struct cil_tree_node *node, __attribute__((unused)) case CIL_BOOLEANIF: cil_reset_booleanif(node->data); break; + case CIL_DISJOINTATTRIBUTES: + cil_reset_disjointattributes(node->data); + break; case CIL_SIDORDER: case CIL_CLASSORDER: case CIL_CATORDER: diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c index 427a320c97..dca1d89980 100644 --- a/libsepol/cil/src/cil_resolve_ast.c +++ b/libsepol/cil/src/cil_resolve_ast.c @@ -3166,6 +3166,7 @@ int cil_resolve_expr(enum cil_flavor expr_type, struct cil_list *str_expr, struc sym_index = CIL_SYM_TUNABLES; break; case CIL_TYPE: + case CIL_TYPEATTRIBUTE: sym_index = CIL_SYM_TYPES; break; case CIL_ROLE: @@ -3213,6 +3214,13 @@ int cil_resolve_expr(enum cil_flavor expr_type, struct cil_list *str_expr, struc } else { if (sym_index == CIL_SYM_TYPES && (expr_type == CIL_CONSTRAIN || expr_type == CIL_VALIDATETRANS)) { cil_type_used(res_datum, CIL_ATTR_CONSTRAINT); + } else if (expr_type == CIL_DISJOINTATTRIBUTES) { + if (FLAVOR(res_datum) != CIL_TYPEATTRIBUTE) { + cil_tree_log(parent, CIL_ERR, "Type or type alias not supported in disjoint attributes rule declaration"); + rc = SEPOL_ERR; + goto exit; + } + cil_type_used(res_datum, CIL_ATTR_NEVERALLOW); } cil_list_append(*datum_expr, CIL_DATUM, res_datum); } @@ -3404,6 +3412,33 @@ int cil_resolve_userattributeset(struct cil_tree_node *current, struct cil_db *d return rc; } +int cil_resolve_disjointattributes(struct cil_tree_node *current, struct cil_db *db) +{ + struct cil_disjointattributes *dattrs = current->data; + struct cil_list_item *first, *second; + int rc; + + rc = cil_resolve_expr(CIL_DISJOINTATTRIBUTES, dattrs->str_expr, &dattrs->datum_expr, current, db); + if (rc != SEPOL_OK) { + goto exit; + } + + cil_list_for_each(first, dattrs->datum_expr) { + for (second = first->next; second; second = second->next) { + if (first->data == second->data) { + cil_tree_log(current, CIL_ERR, "Repeated attribute in disjoint attributes rule declaration"); + rc = SEPOL_ERR; + goto exit; + } + } + } + + return SEPOL_OK; + +exit: + return rc; +} + /* * Degenerate inheritance leads to exponential growth of the policy * It can take many forms, but here is one example. @@ -3783,6 +3818,9 @@ static int __cil_resolve_ast_node(struct cil_tree_node *node, struct cil_args_re case CIL_USERATTRIBUTESET: rc = cil_resolve_userattributeset(node, db); break; + case CIL_DISJOINTATTRIBUTES: + rc = cil_resolve_disjointattributes(node, db); + break; default: break; } diff --git a/libsepol/cil/src/cil_resolve_ast.h b/libsepol/cil/src/cil_resolve_ast.h index 2f6b7e86a6..d2c5515c33 100644 --- a/libsepol/cil/src/cil_resolve_ast.h +++ b/libsepol/cil/src/cil_resolve_ast.h @@ -97,6 +97,7 @@ int cil_resolve_expr(enum cil_flavor expr_type, struct cil_list *str_expr, struc int cil_resolve_boolif(struct cil_tree_node *current, struct cil_db *db); int cil_evaluate_expr(struct cil_list *datum_expr, uint16_t *result); int cil_resolve_tunif(struct cil_tree_node *current, struct cil_db *db); +int cil_resolve_disjointattributes(struct cil_tree_node *current, struct cil_db *db); int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current); int cil_resolve_name(struct cil_tree_node *ast_node, char *name, enum cil_sym_index sym_index, struct cil_db *db, struct cil_symtab_datum **datum); diff --git a/libsepol/cil/src/cil_write_ast.c b/libsepol/cil/src/cil_write_ast.c index f4f9f16709..d944484e3f 100644 --- a/libsepol/cil/src/cil_write_ast.c +++ b/libsepol/cil/src/cil_write_ast.c @@ -1527,7 +1527,18 @@ void cil_write_ast_node(FILE *out, struct cil_tree_node *node) fprintf(out, "(ipaddr %s %s)\n", datum_to_str(&ipaddr->datum), buf); break; } + case CIL_DISJOINTATTRIBUTES: { + struct cil_disjointattributes *dattrs = node->data; + fprintf(out, "(disjointattributes "); + if (dattrs->datum_expr) + write_expr(out, dattrs->datum_expr); + else + write_expr(out, dattrs->str_expr); + fprintf(out, ")\n"); + break; + } default : + cil_log(CIL_ERR, "Unsupported flavor: %d\n", node->flavor); fprintf(out, "()\n", cil_node_to_string(node)); break; } diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c index e20ba4afad..d48f40d450 100644 --- a/libsepol/src/kernel_to_cil.c +++ b/libsepol/src/kernel_to_cil.c @@ -1968,6 +1968,33 @@ static int write_filename_trans_rules_to_cil(FILE *out, struct policydb *pdb) return rc; } +static int write_disjoint_attributes_to_cil(FILE *out, const struct policydb *pdb) +{ + const disjoint_attributes_rule_t *dattr; + + for (dattr = pdb->disjoint_attributes; dattr; dattr = dattr->next) { + struct ebitmap_node *node; + unsigned int bit; + int first = 1; + + sepol_printf(out, "(disjointattributes ("); + + ebitmap_for_each_positive_bit(&dattr->attrs, node, bit) { + if (first) { + first = 0; + } else { + sepol_printf(out, " "); + } + + sepol_printf(out, "%s", pdb->p_type_val_to_name[bit - 1]); + } + + sepol_printf(out, "))\n"); + } + + return 0; +} + static char *level_to_str(struct policydb *pdb, struct mls_level *level) { ebitmap_t *cats = &level->cat; @@ -3363,6 +3390,11 @@ int sepol_kernel_policydb_to_cil(FILE *out, struct policydb *pdb) goto exit; } + rc = write_disjoint_attributes_to_cil(out, pdb); + if (rc != 0) { + goto exit; + } + if (pdb->mls) { rc = write_range_trans_rules_to_cil(out, pdb); if (rc != 0) { diff --git a/secilc/docs/README.md b/secilc/docs/README.md index 5e00fc3b91..ce7c66716a 100644 --- a/secilc/docs/README.md +++ b/secilc/docs/README.md @@ -131,6 +131,7 @@ CIL (Common Intermediate Language) * [typemember](cil_type_statements.md#typemember) * [typetransition](cil_type_statements.md#typetransition) * [typepermissive](cil_type_statements.md#typepermissive) + * [disjointattributes](cil_type_statements.md#disjointattributes) * [User Statements](cil_user_statements.md#user-statements) * [user](cil_user_statements.md#user) diff --git a/secilc/docs/cil_type_statements.md b/secilc/docs/cil_type_statements.md index 19438417c5..2fe64c5222 100644 --- a/secilc/docs/cil_type_statements.md +++ b/secilc/docs/cil_type_statements.md @@ -601,3 +601,53 @@ This example will allow SELinux to run the `healthd.process` domain in permissiv (allow ...) ) ``` + +disjointattributes +------------------ + +Libsepol and secilc version 3.7 introduced the disjointattributes statement +to mark two or more type attributes mutual exclusive. This is a compiler +enforced action that will stop compilation until the offending associations +are modified. + +Note that these constraints can be over-ridden by the CIL compiler command +line parameter `-N` or `--disable-neverallow` flags. + +**Statement definition:** + +```secil + (disjointattributes (typeattribute_id typeattribute_id ...)) +``` + +**Where:** + + ++++ + + + + + + + + + + +

disjointattributes

The disjointattributes keyword.

typeattribute_id

A previously declared typeattribute identifier.

+

Note that the same typeattribute identifier must not be repeated.

+ +**Example:** + +This example will not compile as `type_1` is associated with type attributes `attr_1` and `attr_2`: + +```secil + (type type_1) + (typeattribute attr_1) + (typeattribute attr_2) + (typeattributeset attr_1 (type_1)) + (typeattributeset attr_2 (type_1)) + (disjointattributes (attr_1 attr_2)) +```