Message ID | 20240822003757.1998016-2-tweek@google.com (mailing list archive) |
---|---|
State | Accepted |
Commit | ba7945a250c0 |
Delegated to: | Petr Lautrbach |
Headers | show |
Series | [1/3] libsepol: Rename ioctl xperms structures and functions | expand |
On Wed, Aug 21, 2024 at 8:38 PM Thiébaud Weksteen <tweek@google.com> wrote: > > Add support for AVTAB_XPERMS_NLMSG as extended permissions for netlink > sockets. The behaviour is similar to the existing > AVTAB_XPERMS_IOCTLFUNCTION. > > Signed-off-by: Thiébaud Weksteen <tweek@google.com> Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com> (side bar: would be nice to reduce the duplicated checking/handling of "ioctl" and "nlmsg" throughout, but you didn't introduce it for ioctl so not fair to require you to fix it) > --- > checkpolicy/policy_define.c | 64 +++++++++++++++-- > checkpolicy/test/dismod.c | 2 + > libsepol/cil/src/cil.c | 2 + > libsepol/cil/src/cil_binary.c | 84 ++++++++++++++++------ > libsepol/cil/src/cil_build_ast.c | 4 +- > libsepol/cil/src/cil_internal.h | 2 + > libsepol/cil/src/cil_policy.c | 2 + > libsepol/cil/src/cil_verify.c | 3 + > libsepol/cil/src/cil_write_ast.c | 16 ++++- > libsepol/include/sepol/policydb/avtab.h | 1 + > libsepol/include/sepol/policydb/policydb.h | 1 + > libsepol/src/expand.c | 3 + > libsepol/src/kernel_to_cil.c | 21 ++++-- > libsepol/src/module_to_cil.c | 20 ++++-- > libsepol/src/policydb_validate.c | 2 + > libsepol/src/util.c | 14 ++-- > 16 files changed, 200 insertions(+), 41 deletions(-) > > diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c > index 4f6b2266..6b062657 100644 > --- a/checkpolicy/policy_define.c > +++ b/checkpolicy/policy_define.c > @@ -2342,8 +2342,8 @@ static int avrule_ioctl_completedriver(struct av_xperm_range_list *rangelist, > return 0; > } > > -static int avrule_ioctl_func(struct av_xperm_range_list *rangelist, > - av_extended_perms_t **extended_perms, unsigned int driver) > +static int avrule_xperm_func(struct av_xperm_range_list *rangelist, > + av_extended_perms_t **extended_perms, unsigned int driver, uint8_t specified) > { > struct av_xperm_range_list *r; > av_extended_perms_t *xperms; > @@ -2379,7 +2379,7 @@ static int avrule_ioctl_func(struct av_xperm_range_list *rangelist, > high = IOC_FUNC(high); > avrule_xperm_setrangebits(low, high, xperms); > xperms->driver = driver; > - xperms->specified = AVRULE_XPERMS_IOCTLFUNCTION; > + xperms->specified = specified; > r = r->next; > } > > @@ -2495,7 +2495,61 @@ static int define_te_avtab_ioctl(const avrule_t *avrule_template) > */ > i = 0; > while (xperms_for_each_bit(&i, partial_driver)) { > - if (avrule_ioctl_func(rangelist, &xperms, i)) > + if (avrule_xperm_func(rangelist, &xperms, i, AVRULE_XPERMS_IOCTLFUNCTION)) > + return -1; > + > + if (xperms) { > + avrule = (avrule_t *) calloc(1, sizeof(avrule_t)); > + if (!avrule) { > + yyerror("out of memory"); > + return -1; > + } > + if (avrule_cpy(avrule, avrule_template)) > + return -1; > + avrule->xperms = xperms; > + append_avrule(avrule); > + } > + } > + > +done: > + if (partial_driver) > + free(partial_driver); > + > + while (rangelist != NULL) { > + r = rangelist; > + rangelist = rangelist->next; > + free(r); > + } > + > + return 0; > +} > + > +static int define_te_avtab_netlink(const avrule_t *avrule_template) > +{ > + avrule_t *avrule; > + struct av_xperm_range_list *rangelist, *r; > + av_extended_perms_t *partial_driver, *xperms; > + unsigned int i; > + > + /* organize ranges */ > + if (avrule_xperm_ranges(&rangelist)) > + return -1; > + > + /* flag driver codes that are partially enabled */ > + if (avrule_xperm_partialdriver(rangelist, NULL, &partial_driver)) > + return -1; > + > + if (!partial_driver || !avrule_xperms_used(partial_driver)) > + goto done; > + > + /* > + * create rule for each partially used driver codes > + * "partially used" meaning that the code number e.g. socket 0x89 > + * has some permission bits set and others not set. > + */ > + i = 0; > + while (xperms_for_each_bit(&i, partial_driver)) { > + if (avrule_xperm_func(rangelist, &xperms, i, AVRULE_XPERMS_NLMSG)) > return -1; > > if (xperms) { > @@ -2546,6 +2600,8 @@ int define_te_avtab_extended_perms(int which) > id = queue_remove(id_queue); > if (strcmp(id,"ioctl") == 0) { > rc = define_te_avtab_ioctl(avrule_template); > + } else if (strcmp(id,"nlmsg") == 0) { > + rc = define_te_avtab_netlink(avrule_template); > } else { > yyerror2("only ioctl extended permissions are supported, found %s", id); > rc = -1; > diff --git a/checkpolicy/test/dismod.c b/checkpolicy/test/dismod.c > index bd45c95e..4868190f 100644 > --- a/checkpolicy/test/dismod.c > +++ b/checkpolicy/test/dismod.c > @@ -353,6 +353,8 @@ static int display_avrule(avrule_t * avrule, policydb_t * policy, > xperms.specified = AVTAB_XPERMS_IOCTLFUNCTION; > else if (avrule->xperms->specified == AVRULE_XPERMS_IOCTLDRIVER) > xperms.specified = AVTAB_XPERMS_IOCTLDRIVER; > + else if (avrule->xperms->specified == AVRULE_XPERMS_NLMSG) > + xperms.specified = AVTAB_XPERMS_NLMSG; > else { > fprintf(fp, " ERROR: no valid xperms specified\n"); > return -1; > diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c > index 067e28a6..5521c7ea 100644 > --- a/libsepol/cil/src/cil.c > +++ b/libsepol/cil/src/cil.c > @@ -221,6 +221,7 @@ char *CIL_KEY_DONTAUDITX; > char *CIL_KEY_NEVERALLOWX; > char *CIL_KEY_PERMISSIONX; > char *CIL_KEY_IOCTL; > +char *CIL_KEY_NLMSG; > char *CIL_KEY_UNORDERED; > char *CIL_KEY_SRC_INFO; > char *CIL_KEY_SRC_CIL; > @@ -393,6 +394,7 @@ static void cil_init_keys(void) > CIL_KEY_NEVERALLOWX = cil_strpool_add("neverallowx"); > CIL_KEY_PERMISSIONX = cil_strpool_add("permissionx"); > CIL_KEY_IOCTL = cil_strpool_add("ioctl"); > + CIL_KEY_NLMSG = cil_strpool_add("nlmsg"); > CIL_KEY_UNORDERED = cil_strpool_add("unordered"); > CIL_KEY_SRC_INFO = cil_strpool_add("<src_info>"); > CIL_KEY_SRC_CIL = cil_strpool_add("cil"); > diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c > index c8144a5a..3dec1883 100644 > --- a/libsepol/cil/src/cil_binary.c > +++ b/libsepol/cil/src/cil_binary.c > @@ -66,6 +66,7 @@ struct cil_args_binary { > int pass; > hashtab_t role_trans_table; > hashtab_t avrulex_ioctl_table; > + hashtab_t avrulex_nlmsg_table; > void **type_value_to_cil; > }; > > @@ -1671,11 +1672,22 @@ static void __avrule_xperm_setrangebits(uint16_t low, uint16_t high, struct avta > } > } > > +static char* __cil_xperm_kind_to_str(uint32_t xperm_kind) > +{ > + switch (xperm_kind) { > + case CIL_PERMX_KIND_IOCTL: > + return CIL_KEY_IOCTL; > + case CIL_PERMX_KIND_NLMSG: > + return CIL_KEY_NLMSG; > + default: > + return (char *) "unknown"; > + } > +} > > #define IOC_DRIV(x) (x >> 8) > #define IOC_FUNC(x) (x & 0xff) > > -static int __cil_permx_bitmap_to_sepol_xperms_list(ebitmap_t *xperms, struct cil_list **xperms_list) > +static int __cil_permx_bitmap_to_sepol_xperms_list(uint32_t kind, ebitmap_t *xperms, struct cil_list **xperms_list) > { > ebitmap_node_t *node; > unsigned int i; > @@ -1705,7 +1717,7 @@ static int __cil_permx_bitmap_to_sepol_xperms_list(ebitmap_t *xperms, struct cil > high = i; > start_new_range = 1; > > - if (IOC_FUNC(low) == 0x00 && IOC_FUNC(high) == 0xff) { > + if (kind == CIL_PERMX_KIND_IOCTL && IOC_FUNC(low) == 0x00 && IOC_FUNC(high) == 0xff) { > if (!complete) { > complete = cil_calloc(1, sizeof(*complete)); > complete->driver = 0x0; > @@ -1722,7 +1734,14 @@ static int __cil_permx_bitmap_to_sepol_xperms_list(ebitmap_t *xperms, struct cil > if (!partial) { > partial = cil_calloc(1, sizeof(*partial)); > partial->driver = IOC_DRIV(low); > - partial->specified = AVTAB_XPERMS_IOCTLFUNCTION; > + switch (kind) { > + case CIL_PERMX_KIND_IOCTL: > + partial->specified = AVTAB_XPERMS_IOCTLFUNCTION; > + break; > + case CIL_PERMX_KIND_NLMSG: > + partial->specified = AVTAB_XPERMS_NLMSG; > + break; > + } > } > > __avrule_xperm_setrangebits(IOC_FUNC(low), IOC_FUNC(high), partial); > @@ -1740,7 +1759,7 @@ static int __cil_permx_bitmap_to_sepol_xperms_list(ebitmap_t *xperms, struct cil > return SEPOL_OK; > } > > -static int __cil_avrulex_ioctl_to_policydb(hashtab_key_t k, hashtab_datum_t datum, void *args) > +static int __cil_avrulex_xperm_to_policydb(hashtab_key_t k, hashtab_datum_t datum, uint32_t xperm_kind, void *args) > { > int rc = SEPOL_OK; > struct policydb *pdb; > @@ -1750,6 +1769,7 @@ static int __cil_avrulex_ioctl_to_policydb(hashtab_key_t k, hashtab_datum_t datu > struct cil_list_item *item; > class_datum_t *sepol_obj; > uint32_t data = 0; > + char *kind = NULL; > > avtab_key = (avtab_key_t *)k; > pdb = args; > @@ -1759,13 +1779,14 @@ static int __cil_avrulex_ioctl_to_policydb(hashtab_key_t k, hashtab_datum_t datu > // setting the data for an extended avtab isn't really necessary because > // it is ignored by the kernel. However, neverallow checking requires that > // the data value be set, so set it for that to work. > - rc = __perm_str_to_datum(CIL_KEY_IOCTL, sepol_obj, &data); > + kind = __cil_xperm_kind_to_str(xperm_kind); > + rc = __perm_str_to_datum(kind, sepol_obj, &data); > if (rc != SEPOL_OK) { > goto exit; > } > avtab_datum.data = data; > > - rc = __cil_permx_bitmap_to_sepol_xperms_list(datum, &xperms_list); > + rc = __cil_permx_bitmap_to_sepol_xperms_list(xperm_kind, datum, &xperms_list); > if (rc != SEPOL_OK) { > goto exit; > } > @@ -1790,7 +1811,15 @@ exit: > return rc; > } > > -static int __cil_avrulex_ioctl_to_hashtable(hashtab_t h, uint16_t kind, uint32_t src, uint32_t tgt, uint32_t obj, ebitmap_t *xperms) > +static int __cil_avrulex_ioctl_to_policydb(hashtab_key_t k, hashtab_datum_t datum, void *args) { > + return __cil_avrulex_xperm_to_policydb(k, datum, CIL_PERMX_KIND_IOCTL, args); > +} > + > +static int __cil_avrulex_nlmsg_to_policydb(hashtab_key_t k, hashtab_datum_t datum, void *args) { > + return __cil_avrulex_xperm_to_policydb(k, datum, CIL_PERMX_KIND_NLMSG, args); > +} > + > +static int __cil_avrulex_xperm_to_hashtable(hashtab_t h, uint16_t kind, uint32_t src, uint32_t tgt, uint32_t obj, ebitmap_t *xperms) > { > uint16_t specified; > avtab_key_t *avtab_key; > @@ -1870,7 +1899,11 @@ static int __cil_avrulex_to_hashtable_helper(policydb_t *pdb, uint16_t kind, str > > switch (permx->kind) { > case CIL_PERMX_KIND_IOCTL: > - rc = __cil_avrulex_ioctl_to_hashtable(args->avrulex_ioctl_table, kind, sepol_src->s.value, sepol_tgt->s.value, sepol_obj->s.value, permx->perms); > + rc = __cil_avrulex_xperm_to_hashtable(args->avrulex_ioctl_table, kind, sepol_src->s.value, sepol_tgt->s.value, sepol_obj->s.value, permx->perms); > + if (rc != SEPOL_OK) goto exit; > + break; > + case CIL_PERMX_KIND_NLMSG: > + rc = __cil_avrulex_xperm_to_hashtable(args->avrulex_nlmsg_table, kind, sepol_src->s.value, sepol_tgt->s.value, sepol_obj->s.value, permx->perms); > if (rc != SEPOL_OK) goto exit; > break; > default: > @@ -2037,7 +2070,7 @@ exit: > return rc; > } > > -static int __cil_avrulex_ioctl_destroy(hashtab_key_t k, hashtab_datum_t datum, __attribute__((unused)) void *args) > +static int __cil_avrulex_xperm_destroy(hashtab_key_t k, hashtab_datum_t datum, __attribute__((unused)) void *args) > { > free(k); > ebitmap_destroy(datum); > @@ -4630,6 +4663,9 @@ static int __cil_permx_to_sepol_class_perms(policydb_t *pdb, struct cil_permissi > case CIL_PERMX_KIND_IOCTL: > perm_str = CIL_KEY_IOCTL; > break; > + case CIL_PERMX_KIND_NLMSG: > + perm_str = CIL_KEY_NLMSG; > + break; > default: > rc = SEPOL_ERR; > goto exit; > @@ -4769,17 +4805,10 @@ static void __cil_print_classperm(struct cil_list *cp_list) > > static void __cil_print_permissionx(struct cil_permissionx *px) > { > - const char *kind_str = ""; > + const char *kind_str = NULL; > char *expr_str; > > - switch (px->kind) { > - case CIL_PERMX_KIND_IOCTL: > - kind_str = CIL_KEY_IOCTL; > - break; > - default: > - kind_str = "unknown"; > - break; > - } > + kind_str = __cil_xperm_kind_to_str(px->kind); > > __cil_expr_to_string(px->expr_str, CIL_PERMISSIONX, &expr_str); > > @@ -4928,7 +4957,7 @@ static int cil_check_neverallow(const struct cil_db *db, policydb_t *pdb, struct > goto exit; > } > > - rc = __cil_permx_bitmap_to_sepol_xperms_list(cil_rule->perms.x.permx->perms, &xperms); > + rc = __cil_permx_bitmap_to_sepol_xperms_list(cil_rule->perms.x.permx->kind, cil_rule->perms.x.permx->perms, &xperms); > if (rc != SEPOL_OK) { > goto exit; > } > @@ -5137,6 +5166,7 @@ int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *p > struct cil_list *neverallows = NULL; > hashtab_t role_trans_table = NULL; > hashtab_t avrulex_ioctl_table = NULL; > + hashtab_t avrulex_nlmsg_table = NULL; > void **type_value_to_cil = NULL; > struct cil_class **class_value_to_cil = NULL; > struct cil_perm ***perm_value_to_cil = NULL; > @@ -5184,6 +5214,12 @@ int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *p > goto exit; > } > > + avrulex_nlmsg_table = hashtab_create(avrulex_hash, avrulex_compare, AVRULEX_TABLE_SIZE); > + if (!avrulex_nlmsg_table) { > + cil_log(CIL_INFO, "Failure to create hashtab for avrulex\n"); > + goto exit; > + } > + > cil_list_init(&neverallows, CIL_LIST_ITEM); > > extra_args.db = db; > @@ -5191,6 +5227,7 @@ int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *p > extra_args.neverallows = neverallows; > extra_args.role_trans_table = role_trans_table; > extra_args.avrulex_ioctl_table = avrulex_ioctl_table; > + extra_args.avrulex_nlmsg_table = avrulex_nlmsg_table; > extra_args.type_value_to_cil = type_value_to_cil; > > for (i = 1; i <= 3; i++) { > @@ -5216,6 +5253,11 @@ int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *p > cil_log(CIL_INFO, "Failure creating avrulex rules\n"); > goto exit; > } > + rc = hashtab_map(avrulex_nlmsg_table, __cil_avrulex_nlmsg_to_policydb, pdb); > + if (rc != SEPOL_OK) { > + cil_log(CIL_INFO, "Failure creating avrulex rules\n"); > + goto exit; > + } > } > } > > @@ -5287,8 +5329,10 @@ int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *p > > exit: > hashtab_destroy(role_trans_table); > - hashtab_map(avrulex_ioctl_table, __cil_avrulex_ioctl_destroy, NULL); > + hashtab_map(avrulex_ioctl_table, __cil_avrulex_xperm_destroy, NULL); > hashtab_destroy(avrulex_ioctl_table); > + hashtab_map(avrulex_nlmsg_table, __cil_avrulex_xperm_destroy, NULL); > + hashtab_destroy(avrulex_nlmsg_table); > free(type_value_to_cil); > free(class_value_to_cil); > if (perm_value_to_cil != NULL) { > diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c > index 56dac891..87178294 100644 > --- a/libsepol/cil/src/cil_build_ast.c > +++ b/libsepol/cil/src/cil_build_ast.c > @@ -2153,8 +2153,10 @@ static int cil_fill_permissionx(struct cil_tree_node *parse_current, struct cil_ > > if (parse_current->data == CIL_KEY_IOCTL) { > permx->kind = CIL_PERMX_KIND_IOCTL; > + } else if (parse_current->data == CIL_KEY_NLMSG) { > + permx->kind = CIL_PERMX_KIND_NLMSG; > } else { > - cil_log(CIL_ERR, "Unknown permissionx kind, %s. Must be \"ioctl\"\n", (char *)parse_current->data); > + cil_log(CIL_ERR, "Unknown permissionx kind, %s. Must be \"ioctl\" or \"nlmsg\"\n", (char *)parse_current->data); > rc = SEPOL_ERR; > goto exit; > } > diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h > index 47b67c89..959b31e3 100644 > --- a/libsepol/cil/src/cil_internal.h > +++ b/libsepol/cil/src/cil_internal.h > @@ -238,6 +238,7 @@ extern char *CIL_KEY_DONTAUDITX; > extern char *CIL_KEY_NEVERALLOWX; > extern char *CIL_KEY_PERMISSIONX; > extern char *CIL_KEY_IOCTL; > +extern char *CIL_KEY_NLMSG; > extern char *CIL_KEY_UNORDERED; > extern char *CIL_KEY_SRC_INFO; > extern char *CIL_KEY_SRC_CIL; > @@ -636,6 +637,7 @@ struct cil_avrule { > }; > > #define CIL_PERMX_KIND_IOCTL 1 > +#define CIL_PERMX_KIND_NLMSG 2 > struct cil_permissionx { > struct cil_symtab_datum datum; > uint32_t kind; > diff --git a/libsepol/cil/src/cil_policy.c b/libsepol/cil/src/cil_policy.c > index e9a8f75d..c497c8ab 100644 > --- a/libsepol/cil/src/cil_policy.c > +++ b/libsepol/cil/src/cil_policy.c > @@ -1112,6 +1112,8 @@ static void cil_xperms_to_policy(FILE *out, struct cil_permissionx *permx) > > if (permx->kind == CIL_PERMX_KIND_IOCTL) { > kind = "ioctl"; > + } else if (permx->kind == CIL_PERMX_KIND_NLMSG) { > + kind = "nlmsg"; > } else { > kind = "???"; > } > diff --git a/libsepol/cil/src/cil_verify.c b/libsepol/cil/src/cil_verify.c > index 4ef2cbab..9621a247 100644 > --- a/libsepol/cil/src/cil_verify.c > +++ b/libsepol/cil/src/cil_verify.c > @@ -1513,6 +1513,9 @@ static int __cil_verify_permissionx(struct cil_permissionx *permx, struct cil_tr > case CIL_PERMX_KIND_IOCTL: > kind_str = CIL_KEY_IOCTL; > break; > + case CIL_PERMX_KIND_NLMSG: > + kind_str = CIL_KEY_NLMSG; > + break; > default: > cil_tree_log(node, CIL_ERR, "Invalid permissionx kind (%d)", permx->kind); > rc = SEPOL_ERR; > diff --git a/libsepol/cil/src/cil_write_ast.c b/libsepol/cil/src/cil_write_ast.c > index 46bd84db..cd1b6e6c 100644 > --- a/libsepol/cil/src/cil_write_ast.c > +++ b/libsepol/cil/src/cil_write_ast.c > @@ -303,7 +303,13 @@ static void write_permx(FILE *out, struct cil_permissionx *permx) > fprintf(out, "%s", datum_to_str(DATUM(permx))); > } else { > fprintf(out, "("); > - fprintf(out, "%s ", permx->kind == CIL_PERMX_KIND_IOCTL ? "ioctl" : "<?KIND>"); > + if (permx->kind == CIL_PERMX_KIND_IOCTL) { > + fprintf(out, "ioctl "); > + } else if (permx->kind == CIL_PERMX_KIND_NLMSG) { > + fprintf(out, "nlmsg "); > + } else { > + fprintf(out, "<?KIND> "); > + } > fprintf(out, "%s ", datum_or_str(DATUM(permx->obj), permx->obj_str)); > write_expr(out, permx->expr_str); > fprintf(out, ")"); > @@ -825,7 +831,13 @@ void cil_write_ast_node(FILE *out, struct cil_tree_node *node) > case CIL_PERMISSIONX: { > struct cil_permissionx *permx = node->data; > fprintf(out, "(permissionx %s (", datum_to_str(DATUM(permx))); > - fprintf(out, "%s ", permx->kind == CIL_PERMX_KIND_IOCTL ? "ioctl" : "<?KIND>"); > + if (permx->kind == CIL_PERMX_KIND_IOCTL) { > + fprintf(out, "ioctl "); > + } else if (permx->kind == CIL_PERMX_KIND_NLMSG) { > + fprintf(out, "nlmsg "); > + } else { > + fprintf(out, "<?KIND> "); > + } > fprintf(out, "%s ", datum_or_str(DATUM(permx->obj), permx->obj_str)); > write_expr(out, permx->expr_str); > fprintf(out, "))\n"); > diff --git a/libsepol/include/sepol/policydb/avtab.h b/libsepol/include/sepol/policydb/avtab.h > index 2ab99c39..6e154cfe 100644 > --- a/libsepol/include/sepol/policydb/avtab.h > +++ b/libsepol/include/sepol/policydb/avtab.h > @@ -74,6 +74,7 @@ typedef struct avtab_extended_perms { > > #define AVTAB_XPERMS_IOCTLFUNCTION 0x01 > #define AVTAB_XPERMS_IOCTLDRIVER 0x02 > +#define AVTAB_XPERMS_NLMSG 0x03 > /* extension of the avtab_key specified */ > uint8_t specified; > uint8_t driver; > diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h > index 856faeb7..104a7dc8 100644 > --- a/libsepol/include/sepol/policydb/policydb.h > +++ b/libsepol/include/sepol/policydb/policydb.h > @@ -259,6 +259,7 @@ typedef struct class_perm_node { > typedef struct av_extended_perms { > #define AVRULE_XPERMS_IOCTLFUNCTION 0x01 > #define AVRULE_XPERMS_IOCTLDRIVER 0x02 > +#define AVRULE_XPERMS_NLMSG 0x03 > uint8_t specified; > uint8_t driver; > /* 256 bits of permissions */ > diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c > index e63414b1..7032a83f 100644 > --- a/libsepol/src/expand.c > +++ b/libsepol/src/expand.c > @@ -1821,6 +1821,9 @@ static int allocate_xperms(sepol_handle_t * handle, avtab_datum_t * avdatump, > case AVRULE_XPERMS_IOCTLDRIVER: > xperms->specified = AVTAB_XPERMS_IOCTLDRIVER; > break; > + case AVRULE_XPERMS_NLMSG: > + xperms->specified = AVTAB_XPERMS_NLMSG; > + break; > default: > return -1; > } > diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c > index f94cb245..7243b3c0 100644 > --- a/libsepol/src/kernel_to_cil.c > +++ b/libsepol/src/kernel_to_cil.c > @@ -1651,7 +1651,8 @@ static char *xperms_to_str(const avtab_extended_perms_t *xperms) > size_t remaining, size = 128; > > if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION) > - && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER)) { > + && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER) > + && (xperms->specified != AVTAB_XPERMS_NLMSG)) { > return NULL; > } > > @@ -1681,7 +1682,8 @@ retry: > continue; > } > > - if (xperms->specified & AVTAB_XPERMS_IOCTLFUNCTION) { > + if ((xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) > + || (xperms->specified == AVTAB_XPERMS_NLMSG)) { > value = xperms->driver<<8 | bit; > if (in_range) { > low_value = xperms->driver<<8 | low_bit; > @@ -1690,7 +1692,7 @@ retry: > } else { > len = snprintf(p, remaining, " 0x%hx", value); > } > - } else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) { > + } else if (xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { > value = bit << 8; > if (in_range) { > low_value = low_bit << 8; > @@ -1728,7 +1730,7 @@ static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_dat > uint32_t data = datum->data; > type_datum_t *type; > const char *flavor, *tgt; > - char *src, *class, *perms, *new; > + char *src, *class, *perms, *new, *xperm; > char *rule = NULL; > > switch (0xFFF & key->specified) { > @@ -1795,9 +1797,16 @@ static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_dat > ERR(NULL, "Failed to generate extended permission string"); > goto exit; > } > - > + if (datum->xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION || datum->xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { > + xperm = (char *) "ioctl"; > + } else if (datum->xperms->specified == AVTAB_XPERMS_NLMSG) { > + xperm = (char *) "nlmsg"; > + } else { > + ERR(NULL, "Unknown extended permssion"); > + goto exit; > + } > rule = create_str("(%s %s %s (%s %s (%s)))", > - flavor, src, tgt, "ioctl", class, perms); > + flavor, src, tgt, xperm, class, perms); > free(perms); > } else { > new = pdb->p_type_val_to_name[data - 1]; > diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c > index 2dbf137e..79636897 100644 > --- a/libsepol/src/module_to_cil.c > +++ b/libsepol/src/module_to_cil.c > @@ -630,7 +630,8 @@ static int xperms_to_cil(const av_extended_perms_t *xperms) > int first = 1; > > if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION) > - && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER)) > + && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER) > + && (xperms->specified != AVTAB_XPERMS_NLMSG)) > return -1; > > for (bit = 0; bit < sizeof(xperms->perms)*8; bit++) { > @@ -652,7 +653,8 @@ static int xperms_to_cil(const av_extended_perms_t *xperms) > else > first = 0; > > - if (xperms->specified & AVTAB_XPERMS_IOCTLFUNCTION) { > + if ((xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) > + || (xperms->specified == AVTAB_XPERMS_NLMSG)) { > value = xperms->driver<<8 | bit; > if (in_range) { > low_value = xperms->driver<<8 | low_bit; > @@ -661,7 +663,7 @@ static int xperms_to_cil(const av_extended_perms_t *xperms) > } else { > cil_printf("0x%hx", value); > } > - } else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) { > + } else if (xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { > value = bit << 8; > if (in_range) { > low_value = low_bit << 8; > @@ -680,6 +682,7 @@ static int avrulex_to_cil(int indent, struct policydb *pdb, uint32_t type, const > { > int rc = -1; > const char *rule; > + const char *xperm; > const struct class_perm_node *classperm; > > switch (type) { > @@ -701,10 +704,19 @@ static int avrulex_to_cil(int indent, struct policydb *pdb, uint32_t type, const > goto exit; > } > > + if (xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION || xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { > + xperm = "ioctl"; > + } else if (xperms->specified == AVTAB_XPERMS_NLMSG) { > + xperm = "nlmsg"; > + } else { > + ERR(NULL, "Unkown avrule xperms->specified: %i", xperms->specified); > + rc = -1; > + goto exit; > + } > for (classperm = classperms; classperm != NULL; classperm = classperm->next) { > cil_indent(indent); > cil_printf("(%s %s %s (%s %s (", rule, src, tgt, > - "ioctl", pdb->p_class_val_to_name[classperm->tclass - 1]); > + xperm, pdb->p_class_val_to_name[classperm->tclass - 1]); > xperms_to_cil(xperms); > cil_printf(")))\n"); > } > diff --git a/libsepol/src/policydb_validate.c b/libsepol/src/policydb_validate.c > index 121fd46c..5035313b 100644 > --- a/libsepol/src/policydb_validate.c > +++ b/libsepol/src/policydb_validate.c > @@ -921,6 +921,7 @@ static int validate_xperms(const avtab_extended_perms_t *xperms) > switch (xperms->specified) { > case AVTAB_XPERMS_IOCTLDRIVER: > case AVTAB_XPERMS_IOCTLFUNCTION: > + case AVTAB_XPERMS_NLMSG: > break; > default: > goto bad; > @@ -1067,6 +1068,7 @@ static int validate_avrules(sepol_handle_t *handle, const avrule_t *avrule, int > switch (avrule->xperms->specified) { > case AVRULE_XPERMS_IOCTLFUNCTION: > case AVRULE_XPERMS_IOCTLDRIVER: > + case AVRULE_XPERMS_NLMSG: > break; > default: > goto bad; > diff --git a/libsepol/src/util.c b/libsepol/src/util.c > index b1eb9b38..a4befbd9 100644 > --- a/libsepol/src/util.c > +++ b/libsepol/src/util.c > @@ -146,7 +146,8 @@ char *sepol_extended_perms_to_string(const avtab_extended_perms_t *xperms) > size_t remaining, size = 128; > > if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION) > - && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER)) > + && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER) > + && (xperms->specified != AVTAB_XPERMS_NLMSG)) > return NULL; > > retry: > @@ -158,7 +159,12 @@ retry: > buffer = p; > remaining = size; > > - len = snprintf(p, remaining, "ioctl { "); > + if ((xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) > + || (xperms->specified == AVTAB_XPERMS_IOCTLDRIVER)) { > + len = snprintf(p, remaining, "ioctl { "); > + } else { > + len = snprintf(p, remaining, "nlmsg { "); > + } > if (len < 0 || (size_t)len >= remaining) > goto err; > p += len; > @@ -179,7 +185,7 @@ retry: > continue; > } > > - if (xperms->specified & AVTAB_XPERMS_IOCTLFUNCTION) { > + if (xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION || xperms->specified == AVTAB_XPERMS_NLMSG) { > value = xperms->driver<<8 | bit; > if (in_range) { > low_value = xperms->driver<<8 | low_bit; > @@ -187,7 +193,7 @@ retry: > } else { > len = snprintf(p, remaining, "0x%hx ", value); > } > - } else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) { > + } else if (xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { > value = bit << 8; > if (in_range) { > low_value = low_bit << 8; > -- > 2.46.0.184.g6999bdac58-goog >
diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c index 4f6b2266..6b062657 100644 --- a/checkpolicy/policy_define.c +++ b/checkpolicy/policy_define.c @@ -2342,8 +2342,8 @@ static int avrule_ioctl_completedriver(struct av_xperm_range_list *rangelist, return 0; } -static int avrule_ioctl_func(struct av_xperm_range_list *rangelist, - av_extended_perms_t **extended_perms, unsigned int driver) +static int avrule_xperm_func(struct av_xperm_range_list *rangelist, + av_extended_perms_t **extended_perms, unsigned int driver, uint8_t specified) { struct av_xperm_range_list *r; av_extended_perms_t *xperms; @@ -2379,7 +2379,7 @@ static int avrule_ioctl_func(struct av_xperm_range_list *rangelist, high = IOC_FUNC(high); avrule_xperm_setrangebits(low, high, xperms); xperms->driver = driver; - xperms->specified = AVRULE_XPERMS_IOCTLFUNCTION; + xperms->specified = specified; r = r->next; } @@ -2495,7 +2495,61 @@ static int define_te_avtab_ioctl(const avrule_t *avrule_template) */ i = 0; while (xperms_for_each_bit(&i, partial_driver)) { - if (avrule_ioctl_func(rangelist, &xperms, i)) + if (avrule_xperm_func(rangelist, &xperms, i, AVRULE_XPERMS_IOCTLFUNCTION)) + return -1; + + if (xperms) { + avrule = (avrule_t *) calloc(1, sizeof(avrule_t)); + if (!avrule) { + yyerror("out of memory"); + return -1; + } + if (avrule_cpy(avrule, avrule_template)) + return -1; + avrule->xperms = xperms; + append_avrule(avrule); + } + } + +done: + if (partial_driver) + free(partial_driver); + + while (rangelist != NULL) { + r = rangelist; + rangelist = rangelist->next; + free(r); + } + + return 0; +} + +static int define_te_avtab_netlink(const avrule_t *avrule_template) +{ + avrule_t *avrule; + struct av_xperm_range_list *rangelist, *r; + av_extended_perms_t *partial_driver, *xperms; + unsigned int i; + + /* organize ranges */ + if (avrule_xperm_ranges(&rangelist)) + return -1; + + /* flag driver codes that are partially enabled */ + if (avrule_xperm_partialdriver(rangelist, NULL, &partial_driver)) + return -1; + + if (!partial_driver || !avrule_xperms_used(partial_driver)) + goto done; + + /* + * create rule for each partially used driver codes + * "partially used" meaning that the code number e.g. socket 0x89 + * has some permission bits set and others not set. + */ + i = 0; + while (xperms_for_each_bit(&i, partial_driver)) { + if (avrule_xperm_func(rangelist, &xperms, i, AVRULE_XPERMS_NLMSG)) return -1; if (xperms) { @@ -2546,6 +2600,8 @@ int define_te_avtab_extended_perms(int which) id = queue_remove(id_queue); if (strcmp(id,"ioctl") == 0) { rc = define_te_avtab_ioctl(avrule_template); + } else if (strcmp(id,"nlmsg") == 0) { + rc = define_te_avtab_netlink(avrule_template); } else { yyerror2("only ioctl extended permissions are supported, found %s", id); rc = -1; diff --git a/checkpolicy/test/dismod.c b/checkpolicy/test/dismod.c index bd45c95e..4868190f 100644 --- a/checkpolicy/test/dismod.c +++ b/checkpolicy/test/dismod.c @@ -353,6 +353,8 @@ static int display_avrule(avrule_t * avrule, policydb_t * policy, xperms.specified = AVTAB_XPERMS_IOCTLFUNCTION; else if (avrule->xperms->specified == AVRULE_XPERMS_IOCTLDRIVER) xperms.specified = AVTAB_XPERMS_IOCTLDRIVER; + else if (avrule->xperms->specified == AVRULE_XPERMS_NLMSG) + xperms.specified = AVTAB_XPERMS_NLMSG; else { fprintf(fp, " ERROR: no valid xperms specified\n"); return -1; diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c index 067e28a6..5521c7ea 100644 --- a/libsepol/cil/src/cil.c +++ b/libsepol/cil/src/cil.c @@ -221,6 +221,7 @@ char *CIL_KEY_DONTAUDITX; char *CIL_KEY_NEVERALLOWX; char *CIL_KEY_PERMISSIONX; char *CIL_KEY_IOCTL; +char *CIL_KEY_NLMSG; char *CIL_KEY_UNORDERED; char *CIL_KEY_SRC_INFO; char *CIL_KEY_SRC_CIL; @@ -393,6 +394,7 @@ static void cil_init_keys(void) CIL_KEY_NEVERALLOWX = cil_strpool_add("neverallowx"); CIL_KEY_PERMISSIONX = cil_strpool_add("permissionx"); CIL_KEY_IOCTL = cil_strpool_add("ioctl"); + CIL_KEY_NLMSG = cil_strpool_add("nlmsg"); CIL_KEY_UNORDERED = cil_strpool_add("unordered"); CIL_KEY_SRC_INFO = cil_strpool_add("<src_info>"); CIL_KEY_SRC_CIL = cil_strpool_add("cil"); diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c index c8144a5a..3dec1883 100644 --- a/libsepol/cil/src/cil_binary.c +++ b/libsepol/cil/src/cil_binary.c @@ -66,6 +66,7 @@ struct cil_args_binary { int pass; hashtab_t role_trans_table; hashtab_t avrulex_ioctl_table; + hashtab_t avrulex_nlmsg_table; void **type_value_to_cil; }; @@ -1671,11 +1672,22 @@ static void __avrule_xperm_setrangebits(uint16_t low, uint16_t high, struct avta } } +static char* __cil_xperm_kind_to_str(uint32_t xperm_kind) +{ + switch (xperm_kind) { + case CIL_PERMX_KIND_IOCTL: + return CIL_KEY_IOCTL; + case CIL_PERMX_KIND_NLMSG: + return CIL_KEY_NLMSG; + default: + return (char *) "unknown"; + } +} #define IOC_DRIV(x) (x >> 8) #define IOC_FUNC(x) (x & 0xff) -static int __cil_permx_bitmap_to_sepol_xperms_list(ebitmap_t *xperms, struct cil_list **xperms_list) +static int __cil_permx_bitmap_to_sepol_xperms_list(uint32_t kind, ebitmap_t *xperms, struct cil_list **xperms_list) { ebitmap_node_t *node; unsigned int i; @@ -1705,7 +1717,7 @@ static int __cil_permx_bitmap_to_sepol_xperms_list(ebitmap_t *xperms, struct cil high = i; start_new_range = 1; - if (IOC_FUNC(low) == 0x00 && IOC_FUNC(high) == 0xff) { + if (kind == CIL_PERMX_KIND_IOCTL && IOC_FUNC(low) == 0x00 && IOC_FUNC(high) == 0xff) { if (!complete) { complete = cil_calloc(1, sizeof(*complete)); complete->driver = 0x0; @@ -1722,7 +1734,14 @@ static int __cil_permx_bitmap_to_sepol_xperms_list(ebitmap_t *xperms, struct cil if (!partial) { partial = cil_calloc(1, sizeof(*partial)); partial->driver = IOC_DRIV(low); - partial->specified = AVTAB_XPERMS_IOCTLFUNCTION; + switch (kind) { + case CIL_PERMX_KIND_IOCTL: + partial->specified = AVTAB_XPERMS_IOCTLFUNCTION; + break; + case CIL_PERMX_KIND_NLMSG: + partial->specified = AVTAB_XPERMS_NLMSG; + break; + } } __avrule_xperm_setrangebits(IOC_FUNC(low), IOC_FUNC(high), partial); @@ -1740,7 +1759,7 @@ static int __cil_permx_bitmap_to_sepol_xperms_list(ebitmap_t *xperms, struct cil return SEPOL_OK; } -static int __cil_avrulex_ioctl_to_policydb(hashtab_key_t k, hashtab_datum_t datum, void *args) +static int __cil_avrulex_xperm_to_policydb(hashtab_key_t k, hashtab_datum_t datum, uint32_t xperm_kind, void *args) { int rc = SEPOL_OK; struct policydb *pdb; @@ -1750,6 +1769,7 @@ static int __cil_avrulex_ioctl_to_policydb(hashtab_key_t k, hashtab_datum_t datu struct cil_list_item *item; class_datum_t *sepol_obj; uint32_t data = 0; + char *kind = NULL; avtab_key = (avtab_key_t *)k; pdb = args; @@ -1759,13 +1779,14 @@ static int __cil_avrulex_ioctl_to_policydb(hashtab_key_t k, hashtab_datum_t datu // setting the data for an extended avtab isn't really necessary because // it is ignored by the kernel. However, neverallow checking requires that // the data value be set, so set it for that to work. - rc = __perm_str_to_datum(CIL_KEY_IOCTL, sepol_obj, &data); + kind = __cil_xperm_kind_to_str(xperm_kind); + rc = __perm_str_to_datum(kind, sepol_obj, &data); if (rc != SEPOL_OK) { goto exit; } avtab_datum.data = data; - rc = __cil_permx_bitmap_to_sepol_xperms_list(datum, &xperms_list); + rc = __cil_permx_bitmap_to_sepol_xperms_list(xperm_kind, datum, &xperms_list); if (rc != SEPOL_OK) { goto exit; } @@ -1790,7 +1811,15 @@ exit: return rc; } -static int __cil_avrulex_ioctl_to_hashtable(hashtab_t h, uint16_t kind, uint32_t src, uint32_t tgt, uint32_t obj, ebitmap_t *xperms) +static int __cil_avrulex_ioctl_to_policydb(hashtab_key_t k, hashtab_datum_t datum, void *args) { + return __cil_avrulex_xperm_to_policydb(k, datum, CIL_PERMX_KIND_IOCTL, args); +} + +static int __cil_avrulex_nlmsg_to_policydb(hashtab_key_t k, hashtab_datum_t datum, void *args) { + return __cil_avrulex_xperm_to_policydb(k, datum, CIL_PERMX_KIND_NLMSG, args); +} + +static int __cil_avrulex_xperm_to_hashtable(hashtab_t h, uint16_t kind, uint32_t src, uint32_t tgt, uint32_t obj, ebitmap_t *xperms) { uint16_t specified; avtab_key_t *avtab_key; @@ -1870,7 +1899,11 @@ static int __cil_avrulex_to_hashtable_helper(policydb_t *pdb, uint16_t kind, str switch (permx->kind) { case CIL_PERMX_KIND_IOCTL: - rc = __cil_avrulex_ioctl_to_hashtable(args->avrulex_ioctl_table, kind, sepol_src->s.value, sepol_tgt->s.value, sepol_obj->s.value, permx->perms); + rc = __cil_avrulex_xperm_to_hashtable(args->avrulex_ioctl_table, kind, sepol_src->s.value, sepol_tgt->s.value, sepol_obj->s.value, permx->perms); + if (rc != SEPOL_OK) goto exit; + break; + case CIL_PERMX_KIND_NLMSG: + rc = __cil_avrulex_xperm_to_hashtable(args->avrulex_nlmsg_table, kind, sepol_src->s.value, sepol_tgt->s.value, sepol_obj->s.value, permx->perms); if (rc != SEPOL_OK) goto exit; break; default: @@ -2037,7 +2070,7 @@ exit: return rc; } -static int __cil_avrulex_ioctl_destroy(hashtab_key_t k, hashtab_datum_t datum, __attribute__((unused)) void *args) +static int __cil_avrulex_xperm_destroy(hashtab_key_t k, hashtab_datum_t datum, __attribute__((unused)) void *args) { free(k); ebitmap_destroy(datum); @@ -4630,6 +4663,9 @@ static int __cil_permx_to_sepol_class_perms(policydb_t *pdb, struct cil_permissi case CIL_PERMX_KIND_IOCTL: perm_str = CIL_KEY_IOCTL; break; + case CIL_PERMX_KIND_NLMSG: + perm_str = CIL_KEY_NLMSG; + break; default: rc = SEPOL_ERR; goto exit; @@ -4769,17 +4805,10 @@ static void __cil_print_classperm(struct cil_list *cp_list) static void __cil_print_permissionx(struct cil_permissionx *px) { - const char *kind_str = ""; + const char *kind_str = NULL; char *expr_str; - switch (px->kind) { - case CIL_PERMX_KIND_IOCTL: - kind_str = CIL_KEY_IOCTL; - break; - default: - kind_str = "unknown"; - break; - } + kind_str = __cil_xperm_kind_to_str(px->kind); __cil_expr_to_string(px->expr_str, CIL_PERMISSIONX, &expr_str); @@ -4928,7 +4957,7 @@ static int cil_check_neverallow(const struct cil_db *db, policydb_t *pdb, struct goto exit; } - rc = __cil_permx_bitmap_to_sepol_xperms_list(cil_rule->perms.x.permx->perms, &xperms); + rc = __cil_permx_bitmap_to_sepol_xperms_list(cil_rule->perms.x.permx->kind, cil_rule->perms.x.permx->perms, &xperms); if (rc != SEPOL_OK) { goto exit; } @@ -5137,6 +5166,7 @@ int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *p struct cil_list *neverallows = NULL; hashtab_t role_trans_table = NULL; hashtab_t avrulex_ioctl_table = NULL; + hashtab_t avrulex_nlmsg_table = NULL; void **type_value_to_cil = NULL; struct cil_class **class_value_to_cil = NULL; struct cil_perm ***perm_value_to_cil = NULL; @@ -5184,6 +5214,12 @@ int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *p goto exit; } + avrulex_nlmsg_table = hashtab_create(avrulex_hash, avrulex_compare, AVRULEX_TABLE_SIZE); + if (!avrulex_nlmsg_table) { + cil_log(CIL_INFO, "Failure to create hashtab for avrulex\n"); + goto exit; + } + cil_list_init(&neverallows, CIL_LIST_ITEM); extra_args.db = db; @@ -5191,6 +5227,7 @@ int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *p extra_args.neverallows = neverallows; extra_args.role_trans_table = role_trans_table; extra_args.avrulex_ioctl_table = avrulex_ioctl_table; + extra_args.avrulex_nlmsg_table = avrulex_nlmsg_table; extra_args.type_value_to_cil = type_value_to_cil; for (i = 1; i <= 3; i++) { @@ -5216,6 +5253,11 @@ int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *p cil_log(CIL_INFO, "Failure creating avrulex rules\n"); goto exit; } + rc = hashtab_map(avrulex_nlmsg_table, __cil_avrulex_nlmsg_to_policydb, pdb); + if (rc != SEPOL_OK) { + cil_log(CIL_INFO, "Failure creating avrulex rules\n"); + goto exit; + } } } @@ -5287,8 +5329,10 @@ int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *p exit: hashtab_destroy(role_trans_table); - hashtab_map(avrulex_ioctl_table, __cil_avrulex_ioctl_destroy, NULL); + hashtab_map(avrulex_ioctl_table, __cil_avrulex_xperm_destroy, NULL); hashtab_destroy(avrulex_ioctl_table); + hashtab_map(avrulex_nlmsg_table, __cil_avrulex_xperm_destroy, NULL); + hashtab_destroy(avrulex_nlmsg_table); free(type_value_to_cil); free(class_value_to_cil); if (perm_value_to_cil != NULL) { diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c index 56dac891..87178294 100644 --- a/libsepol/cil/src/cil_build_ast.c +++ b/libsepol/cil/src/cil_build_ast.c @@ -2153,8 +2153,10 @@ static int cil_fill_permissionx(struct cil_tree_node *parse_current, struct cil_ if (parse_current->data == CIL_KEY_IOCTL) { permx->kind = CIL_PERMX_KIND_IOCTL; + } else if (parse_current->data == CIL_KEY_NLMSG) { + permx->kind = CIL_PERMX_KIND_NLMSG; } else { - cil_log(CIL_ERR, "Unknown permissionx kind, %s. Must be \"ioctl\"\n", (char *)parse_current->data); + cil_log(CIL_ERR, "Unknown permissionx kind, %s. Must be \"ioctl\" or \"nlmsg\"\n", (char *)parse_current->data); rc = SEPOL_ERR; goto exit; } diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h index 47b67c89..959b31e3 100644 --- a/libsepol/cil/src/cil_internal.h +++ b/libsepol/cil/src/cil_internal.h @@ -238,6 +238,7 @@ extern char *CIL_KEY_DONTAUDITX; extern char *CIL_KEY_NEVERALLOWX; extern char *CIL_KEY_PERMISSIONX; extern char *CIL_KEY_IOCTL; +extern char *CIL_KEY_NLMSG; extern char *CIL_KEY_UNORDERED; extern char *CIL_KEY_SRC_INFO; extern char *CIL_KEY_SRC_CIL; @@ -636,6 +637,7 @@ struct cil_avrule { }; #define CIL_PERMX_KIND_IOCTL 1 +#define CIL_PERMX_KIND_NLMSG 2 struct cil_permissionx { struct cil_symtab_datum datum; uint32_t kind; diff --git a/libsepol/cil/src/cil_policy.c b/libsepol/cil/src/cil_policy.c index e9a8f75d..c497c8ab 100644 --- a/libsepol/cil/src/cil_policy.c +++ b/libsepol/cil/src/cil_policy.c @@ -1112,6 +1112,8 @@ static void cil_xperms_to_policy(FILE *out, struct cil_permissionx *permx) if (permx->kind == CIL_PERMX_KIND_IOCTL) { kind = "ioctl"; + } else if (permx->kind == CIL_PERMX_KIND_NLMSG) { + kind = "nlmsg"; } else { kind = "???"; } diff --git a/libsepol/cil/src/cil_verify.c b/libsepol/cil/src/cil_verify.c index 4ef2cbab..9621a247 100644 --- a/libsepol/cil/src/cil_verify.c +++ b/libsepol/cil/src/cil_verify.c @@ -1513,6 +1513,9 @@ static int __cil_verify_permissionx(struct cil_permissionx *permx, struct cil_tr case CIL_PERMX_KIND_IOCTL: kind_str = CIL_KEY_IOCTL; break; + case CIL_PERMX_KIND_NLMSG: + kind_str = CIL_KEY_NLMSG; + break; default: cil_tree_log(node, CIL_ERR, "Invalid permissionx kind (%d)", permx->kind); rc = SEPOL_ERR; diff --git a/libsepol/cil/src/cil_write_ast.c b/libsepol/cil/src/cil_write_ast.c index 46bd84db..cd1b6e6c 100644 --- a/libsepol/cil/src/cil_write_ast.c +++ b/libsepol/cil/src/cil_write_ast.c @@ -303,7 +303,13 @@ static void write_permx(FILE *out, struct cil_permissionx *permx) fprintf(out, "%s", datum_to_str(DATUM(permx))); } else { fprintf(out, "("); - fprintf(out, "%s ", permx->kind == CIL_PERMX_KIND_IOCTL ? "ioctl" : "<?KIND>"); + if (permx->kind == CIL_PERMX_KIND_IOCTL) { + fprintf(out, "ioctl "); + } else if (permx->kind == CIL_PERMX_KIND_NLMSG) { + fprintf(out, "nlmsg "); + } else { + fprintf(out, "<?KIND> "); + } fprintf(out, "%s ", datum_or_str(DATUM(permx->obj), permx->obj_str)); write_expr(out, permx->expr_str); fprintf(out, ")"); @@ -825,7 +831,13 @@ void cil_write_ast_node(FILE *out, struct cil_tree_node *node) case CIL_PERMISSIONX: { struct cil_permissionx *permx = node->data; fprintf(out, "(permissionx %s (", datum_to_str(DATUM(permx))); - fprintf(out, "%s ", permx->kind == CIL_PERMX_KIND_IOCTL ? "ioctl" : "<?KIND>"); + if (permx->kind == CIL_PERMX_KIND_IOCTL) { + fprintf(out, "ioctl "); + } else if (permx->kind == CIL_PERMX_KIND_NLMSG) { + fprintf(out, "nlmsg "); + } else { + fprintf(out, "<?KIND> "); + } fprintf(out, "%s ", datum_or_str(DATUM(permx->obj), permx->obj_str)); write_expr(out, permx->expr_str); fprintf(out, "))\n"); diff --git a/libsepol/include/sepol/policydb/avtab.h b/libsepol/include/sepol/policydb/avtab.h index 2ab99c39..6e154cfe 100644 --- a/libsepol/include/sepol/policydb/avtab.h +++ b/libsepol/include/sepol/policydb/avtab.h @@ -74,6 +74,7 @@ typedef struct avtab_extended_perms { #define AVTAB_XPERMS_IOCTLFUNCTION 0x01 #define AVTAB_XPERMS_IOCTLDRIVER 0x02 +#define AVTAB_XPERMS_NLMSG 0x03 /* extension of the avtab_key specified */ uint8_t specified; uint8_t driver; diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h index 856faeb7..104a7dc8 100644 --- a/libsepol/include/sepol/policydb/policydb.h +++ b/libsepol/include/sepol/policydb/policydb.h @@ -259,6 +259,7 @@ typedef struct class_perm_node { typedef struct av_extended_perms { #define AVRULE_XPERMS_IOCTLFUNCTION 0x01 #define AVRULE_XPERMS_IOCTLDRIVER 0x02 +#define AVRULE_XPERMS_NLMSG 0x03 uint8_t specified; uint8_t driver; /* 256 bits of permissions */ diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c index e63414b1..7032a83f 100644 --- a/libsepol/src/expand.c +++ b/libsepol/src/expand.c @@ -1821,6 +1821,9 @@ static int allocate_xperms(sepol_handle_t * handle, avtab_datum_t * avdatump, case AVRULE_XPERMS_IOCTLDRIVER: xperms->specified = AVTAB_XPERMS_IOCTLDRIVER; break; + case AVRULE_XPERMS_NLMSG: + xperms->specified = AVTAB_XPERMS_NLMSG; + break; default: return -1; } diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c index f94cb245..7243b3c0 100644 --- a/libsepol/src/kernel_to_cil.c +++ b/libsepol/src/kernel_to_cil.c @@ -1651,7 +1651,8 @@ static char *xperms_to_str(const avtab_extended_perms_t *xperms) size_t remaining, size = 128; if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION) - && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER)) { + && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER) + && (xperms->specified != AVTAB_XPERMS_NLMSG)) { return NULL; } @@ -1681,7 +1682,8 @@ retry: continue; } - if (xperms->specified & AVTAB_XPERMS_IOCTLFUNCTION) { + if ((xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) + || (xperms->specified == AVTAB_XPERMS_NLMSG)) { value = xperms->driver<<8 | bit; if (in_range) { low_value = xperms->driver<<8 | low_bit; @@ -1690,7 +1692,7 @@ retry: } else { len = snprintf(p, remaining, " 0x%hx", value); } - } else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) { + } else if (xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { value = bit << 8; if (in_range) { low_value = low_bit << 8; @@ -1728,7 +1730,7 @@ static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_dat uint32_t data = datum->data; type_datum_t *type; const char *flavor, *tgt; - char *src, *class, *perms, *new; + char *src, *class, *perms, *new, *xperm; char *rule = NULL; switch (0xFFF & key->specified) { @@ -1795,9 +1797,16 @@ static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_dat ERR(NULL, "Failed to generate extended permission string"); goto exit; } - + if (datum->xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION || datum->xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { + xperm = (char *) "ioctl"; + } else if (datum->xperms->specified == AVTAB_XPERMS_NLMSG) { + xperm = (char *) "nlmsg"; + } else { + ERR(NULL, "Unknown extended permssion"); + goto exit; + } rule = create_str("(%s %s %s (%s %s (%s)))", - flavor, src, tgt, "ioctl", class, perms); + flavor, src, tgt, xperm, class, perms); free(perms); } else { new = pdb->p_type_val_to_name[data - 1]; diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c index 2dbf137e..79636897 100644 --- a/libsepol/src/module_to_cil.c +++ b/libsepol/src/module_to_cil.c @@ -630,7 +630,8 @@ static int xperms_to_cil(const av_extended_perms_t *xperms) int first = 1; if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION) - && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER)) + && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER) + && (xperms->specified != AVTAB_XPERMS_NLMSG)) return -1; for (bit = 0; bit < sizeof(xperms->perms)*8; bit++) { @@ -652,7 +653,8 @@ static int xperms_to_cil(const av_extended_perms_t *xperms) else first = 0; - if (xperms->specified & AVTAB_XPERMS_IOCTLFUNCTION) { + if ((xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) + || (xperms->specified == AVTAB_XPERMS_NLMSG)) { value = xperms->driver<<8 | bit; if (in_range) { low_value = xperms->driver<<8 | low_bit; @@ -661,7 +663,7 @@ static int xperms_to_cil(const av_extended_perms_t *xperms) } else { cil_printf("0x%hx", value); } - } else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) { + } else if (xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { value = bit << 8; if (in_range) { low_value = low_bit << 8; @@ -680,6 +682,7 @@ static int avrulex_to_cil(int indent, struct policydb *pdb, uint32_t type, const { int rc = -1; const char *rule; + const char *xperm; const struct class_perm_node *classperm; switch (type) { @@ -701,10 +704,19 @@ static int avrulex_to_cil(int indent, struct policydb *pdb, uint32_t type, const goto exit; } + if (xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION || xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { + xperm = "ioctl"; + } else if (xperms->specified == AVTAB_XPERMS_NLMSG) { + xperm = "nlmsg"; + } else { + ERR(NULL, "Unkown avrule xperms->specified: %i", xperms->specified); + rc = -1; + goto exit; + } for (classperm = classperms; classperm != NULL; classperm = classperm->next) { cil_indent(indent); cil_printf("(%s %s %s (%s %s (", rule, src, tgt, - "ioctl", pdb->p_class_val_to_name[classperm->tclass - 1]); + xperm, pdb->p_class_val_to_name[classperm->tclass - 1]); xperms_to_cil(xperms); cil_printf(")))\n"); } diff --git a/libsepol/src/policydb_validate.c b/libsepol/src/policydb_validate.c index 121fd46c..5035313b 100644 --- a/libsepol/src/policydb_validate.c +++ b/libsepol/src/policydb_validate.c @@ -921,6 +921,7 @@ static int validate_xperms(const avtab_extended_perms_t *xperms) switch (xperms->specified) { case AVTAB_XPERMS_IOCTLDRIVER: case AVTAB_XPERMS_IOCTLFUNCTION: + case AVTAB_XPERMS_NLMSG: break; default: goto bad; @@ -1067,6 +1068,7 @@ static int validate_avrules(sepol_handle_t *handle, const avrule_t *avrule, int switch (avrule->xperms->specified) { case AVRULE_XPERMS_IOCTLFUNCTION: case AVRULE_XPERMS_IOCTLDRIVER: + case AVRULE_XPERMS_NLMSG: break; default: goto bad; diff --git a/libsepol/src/util.c b/libsepol/src/util.c index b1eb9b38..a4befbd9 100644 --- a/libsepol/src/util.c +++ b/libsepol/src/util.c @@ -146,7 +146,8 @@ char *sepol_extended_perms_to_string(const avtab_extended_perms_t *xperms) size_t remaining, size = 128; if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION) - && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER)) + && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER) + && (xperms->specified != AVTAB_XPERMS_NLMSG)) return NULL; retry: @@ -158,7 +159,12 @@ retry: buffer = p; remaining = size; - len = snprintf(p, remaining, "ioctl { "); + if ((xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) + || (xperms->specified == AVTAB_XPERMS_IOCTLDRIVER)) { + len = snprintf(p, remaining, "ioctl { "); + } else { + len = snprintf(p, remaining, "nlmsg { "); + } if (len < 0 || (size_t)len >= remaining) goto err; p += len; @@ -179,7 +185,7 @@ retry: continue; } - if (xperms->specified & AVTAB_XPERMS_IOCTLFUNCTION) { + if (xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION || xperms->specified == AVTAB_XPERMS_NLMSG) { value = xperms->driver<<8 | bit; if (in_range) { low_value = xperms->driver<<8 | low_bit; @@ -187,7 +193,7 @@ retry: } else { len = snprintf(p, remaining, "0x%hx ", value); } - } else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) { + } else if (xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { value = bit << 8; if (in_range) { low_value = low_bit << 8;
Add support for AVTAB_XPERMS_NLMSG as extended permissions for netlink sockets. The behaviour is similar to the existing AVTAB_XPERMS_IOCTLFUNCTION. Signed-off-by: Thiébaud Weksteen <tweek@google.com> --- checkpolicy/policy_define.c | 64 +++++++++++++++-- checkpolicy/test/dismod.c | 2 + libsepol/cil/src/cil.c | 2 + libsepol/cil/src/cil_binary.c | 84 ++++++++++++++++------ libsepol/cil/src/cil_build_ast.c | 4 +- libsepol/cil/src/cil_internal.h | 2 + libsepol/cil/src/cil_policy.c | 2 + libsepol/cil/src/cil_verify.c | 3 + libsepol/cil/src/cil_write_ast.c | 16 ++++- libsepol/include/sepol/policydb/avtab.h | 1 + libsepol/include/sepol/policydb/policydb.h | 1 + libsepol/src/expand.c | 3 + libsepol/src/kernel_to_cil.c | 21 ++++-- libsepol/src/module_to_cil.c | 20 ++++-- libsepol/src/policydb_validate.c | 2 + libsepol/src/util.c | 14 ++-- 16 files changed, 200 insertions(+), 41 deletions(-)