diff options
author | Jeff Vander Stoep <jeffv@google.com> | 2015-04-01 10:35:01 -0700 |
---|---|---|
committer | Jeff Vander Stoep <jeffv@google.com> | 2015-04-14 14:55:40 -0700 |
commit | f27738a7afe48b5c9937ffc5a4363d6086c4195b (patch) | |
tree | dfa95480c5f2baedd5c8c897fd6e71cf38494a51 | |
parent | c43eb7aea917a322b736fb88f647ff6c797b0db0 (diff) | |
download | libsepol-master-soong.tar.gz |
Add ioctl command whitelisting rulesmaster-soong
Add new policy statements for whitelisting ioctl commands.
<source> <target>:<class> { 0x8900-0x8905 0x8910 }
Bug: 19419509
Change-Id: I198e8c9279b94d8ce4ae5625018daa99577ee970
-rw-r--r-- | include/sepol/policydb/avtab.h | 37 | ||||
-rw-r--r-- | include/sepol/policydb/policydb.h | 37 | ||||
-rw-r--r-- | src/avtab.c | 66 | ||||
-rw-r--r-- | src/expand.c | 109 | ||||
-rw-r--r-- | src/policydb.c | 7 | ||||
-rw-r--r-- | src/write.c | 35 |
6 files changed, 241 insertions, 50 deletions
diff --git a/include/sepol/policydb/avtab.h b/include/sepol/policydb/avtab.h index 3f56a0e..2ea821c 100644 --- a/include/sepol/policydb/avtab.h +++ b/include/sepol/policydb/avtab.h @@ -50,22 +50,37 @@ typedef struct avtab_key { uint16_t source_type; uint16_t target_type; uint16_t target_class; -#define AVTAB_ALLOWED 1 -#define AVTAB_AUDITALLOW 2 -#define AVTAB_AUDITDENY 4 -#define AVTAB_NEVERALLOW 128 -#define AVTAB_AV (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY) -#define AVTAB_TRANSITION 16 -#define AVTAB_MEMBER 32 -#define AVTAB_CHANGE 64 -#define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) -#define AVTAB_ENABLED_OLD 0x80000000 -#define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */ +#define AVTAB_ALLOWED 0x0001 +#define AVTAB_AUDITALLOW 0x0002 +#define AVTAB_AUDITDENY 0x0004 +#define AVTAB_NEVERALLOW 0x0080 +#define AVTAB_AV (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY) +#define AVTAB_TRANSITION 0x0010 +#define AVTAB_MEMBER 0x0020 +#define AVTAB_CHANGE 0x0040 +#define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) +#define AVTAB_OPNUM_ALLOWED 0x0100 +#define AVTAB_OPNUM_AUDITALLOW 0x0200 +#define AVTAB_OPNUM_DONTAUDIT 0x0400 +#define AVTAB_OPNUM (AVTAB_OPNUM_ALLOWED | AVTAB_OPNUM_AUDITALLOW | AVTAB_OPNUM_DONTAUDIT) +#define AVTAB_OPTYPE_ALLOWED 0x1000 +#define AVTAB_OPTYPE_AUDITALLOW 0x2000 +#define AVTAB_OPTYPE_DONTAUDIT 0x4000 +#define AVTAB_OPTYPE (AVTAB_OPTYPE_ALLOWED | AVTAB_OPTYPE_AUDITALLOW | AVTAB_OPTYPE_DONTAUDIT) +#define AVTAB_OP (AVTAB_OPNUM | AVTAB_OPTYPE) +#define AVTAB_ENABLED_OLD 0x80000000 +#define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */ uint16_t specified; /* what fields are specified */ } avtab_key_t; +typedef struct avtab_operations { + uint8_t type; + uint32_t perms[8]; +} avtab_operations_t; + typedef struct avtab_datum { uint32_t data; /* access vector or type */ + avtab_operations_t *ops; } avtab_datum_t; typedef struct avtab_node *avtab_ptr_t; diff --git a/include/sepol/policydb/policydb.h b/include/sepol/policydb/policydb.h index 6254fef..4dc3704 100644 --- a/include/sepol/policydb/policydb.h +++ b/include/sepol/policydb/policydb.h @@ -241,25 +241,43 @@ typedef struct class_perm_node { struct class_perm_node *next; } class_perm_node_t; +typedef struct av_operations { + uint8_t type; + /* 256 bits of ioctl number permissions */ + uint32_t perms[8]; +} av_operations_t; + typedef struct avrule { /* these typedefs are almost exactly the same as those in avtab.h - they are * here because of the need to include neverallow and dontaudit messages */ -#define AVRULE_ALLOWED 1 -#define AVRULE_AUDITALLOW 2 -#define AVRULE_AUDITDENY 4 -#define AVRULE_DONTAUDIT 8 -#define AVRULE_NEVERALLOW 128 +#define AVRULE_ALLOWED 0x0001 +#define AVRULE_AUDITALLOW 0x0002 +#define AVRULE_AUDITDENY 0x0004 +#define AVRULE_DONTAUDIT 0x0008 +#define AVRULE_NEVERALLOW 0x0080 #define AVRULE_AV (AVRULE_ALLOWED | AVRULE_AUDITALLOW | AVRULE_AUDITDENY | AVRULE_DONTAUDIT | AVRULE_NEVERALLOW) -#define AVRULE_TRANSITION 16 -#define AVRULE_MEMBER 32 -#define AVRULE_CHANGE 64 +#define AVRULE_TRANSITION 0x0010 +#define AVRULE_MEMBER 0x0020 +#define AVRULE_CHANGE 0x0040 #define AVRULE_TYPE (AVRULE_TRANSITION | AVRULE_MEMBER | AVRULE_CHANGE) +#define AVRULE_OPNUM_ALLOWED 0x0100 +#define AVRULE_OPNUM_AUDITALLOW 0x0200 +#define AVRULE_OPNUM_DONTAUDIT 0x0400 +#define AVRULE_OPNUM (AVRULE_OPNUM_ALLOWED | AVRULE_OPNUM_AUDITALLOW | \ + AVRULE_OPNUM_DONTAUDIT) +#define AVRULE_OPTYPE_ALLOWED 0x1000 +#define AVRULE_OPTYPE_AUDITALLOW 0x2000 +#define AVRULE_OPTYPE_DONTAUDIT 0x4000 +#define AVRULE_OPTYPE (AVRULE_OPTYPE_ALLOWED | AVRULE_OPTYPE_AUDITALLOW | \ + AVRULE_OPTYPE_DONTAUDIT) +#define AVRULE_OP (AVRULE_OPNUM | AVRULE_OPTYPE) uint32_t specified; #define RULE_SELF 1 uint32_t flags; type_set_t stypes; type_set_t ttypes; class_perm_node_t *perms; + av_operations_t * ops; unsigned long line; /* line number from policy.conf where * this rule originated */ /* source file name and line number (e.g. .te file) */ @@ -689,10 +707,11 @@ extern int policydb_set_target_platform(policydb_t *p, int platform); #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 #define POLICYDB_VERSION_DEFAULT_TYPE 28 #define POLICYDB_VERSION_CONSTRAINT_NAMES 29 +#define POLICYDB_VERSION_IOCTL_OPERATIONS 30 /* Range of policy versions we understand*/ #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE -#define POLICYDB_VERSION_MAX POLICYDB_VERSION_CONSTRAINT_NAMES +#define POLICYDB_VERSION_MAX POLICYDB_VERSION_IOCTL_OPERATIONS /* Module versions and specific changes*/ #define MOD_POLICYDB_VERSION_BASE 4 diff --git a/src/avtab.c b/src/avtab.c index d6041d4..d3745fe 100644 --- a/src/avtab.c +++ b/src/avtab.c @@ -93,12 +93,28 @@ avtab_insert_node(avtab_t * h, int hvalue, avtab_ptr_t prev, avtab_key_t * key, avtab_datum_t * datum) { avtab_ptr_t newnode; + avtab_operations_t *ops; + newnode = (avtab_ptr_t) malloc(sizeof(struct avtab_node)); if (newnode == NULL) return NULL; memset(newnode, 0, sizeof(struct avtab_node)); newnode->key = *key; - newnode->datum = *datum; + + if (key->specified & AVTAB_OP) { + ops = calloc(1, sizeof(avtab_operations_t)); + if (ops == NULL) { + free(newnode); + return NULL; + } + if (datum->ops) /* else caller populates ops*/ + *ops = *(datum->ops); + + newnode->datum.ops = ops; + } else { + newnode->datum = *datum; + } + if (prev) { newnode->next = prev->next; prev->next = newnode; @@ -127,8 +143,11 @@ int avtab_insert(avtab_t * h, avtab_key_t * key, avtab_datum_t * datum) if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type && key->target_class == cur->key.target_class && - (specified & cur->key.specified)) + (specified & cur->key.specified)) { + if (specified & AVTAB_OPNUM) + break; return SEPOL_EEXIST; + } if (key->source_type < cur->key.source_type) break; if (key->source_type == cur->key.source_type && @@ -396,23 +415,32 @@ static uint16_t spec_order[] = { AVTAB_AUDITALLOW, AVTAB_TRANSITION, AVTAB_CHANGE, - AVTAB_MEMBER + AVTAB_MEMBER, + AVTAB_OPNUM_ALLOWED, + AVTAB_OPNUM_AUDITALLOW, + AVTAB_OPNUM_DONTAUDIT, + AVTAB_OPTYPE_ALLOWED, + AVTAB_OPTYPE_AUDITALLOW, + AVTAB_OPTYPE_DONTAUDIT }; int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a, int (*insertf) (avtab_t * a, avtab_key_t * k, avtab_datum_t * d, void *p), void *p) { + uint8_t buf8; uint16_t buf16[4], enabled; - uint32_t buf32[7], items, items2, val; + uint32_t buf32[8], items, items2, val; avtab_key_t key; avtab_datum_t datum; + avtab_operations_t ops; unsigned set; unsigned int i; int rc; memset(&key, 0, sizeof(avtab_key_t)); memset(&datum, 0, sizeof(avtab_datum_t)); + memset(&ops, 0, sizeof(avtab_operations_t)); if (vers < POLICYDB_VERSION_AVTAB) { rc = next_entry(buf32, fp, sizeof(uint32_t)); @@ -505,12 +533,34 @@ int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a, return -1; } - rc = next_entry(buf32, fp, sizeof(uint32_t)); - if (rc < 0) { - ERR(fp->handle, "truncated entry"); + if ((vers < POLICYDB_VERSION_IOCTL_OPERATIONS) && + (key.specified & AVTAB_OP)) { + ERR(fp->handle, "policy version %u does not support ioctl " + "operation rules and one was specified\n", vers); return -1; + } else if (key.specified & AVTAB_OP) { + rc = next_entry(&buf8, fp, sizeof(uint8_t)); + if (rc < 0) { + ERR(fp->handle, "truncated entry"); + return -1; + } + ops.type = buf8; + rc = next_entry(buf32, fp, sizeof(uint32_t)*8); + if (rc < 0) { + ERR(fp->handle, "truncated entry"); + return -1; + } + for (i = 0; i < ARRAY_SIZE(ops.perms); i++) + ops.perms[i] = le32_to_cpu(buf32[i]); + datum.ops = &ops; + } else { + rc = next_entry(buf32, fp, sizeof(uint32_t)); + if (rc < 0) { + ERR(fp->handle, "truncated entry"); + return -1; + } + datum.data = le32_to_cpu(*buf32); } - datum.data = le32_to_cpu(*buf32); return insertf(a, &key, &datum, p); } diff --git a/src/expand.c b/src/expand.c index 467f7a7..3f7f3e5 100644 --- a/src/expand.c +++ b/src/expand.c @@ -1602,13 +1602,29 @@ static int expand_range_trans(expand_state_t * state, */ static avtab_ptr_t find_avtab_node(sepol_handle_t * handle, avtab_t * avtab, avtab_key_t * key, - cond_av_list_t ** cond) + cond_av_list_t ** cond, + av_operations_t *operations) { avtab_ptr_t node; avtab_datum_t avdatum; cond_av_list_t *nl; + int type_match = 0; - node = avtab_search_node(avtab, key); + /* AVTAB_OPNUM entries are not necessarily unique */ + if (key->specified & AVTAB_OPNUM) { + node = avtab_search_node(avtab, key); + while (node) { + if (node->datum.ops->type == operations->type) { + type_match = 1; + break; + } + node = avtab_search_node_next(node, key->specified); + } + if (!type_match) + node = NULL; + } else { + node = avtab_search_node(avtab, key); + } /* If this is for conditional policies, keep searching in case the node is part of my conditional avtab. */ @@ -1732,7 +1748,7 @@ static int expand_terule_helper(sepol_handle_t * handle, return EXPAND_RULE_CONFLICT; } - node = find_avtab_node(handle, avtab, &avkey, cond); + node = find_avtab_node(handle, avtab, &avkey, cond, NULL); if (!node) return -1; if (enabled) { @@ -1763,13 +1779,15 @@ static int expand_avrule_helper(sepol_handle_t * handle, cond_av_list_t ** cond, uint32_t stype, uint32_t ttype, class_perm_node_t * perms, avtab_t * avtab, - int enabled) + int enabled, av_operations_t *operations) { avtab_key_t avkey; avtab_datum_t *avdatump; + avtab_operations_t *ops; avtab_ptr_t node; class_perm_node_t *cur; uint32_t spec = 0; + unsigned int i; if (specified & AVRULE_ALLOWED) { spec = AVTAB_ALLOWED; @@ -1783,6 +1801,22 @@ static int expand_avrule_helper(sepol_handle_t * handle, spec = AVTAB_AUDITDENY; } else if (specified & AVRULE_NEVERALLOW) { spec = AVTAB_NEVERALLOW; + } else if (specified & AVRULE_OPNUM_ALLOWED) { + spec = AVTAB_OPNUM_ALLOWED; + } else if (specified & AVRULE_OPNUM_AUDITALLOW) { + spec = AVTAB_OPNUM_AUDITALLOW; + } else if (specified & AVRULE_OPNUM_DONTAUDIT) { + if (handle && handle->disable_dontaudit) + return EXPAND_RULE_SUCCESS; + spec = AVTAB_OPNUM_DONTAUDIT; + } else if (specified & AVRULE_OPTYPE_ALLOWED) { + spec = AVTAB_OPTYPE_ALLOWED; + } else if (specified & AVRULE_OPTYPE_AUDITALLOW) { + spec = AVTAB_OPTYPE_AUDITALLOW; + } else if (specified & AVRULE_OPTYPE_DONTAUDIT) { + if (handle && handle->disable_dontaudit) + return EXPAND_RULE_SUCCESS; + spec = AVTAB_OPTYPE_DONTAUDIT; } else { assert(0); /* unreachable */ } @@ -1794,7 +1828,7 @@ static int expand_avrule_helper(sepol_handle_t * handle, avkey.target_class = cur->tclass; avkey.specified = spec; - node = find_avtab_node(handle, avtab, &avkey, cond); + node = find_avtab_node(handle, avtab, &avkey, cond, operations); if (!node) return EXPAND_RULE_ERROR; if (enabled) { @@ -1824,6 +1858,20 @@ static int expand_avrule_helper(sepol_handle_t * handle, avdatump->data &= ~cur->data; else avdatump->data = ~cur->data; + } else if (specified & AVRULE_OP) { + if (!avdatump->ops) { + ops = (avtab_operations_t *) + calloc(1, sizeof(avtab_operations_t)); + if (!ops) { + ERR(handle, "Out of memory!"); + return -1; + } + node->datum.ops = ops; + } + node->datum.ops->type = operations->type; + for (i = 0; i < ARRAY_SIZE(operations->perms); i++) { + node->datum.ops->perms[i] |= operations->perms[i]; + } } else { assert(0); /* should never occur */ } @@ -1848,10 +1896,10 @@ static int expand_rule_helper(sepol_handle_t * handle, if (!ebitmap_node_get_bit(snode, i)) continue; if (source_rule->flags & RULE_SELF) { - if (source_rule->specified & AVRULE_AV) { + if (source_rule->specified & (AVRULE_AV | AVRULE_OP)) { retval = expand_avrule_helper(handle, source_rule->specified, cond, i, i, source_rule->perms, - dest_avtab, enabled); + dest_avtab, enabled, source_rule->ops); if (retval != EXPAND_RULE_SUCCESS) return retval; } else { @@ -1866,10 +1914,10 @@ static int expand_rule_helper(sepol_handle_t * handle, ebitmap_for_each_bit(ttypes, tnode, j) { if (!ebitmap_node_get_bit(tnode, j)) continue; - if (source_rule->specified & AVRULE_AV) { + if (source_rule->specified & (AVRULE_AV | AVRULE_OP)) { retval = expand_avrule_helper(handle, source_rule->specified, cond, i, j, source_rule->perms, - dest_avtab, enabled); + dest_avtab, enabled, source_rule->ops); if (retval != EXPAND_RULE_SUCCESS) return retval; } else { @@ -3099,18 +3147,31 @@ static int expand_avtab_insert(avtab_t * a, avtab_key_t * k, avtab_datum_t * d) { avtab_ptr_t node; avtab_datum_t *avd; - int rc; - - node = avtab_search_node(a, k); - if (!node) { - rc = avtab_insert(a, k, d); - if (rc) - ERR(NULL, "Out of memory!"); - return rc; + avtab_operations_t *ops; + unsigned int i; + unsigned int type_match = 0; + + if (k->specified & AVTAB_OPNUM) { + /* + * AVTAB_OPNUM entries are not necessarily unique. + * find node with matching ops->type + */ + node = avtab_search_node(a, k); + while (node) { + if (node->datum.ops->type == d->ops->type) { + type_match = 1; + break; + } + node = avtab_search_node_next(node, k->specified); + } + if (!type_match) + node = NULL; + } else { + node = avtab_search_node(a, k); } - if ((k->specified & AVTAB_ENABLED) != - (node->key.specified & AVTAB_ENABLED)) { + if (!node || ((k->specified & AVTAB_ENABLED) != + (node->key.specified & AVTAB_ENABLED))) { node = avtab_insert_nonunique(a, k, d); if (!node) { ERR(NULL, "Out of memory!"); @@ -3120,6 +3181,7 @@ static int expand_avtab_insert(avtab_t * a, avtab_key_t * k, avtab_datum_t * d) } avd = &node->datum; + ops = node->datum.ops; switch (k->specified & ~AVTAB_ENABLED) { case AVTAB_ALLOWED: case AVTAB_AUDITALLOW: @@ -3128,6 +3190,15 @@ static int expand_avtab_insert(avtab_t * a, avtab_key_t * k, avtab_datum_t * d) case AVTAB_AUDITDENY: avd->data &= d->data; break; + case AVTAB_OPNUM_ALLOWED: + case AVTAB_OPNUM_AUDITALLOW: + case AVTAB_OPNUM_DONTAUDIT: + case AVTAB_OPTYPE_ALLOWED: + case AVTAB_OPTYPE_AUDITALLOW: + case AVTAB_OPTYPE_DONTAUDIT: + for (i = 0; i < ARRAY_SIZE(ops->perms); i++) + ops->perms[i] |= d->ops->perms[i]; + break; default: ERR(NULL, "Type conflict!"); return -1; diff --git a/src/policydb.c b/src/policydb.c index 667e98a..7dd493f 100644 --- a/src/policydb.c +++ b/src/policydb.c @@ -172,6 +172,13 @@ static struct policydb_compat_info policydb_compat[] = { .target_platform = SEPOL_TARGET_SELINUX, }, { + .type = POLICY_KERN, + .version = POLICYDB_VERSION_IOCTL_OPERATIONS, + .sym_num = SYM_NUM, + .ocon_num = OCON_NODE6 + 1, + .target_platform = SEPOL_TARGET_SELINUX, + }, + { .type = POLICY_BASE, .version = MOD_POLICYDB_VERSION_BASE, .sym_num = SYM_NUM, diff --git a/src/write.c b/src/write.c index d03dc20..36444bf 100644 --- a/src/write.c +++ b/src/write.c @@ -101,6 +101,7 @@ static int avtab_write_item(policydb_t * p, unsigned merge, unsigned commit, uint32_t * nel) { avtab_ptr_t node; + uint8_t buf8; uint16_t buf16[4]; uint32_t buf32[10], lookup, val; size_t items, items2; @@ -220,10 +221,38 @@ static int avtab_write_item(policydb_t * p, items = put_entry(buf16, sizeof(uint16_t), 4, fp); if (items != 4) return POLICYDB_ERROR; - buf32[0] = cpu_to_le32(cur->datum.data); - items = put_entry(buf32, sizeof(uint32_t), 1, fp); - if (items != 1) + if ((p->policyvers < POLICYDB_VERSION_IOCTL_OPERATIONS) && + (cur->key.specified & AVTAB_OP)) { + ERR(fp->handle, "policy version %u does not support ioctl operation" + " rules and one was specified", p->policyvers); + return POLICYDB_ERROR; + } + + if (p->target_platform != SEPOL_TARGET_SELINUX && + (cur->key.specified & AVTAB_OP)) { + ERR(fp->handle, "Target platform %s does not support ioctl " + "operation rules and one was specified", + policydb_target_strings[p->target_platform]); return POLICYDB_ERROR; + } + + if (cur->key.specified & AVTAB_OP) { + buf8 = cur->datum.ops->type; + items = put_entry(&buf8, sizeof(uint8_t),1,fp); + if (items != 1) + return POLICYDB_ERROR; + for (i = 0; i < ARRAY_SIZE(cur->datum.ops->perms); i++) + buf32[i] = cpu_to_le32(cur->datum.ops->perms[i]); + items = put_entry(buf32, sizeof(uint32_t),8,fp); + if (items != 8) + return POLICYDB_ERROR; + } else { + buf32[0] = cpu_to_le32(cur->datum.data); + items = put_entry(buf32, sizeof(uint32_t), 1, fp); + if (items != 1) + return POLICYDB_ERROR; + } + return POLICYDB_SUCCESS; } |