summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Vander Stoep <jeffv@google.com>2015-04-01 10:35:01 -0700
committerJeff Vander Stoep <jeffv@google.com>2015-04-14 14:55:40 -0700
commitf27738a7afe48b5c9937ffc5a4363d6086c4195b (patch)
treedfa95480c5f2baedd5c8c897fd6e71cf38494a51
parentc43eb7aea917a322b736fb88f647ff6c797b0db0 (diff)
downloadlibsepol-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.h37
-rw-r--r--include/sepol/policydb/policydb.h37
-rw-r--r--src/avtab.c66
-rw-r--r--src/expand.c109
-rw-r--r--src/policydb.c7
-rw-r--r--src/write.c35
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;
}