Skip to content

Commit

Permalink
libsepol: Support nlmsg extended permissions
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
tweksteen authored and stephensmalley committed Aug 22, 2024
1 parent 9f2d47f commit 1c3fd93
Show file tree
Hide file tree
Showing 16 changed files with 200 additions and 41 deletions.
64 changes: 60 additions & 4 deletions checkpolicy/policy_define.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions checkpolicy/test/dismod.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions libsepol/cil/src/cil.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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");
Expand Down
84 changes: 64 additions & 20 deletions libsepol/cil/src/cil_binary.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
}
Expand All @@ -1790,7 +1811,15 @@ static int __cil_avrulex_ioctl_to_policydb(hashtab_key_t k, hashtab_datum_t datu
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;
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -2037,7 +2070,7 @@ static int cil_avrulex_to_hashtable(policydb_t *pdb, const struct cil_db *db, st
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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -5184,13 +5214,20 @@ 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;
extra_args.pdb = pdb;
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++) {
Expand All @@ -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;
}
}
}

Expand Down Expand Up @@ -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) {
Expand Down
4 changes: 3 additions & 1 deletion libsepol/cil/src/cil_build_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 2 additions & 0 deletions libsepol/cil/src/cil_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions libsepol/cil/src/cil_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "???";
}
Expand Down
3 changes: 3 additions & 0 deletions libsepol/cil/src/cil_verify.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 1c3fd93

Please sign in to comment.