All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] checkpolicy: switch operations to extended perms
@ 2015-06-12 16:01 Jeff Vander Stoep
  2015-06-15 13:32 ` Stephen Smalley
  0 siblings, 1 reply; 2+ messages in thread
From: Jeff Vander Stoep @ 2015-06-12 16:01 UTC (permalink / raw)
  To: selinux

The ioctl operations code is being renamed to the more generic
"extended permissions." This commit brings the policy compiler
up to date with the kernel patch.

Signed-off-by: Jeff Vander Stoep <jeffv@google.com>
---
 checkpolicy/policy_define.c                | 343 +++++++++++++++--------------
 checkpolicy/policy_define.h                |   2 +-
 checkpolicy/policy_parse.y                 |  43 ++--
 checkpolicy/policy_scan.l                  |   6 +
 checkpolicy/test/dispol.c                  |  47 ++--
 libsepol/include/sepol/policydb/avtab.h    |  26 +--
 libsepol/include/sepol/policydb/policydb.h |  33 ++-
 libsepol/src/avtab.c                       |  54 ++---
 libsepol/src/expand.c                      | 102 ++++-----
 libsepol/src/policydb.c                    |   2 +-
 libsepol/src/write.c                       |  30 +--
 11 files changed, 363 insertions(+), 325 deletions(-)

diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c
index 093bded..8c01739 100644
--- a/checkpolicy/policy_define.c
+++ b/checkpolicy/policy_define.c
@@ -1728,32 +1728,31 @@ avrule_t *define_cond_pol_list(avrule_t * avlist, avrule_t * sl)
 	return sl;
 }
 
-#define operation_perm_test(x, p) (1 & (p[x >> 5] >> (x & 0x1f)))
-#define operation_perm_set(x, p) (p[x >> 5] |= (1 << (x & 0x1f)))
-#define operation_perm_clear(x, p) (p[x >> 5] &= ~(1 << (x & 0x1f)))
+#define xperm_test(x, p) (1 & (p[x >> 5] >> (x & 0x1f)))
+#define xperm_set(x, p) (p[x >> 5] |= (1 << (x & 0x1f)))
+#define xperm_clear(x, p) (p[x >> 5] &= ~(1 << (x & 0x1f)))
 
-typedef struct av_operations_range {
+typedef struct av_ioctl_range {
 	uint16_t low;
 	uint16_t high;
-} av_operations_range_t;
+} av_ioctl_range_t;
 
-struct av_operations_range_list {
+struct av_ioctl_range_list {
 	uint8_t omit;
-	av_operations_range_t range;
-	struct av_operations_range_list *next;
+	av_ioctl_range_t range;
+	struct av_ioctl_range_list *next;
 };
 
-int avrule_sort_operations(
-		struct av_operations_range_list **rangehead)
+int avrule_sort_ioctls(struct av_ioctl_range_list **rangehead)
 {
-	struct av_operations_range_list *r, *r2, *sorted, *sortedhead = NULL;
+	struct av_ioctl_range_list *r, *r2, *sorted, *sortedhead = NULL;
 
 	/* order list by range.low */
 	for (r = *rangehead; r != NULL; r = r->next) {
-		sorted = malloc(sizeof(struct av_operations_range_list));
+		sorted = malloc(sizeof(struct av_ioctl_range_list));
 		if (sorted == NULL)
 			goto error;
-		memcpy(sorted, r, sizeof(struct av_operations_range_list));
+		memcpy(sorted, r, sizeof(struct av_ioctl_range_list));
 		sorted->next = NULL;
 		if (sortedhead == NULL) {
 			sortedhead = sorted;
@@ -1792,9 +1791,9 @@ error:
 	return -1;
 }
 
-int avrule_merge_operations(struct av_operations_range_list **rangehead)
+int avrule_merge_ioctls(struct av_ioctl_range_list **rangehead)
 {
-	struct av_operations_range_list *r, *tmp;
+	struct av_ioctl_range_list *r, *tmp;
 	r = *rangehead;
 	while (r != NULL && r->next != NULL) {
 		/* merge */
@@ -1812,14 +1811,14 @@ int avrule_merge_operations(struct av_operations_range_list **rangehead)
 	return 0;
 }
 
-int avrule_read_operations(struct av_operations_range_list **rangehead)
+int avrule_read_ioctls(struct av_ioctl_range_list **rangehead)
 {
 	char *id;
-	struct av_operations_range_list *rnew, *r = NULL;
+	struct av_ioctl_range_list *rnew, *r = NULL;
 	*rangehead = NULL;
 	uint8_t omit = 0;
 
-	/* read in all the operations */
+	/* read in all the ioctl commands */
 	while ((id = queue_remove(id_queue))) {
 		if (strcmp(id,"~") == 0) {
 			/* these are values to be omitted */
@@ -1837,7 +1836,7 @@ int avrule_read_operations(struct av_operations_range_list **rangehead)
 			free(id);
 		} else {
 			/* read in new low value */
-			rnew = malloc(sizeof(struct av_operations_range_list));
+			rnew = malloc(sizeof(struct av_ioctl_range_list));
 			if (rnew == NULL)
 				goto error;
 			rnew->next = NULL;
@@ -1862,11 +1861,11 @@ error:
 }
 
 /* flip to included ranges */
-int avrule_omit_operations(struct av_operations_range_list **rangehead)
+int avrule_omit_ioctls(struct av_ioctl_range_list **rangehead)
 {
-	struct av_operations_range_list *rnew, *r, *newhead, *r2;
+	struct av_ioctl_range_list *rnew, *r, *newhead, *r2;
 
-	rnew = calloc(1, sizeof(struct av_operations_range_list));
+	rnew = calloc(1, sizeof(struct av_ioctl_range_list));
 	if (!rnew)
 		goto error;
 
@@ -1884,7 +1883,7 @@ int avrule_omit_operations(struct av_operations_range_list **rangehead)
 
 	while (r) {
 		r2->range.high = r->range.low - 1;
-		rnew = calloc(1, sizeof(struct av_operations_range_list));
+		rnew = calloc(1, sizeof(struct av_ioctl_range_list));
 		if (!rnew)
 			goto error;
 		r2->next = rnew;
@@ -1910,27 +1909,27 @@ error:
 	return -1;
 }
 
-int avrule_operation_ranges(struct av_operations_range_list **rangelist)
+int avrule_ioctl_ranges(struct av_ioctl_range_list **rangelist)
 {
-	struct av_operations_range_list *rangehead;
+	struct av_ioctl_range_list *rangehead;
 	uint8_t omit;
 
 	/* read in ranges to include and omit */
-	if (avrule_read_operations(&rangehead))
+	if (avrule_read_ioctls(&rangehead))
 		return -1;
 	omit = rangehead->omit;
 	if (rangehead == NULL) {
-		yyerror("error processing ioctl operations");
+		yyerror("error processing ioctl commands");
 		return -1;
 	}
-	/* sort and merge the input operations */
-	if (avrule_sort_operations(&rangehead))
+	/* sort and merge the input ioctls */
+	if (avrule_sort_ioctls(&rangehead))
 		return -1;
-	if (avrule_merge_operations(&rangehead))
+	if (avrule_merge_ioctls(&rangehead))
 		return -1;
 	/* flip ranges if these are ommited*/
 	if (omit) {
-		if (avrule_omit_operations(&rangehead))
+		if (avrule_omit_ioctls(&rangehead))
 			return -1;
 	}
 
@@ -1938,7 +1937,7 @@ int avrule_operation_ranges(struct av_operations_range_list **rangelist)
 	return 0;
 }
 
-int define_te_avtab_operation_helper(int which, avrule_t ** rule)
+int define_te_avtab_xperms_helper(int which, avrule_t ** rule)
 {
 	char *id;
 	class_perm_node_t *perms, *tail = NULL, *cur_perms = NULL;
@@ -1959,7 +1958,7 @@ int define_te_avtab_operation_helper(int which, avrule_t ** rule)
 	avrule->line = policydb_lineno;
 	avrule->source_line = source_lineno;
 	avrule->source_filename = strdup(source_file);
-	avrule->ops = NULL;
+	avrule->xperms = NULL;
 	if (!avrule->source_filename) {
 		yyerror("out of memory");
 		return -1;
@@ -2023,95 +2022,102 @@ out:
 }
 
 /* index of the u32 containing the permission */
-#define OP_IDX(x) (x >> 5)
+#define XPERM_IDX(x) (x >> 5)
 /* set bits 0 through x-1 within the u32 */
-#define OP_SETBITS(x) ((1 << (x & 0x1f)) - 1)
+#define XPERM_SETBITS(x) ((1 << (x & 0x1f)) - 1)
 /* low value for this u32 */
-#define OP_LOW(x) (x << 5)
+#define XPERM_LOW(x) (x << 5)
 /* high value for this u32 */
-#define OP_HIGH(x) (((x + 1) << 5) - 1)
-void avrule_operation_setrangebits(uint16_t low, uint16_t high, av_operations_t *ops)
+#define XPERM_HIGH(x) (((x + 1) << 5) - 1)
+void avrule_xperm_setrangebits(uint16_t low, uint16_t high,
+				av_extended_perms_t *xperms)
 {
 	unsigned int i;
 	uint16_t h = high + 1;
-	/* for each u32 that this low-high range touches, set type permissions */
-	for (i = OP_IDX(low); i <= OP_IDX(high); i++) {
+	/* for each u32 that this low-high range touches, set driver permissions */
+	for (i = XPERM_IDX(low); i <= XPERM_IDX(high); i++) {
 		/* set all bits in u32 */
-		if ((low <= OP_LOW(i)) && (high >= OP_HIGH(i)))
-			ops->perms[i] |= ~0U;
+		if ((low <= XPERM_LOW(i)) && (high >= XPERM_HIGH(i)))
+			xperms->perms[i] |= ~0U;
 		/* set low bits */
-		else if ((low <= OP_LOW(i)) && (high < OP_HIGH(i)))
-			ops->perms[i] |= OP_SETBITS(h);
+		else if ((low <= XPERM_LOW(i)) && (high < XPERM_HIGH(i)))
+			xperms->perms[i] |= XPERM_SETBITS(h);
 		/* set high bits */
-		else if ((low > OP_LOW(i)) && (high >= OP_HIGH(i)))
-			ops->perms[i] |= ~0U - OP_SETBITS(low);
+		else if ((low > XPERM_LOW(i)) && (high >= XPERM_HIGH(i)))
+			xperms->perms[i] |= ~0U - XPERM_SETBITS(low);
 		/* set middle bits */
-		else if ((low > OP_LOW(i)) && (high <= OP_HIGH(i)))
-			ops->perms[i] |= OP_SETBITS(h) - OP_SETBITS(low);
+		else if ((low > XPERM_LOW(i)) && (high <= XPERM_HIGH(i)))
+			xperms->perms[i] |= XPERM_SETBITS(h) - XPERM_SETBITS(low);
 	}
 }
 
-int avrule_operation_used(av_operations_t *ops)
+int avrule_xperms_used(av_extended_perms_t *xperms)
 {
 	unsigned int i;
 
-	for (i = 0; i < sizeof(ops->perms)/sizeof(ops->perms[0]); i++) {
-		if (ops->perms[i])
+	for (i = 0; i < sizeof(xperms->perms)/sizeof(xperms->perms[0]); i++) {
+		if (xperms->perms[i])
 			return 1;
 	}
 	return 0;
 }
 
-#define OP_TYPE(x) (x >> 8)
-#define OP_NUM(x) (x & 0xff)
-#define OP_CMD(type, num) ((type << 8) + num)
-int avrule_operation_partialtype(struct av_operations_range_list *rangelist,
-				av_operations_t *complete_type,
-				av_operations_t **operations)
+/*
+ * using definitions found in kernel document ioctl-number.txt
+ * The kernel components of an ioctl command are:
+ * dir, size, driver, and fucntion. Only the driver and function fields
+ * are considered here
+ */
+#define IOC_DRIV(x) (x >> 8)
+#define IOC_FUNC(x) (x & 0xff)
+#define IOC_CMD(driver, func) ((driver << 8) + func)
+int avrule_ioctl_partialdriver(struct av_ioctl_range_list *rangelist,
+				av_extended_perms_t *complete_driver,
+				av_extended_perms_t **extended_perms)
 {
-	struct av_operations_range_list *r;
-	av_operations_t *ops;
+	struct av_ioctl_range_list *r;
+	av_extended_perms_t *xperms;
 	uint8_t low, high;
 
-	ops = calloc(1, sizeof(av_operations_t));
-	if (!ops) {
+	xperms = calloc(1, sizeof(av_extended_perms_t));
+	if (!xperms) {
 		yyerror("out of memory");
 		return - 1;
 	}
 
 	r = rangelist;
 	while(r) {
-		low = OP_TYPE(r->range.low);
-		high = OP_TYPE(r->range.high);
-		if (complete_type) {
-			if (!operation_perm_test(low, complete_type->perms))
-				operation_perm_set(low, ops->perms);
-			if (!operation_perm_test(high, complete_type->perms))
-				operation_perm_set(high, ops->perms);
+		low = IOC_DRIV(r->range.low);
+		high = IOC_DRIV(r->range.high);
+		if (complete_driver) {
+			if (!xperm_test(low, complete_driver->perms))
+				xperm_set(low, xperms->perms);
+			if (!xperm_test(high, complete_driver->perms))
+				xperm_set(high, xperms->perms);
 		} else {
-			operation_perm_set(low, ops->perms);
-			operation_perm_set(high, ops->perms);
+			xperm_set(low, xperms->perms);
+			xperm_set(high, xperms->perms);
 		}
 		r = r->next;
 	}
-	if (avrule_operation_used(ops)) {
-		*operations = ops;
+	if (avrule_xperms_used(xperms)) {
+		*extended_perms = xperms;
 	} else {
-		free(ops);
-		*operations = NULL;
+		free(xperms);
+		*extended_perms = NULL;
 	}
 	return 0;
 
 }
 
-int avrule_operation_completetype(struct av_operations_range_list *rangelist,
-			av_operations_t **operations)
+int avrule_ioctl_completedriver(struct av_ioctl_range_list *rangelist,
+			av_extended_perms_t **extended_perms)
 {
-	struct av_operations_range_list *r;
-	av_operations_t *ops;
+	struct av_ioctl_range_list *r;
+	av_extended_perms_t *xperms;
 	uint16_t low, high;
-	ops = calloc(1, sizeof(av_operations_t));
-	if (!ops) {
+	xperms = calloc(1, sizeof(av_extended_perms_t));
+	if (!xperms) {
 		yyerror("out of memory");
 		return - 1;
 	}
@@ -2119,83 +2125,86 @@ int avrule_operation_completetype(struct av_operations_range_list *rangelist,
 	r = rangelist;
 	while(r) {
 		/*
-		 * Any type that has numbers 0x00 - 0xff is a complete type,
+		 * Any driver code that has sequence 0x00 - 0xff is a complete code,
 		 *
-		 * if command number = 0xff, then round high up to next type,
-		 * else 0x00 - 0xfe keep current type
+		 * if command number = 0xff, then round high up to next code,
+		 * else 0x00 - 0xfe keep current code
 		 * of this range. temporarily u32 for the + 1
 		 * to account for possible rollover before right shift
 		 */
-		high = OP_TYPE((uint32_t) (r->range.high + 1));
-		/* if 0x00 keep current type else 0x01 - 0xff round up to next type */
-		low = OP_TYPE(r->range.low);
-		if (OP_NUM(r->range.low))
+		high = IOC_DRIV((uint32_t) (r->range.high + 1));
+		/* if 0x00 keep current driver code else 0x01 - 0xff round up to next code*/
+		low = IOC_DRIV(r->range.low);
+		if (IOC_FUNC(r->range.low))
 			low++;
 		if (high > low)
-			avrule_operation_setrangebits(low, high - 1, ops);
+			avrule_xperm_setrangebits(low, high - 1, xperms);
 		r = r->next;
 	}
-	if (avrule_operation_used(ops)) {
-		*operations = ops;
+	if (avrule_xperms_used(xperms)) {
+		xperms->driver = 0x00;
+		xperms->specified = AVRULE_XPERMS_IOCTLDRIVER;
+		*extended_perms = xperms;
 	} else {
-		free(ops);
-		*operations = NULL;
+		free(xperms);
+		*extended_perms = NULL;
 	}
 	return 0;
 }
 
-int avrule_operation_num(struct av_operations_range_list *rangelist,
-		av_operations_t **operations, unsigned int type)
+int avrule_ioctl_func(struct av_ioctl_range_list *rangelist,
+		av_extended_perms_t **extended_perms, unsigned int driver)
 {
-	struct av_operations_range_list *r;
-	av_operations_t *ops;
+	struct av_ioctl_range_list *r;
+	av_extended_perms_t *xperms;
 	uint16_t low, high;
 
-	*operations = NULL;
-	ops = calloc(1, sizeof(av_operations_t));
-	if (!ops) {
+	*extended_perms = NULL;
+	xperms = calloc(1, sizeof(av_extended_perms_t));
+	if (!xperms) {
 		yyerror("out of memory");
 		return - 1;
 	}
 
 	r = rangelist;
-	/* for the passed in types, find the ranges that apply */
+	/* for the passed in driver code, find the ranges that apply */
 	while (r) {
 		low = r->range.low;
 		high = r->range.high;
-		if ((type != OP_TYPE(low)) && (type != OP_TYPE(high))) {
+		if ((driver != IOC_DRIV(low)) && (driver != IOC_DRIV(high))) {
 			r = r->next;
 			continue;
 		}
 
-		if (type == OP_TYPE(low)) {
-			if (high > OP_CMD(type, 0xff))
-				high = OP_CMD(type, 0xff);
+		if (driver == IOC_DRIV(low)) {
+			if (high > IOC_CMD(driver, 0xff))
+				high = IOC_CMD(driver, 0xff);
 
 		} else {
-			if (low < OP_CMD(type, 0))
-				low = OP_CMD(type, 0);
+			if (low < IOC_CMD(driver, 0))
+				low = IOC_CMD(driver, 0);
 		}
 
-		low = OP_NUM(low);
-		high = OP_NUM(high);
-		avrule_operation_setrangebits(low, high, ops);
-		ops->type = type;
+		low = IOC_FUNC(low);
+		high = IOC_FUNC(high);
+		avrule_xperm_setrangebits(low, high, xperms);
+		xperms->driver = driver;
+		xperms->specified = AVRULE_XPERMS_IOCTLFUNCTION;
 		r = r->next;
 	}
 
-	if (avrule_operation_used(ops)) {
-		*operations = ops;
+	if (avrule_xperms_used(xperms)) {
+		*extended_perms = xperms;
 	} else {
-		free(ops);
-		*operations = NULL;
+		free(xperms);
+		*extended_perms = NULL;
 	}
 	return 0;
 }
 
-void avrule_operation_freeranges(struct av_operations_range_list *rangelist)
+void avrule_ioctl_freeranges(struct av_ioctl_range_list *rangelist)
 {
-	struct av_operations_range_list *r, *tmp;
+	struct av_ioctl_range_list *r, *tmp;
 	r = rangelist;
 	while (r) {
 		tmp = r;
@@ -2204,12 +2213,12 @@ void avrule_operation_freeranges(struct av_operations_range_list *rangelist)
 	}
 }
 
-unsigned int operation_for_each_bit(unsigned int *bit, av_operations_t *ops)
+unsigned int xperms_for_each_bit(unsigned int *bit, av_extended_perms_t *xperms)
 {
 	unsigned int i;
-	for (i = *bit; i < sizeof(ops->perms)*8; i++) {
-		if (operation_perm_test(i,ops->perms)) {
-			operation_perm_clear(i, ops->perms);
+	for (i = *bit; i < sizeof(xperms->perms)*8; i++) {
+		if (xperm_test(i,xperms->perms)) {
+			xperm_clear(i, xperms->perms);
 			*bit = i;
 			return 1;
 		}
@@ -2261,35 +2270,22 @@ int avrule_cpy(avrule_t *dest, avrule_t *src)
 	return 0;
 }
 
-int define_te_avtab_operation(int which)
+int define_te_avtab_ioctl(avrule_t *avrule_template)
 {
-	char *id;
-	avrule_t *avrule_template;
 	avrule_t *avrule;
-	struct av_operations_range_list *rangelist;
-	av_operations_t *complete_type, *partial_type, *ops;
+	struct av_ioctl_range_list *rangelist;
+	av_extended_perms_t *complete_driver, *partial_driver, *xperms;
 	unsigned int i;
 
-	if (pass == 1) {
-		for (i = 0; i < 4; i++) {
-			while ((id = queue_remove(id_queue)))
-				free(id);
-		}
-		return 0;
-	}
-
-	/* populate avrule template with source/target/tclass */
-	if (define_te_avtab_operation_helper(which, &avrule_template))
-		return -1;
 
-	/* organize operation ranges */
-	if (avrule_operation_ranges(&rangelist))
+	/* organize ioctl ranges */
+	if (avrule_ioctl_ranges(&rangelist))
 		return -1;
 
-	/* create rule for ioctl operation types that are entirely enabled */
-	if (avrule_operation_completetype(rangelist, &complete_type))
+	/* create rule for ioctl driver types that are entirely enabled */
+	if (avrule_ioctl_completedriver(rangelist, &complete_driver))
 		return -1;
-	if (complete_type) {
+	if (complete_driver) {
 		avrule = (avrule_t *) calloc(1, sizeof(avrule_t));
 		if (!avrule) {
 			yyerror("out of memory");
@@ -2297,31 +2293,28 @@ int define_te_avtab_operation(int which)
 		}
 		if (avrule_cpy(avrule, avrule_template))
 			return -1;
-		avrule->ops = complete_type;
-		if (which == AVRULE_OPNUM_ALLOWED)
-			avrule->specified = AVRULE_OPTYPE_ALLOWED;
-		else if (which == AVRULE_OPNUM_AUDITALLOW)
-			avrule->specified = AVRULE_OPTYPE_AUDITALLOW;
-		else if (which == AVRULE_OPNUM_DONTAUDIT)
-			avrule->specified = AVRULE_OPTYPE_DONTAUDIT;
-
+		avrule->xperms = complete_driver;
 		append_avrule(avrule);
 	}
 
-	/* flag ioctl types that are partially enabled */
-	if (avrule_operation_partialtype(rangelist, complete_type, &partial_type))
+	/* flag ioctl driver codes that are partially enabled */
+	if (avrule_ioctl_partialdriver(rangelist, complete_driver, &partial_driver))
 		return -1;
 
-	if (!partial_type || !avrule_operation_used(partial_type))
+	if (!partial_driver || !avrule_xperms_used(partial_driver))
 		goto done;
 
-	/* create rule for each partially enabled type */
+	/*
+	 * 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 (operation_for_each_bit(&i, partial_type)) {
-		if (avrule_operation_num(rangelist, &ops, i))
+	while (xperms_for_each_bit(&i, partial_driver)) {
+		if (avrule_ioctl_func(rangelist, &xperms, i))
 			return -1;
 
-		if (ops) {
+		if (xperms) {
 			avrule = (avrule_t *) calloc(1, sizeof(avrule_t));
 			if (!avrule) {
 				yyerror("out of memory");
@@ -2329,15 +2322,45 @@ int define_te_avtab_operation(int which)
 			}
 			if (avrule_cpy(avrule, avrule_template))
 				return -1;
-			avrule->ops = ops;
+			avrule->xperms = xperms;
 			append_avrule(avrule);
 		}
 	}
 
 done:
-	if (partial_type)
-		free(partial_type);
+	if (partial_driver)
+		free(partial_driver);
+
+	return 0;
+}
+
+int define_te_avtab_extended_perms(int which)
+{
+	char *id;
+	unsigned int i;
+	avrule_t *avrule_template;
+
+	if (pass == 1) {
+		for (i = 0; i < 4; i++) {
+			while ((id = queue_remove(id_queue)))
+				free(id);
+		}
+		return 0;
+	}
 
+	/* populate avrule template with source/target/tclass */
+	if (define_te_avtab_xperms_helper(which, &avrule_template))
+		return -1;
+
+	id = queue_remove(id_queue);
+	if (strcmp(id,"ioctl") == 0) {
+		if (define_te_avtab_ioctl(avrule_template))
+			return -1;
+		free(id);
+	} else {
+		yyerror("only ioctl extended permissions are supported");
+		return -1;
+	}
 	return 0;
 }
 
@@ -2365,7 +2388,7 @@ int define_te_avtab_helper(int which, avrule_t ** rule)
 	avrule->line = policydb_lineno;
 	avrule->source_line = source_lineno;
 	avrule->source_filename = strdup(source_file);
-	avrule->ops = NULL;
+	avrule->xperms = NULL;
 	if (!avrule->source_filename) {
 		yyerror("out of memory");
 		return -1;
diff --git a/checkpolicy/policy_define.h b/checkpolicy/policy_define.h
index 43c7c08..964baae 100644
--- a/checkpolicy/policy_define.h
+++ b/checkpolicy/policy_define.h
@@ -58,7 +58,7 @@ int define_roleattribute(void);
 int define_filename_trans(void);
 int define_sens(void);
 int define_te_avtab(int which);
-int define_te_avtab_operation(int which);
+int define_te_avtab_extended_perms(int which);
 int define_typealias(void);
 int define_typeattribute(void);
 int define_typebounds(void);
diff --git a/checkpolicy/policy_parse.y b/checkpolicy/policy_parse.y
index 059b7b8..d8b8ac0 100644
--- a/checkpolicy/policy_parse.y
+++ b/checkpolicy/policy_parse.y
@@ -126,6 +126,9 @@ typedef int (* require_func_t)(int pass);
 %token AUDITALLOW
 %token AUDITDENY
 %token DONTAUDIT
+%token ALLOWXPERM
+%token AUDITALLOWXPERM
+%token DONTAUDITXPERM
 %token SOURCE
 %token TARGET
 %token SAMEUSER
@@ -457,9 +460,9 @@ te_avtab_def		: allow_def
 			| auditdeny_def
 			| dontaudit_def
 			| neverallow_def
-			| operation_allow_def
-			| operation_auditallow_def
-			| operation_dontaudit_def
+			| xperm_allow_def
+			| xperm_auditallow_def
+			| xperm_dontaudit_def
 			;
 allow_def		: ALLOW names names ':' names names  ';'
 			{if (define_te_avtab(AVRULE_ALLOWED)) return -1; }
@@ -476,14 +479,14 @@ dontaudit_def		: DONTAUDIT names names ':' names names ';'
 neverallow_def		: NEVERALLOW names names ':' names names  ';'
 			{if (define_te_avtab(AVRULE_NEVERALLOW)) return -1; }
 		        ;
-operation_allow_def	: ALLOW names names ':' names  operations ';'
-			{if (define_te_avtab_operation(AVRULE_OPNUM_ALLOWED)) return -1; }
+xperm_allow_def		: ALLOWXPERM names names ':' names identifier xperms ';'
+			{if (define_te_avtab_extended_perms(AVRULE_XPERMS_ALLOWED)) return -1; }
 		        ;
-operation_auditallow_def: AUDITALLOW names names ':' names operations ';'
-			{if (define_te_avtab_operation(AVRULE_OPNUM_AUDITALLOW)) return -1; }
+xperm_auditallow_def	: AUDITALLOWXPERM names names ':' names identifier xperms ';'
+			{if (define_te_avtab_extended_perms(AVRULE_XPERMS_AUDITALLOW)) return -1; }
 		        ;
-operation_dontaudit_def	: DONTAUDIT names names ':' names operations ';'
-			{if (define_te_avtab_operation(AVRULE_OPNUM_DONTAUDIT)) return -1; }
+xperm_dontaudit_def	: DONTAUDITXPERM names names ':' names identifier xperms ';'
+			{if (define_te_avtab_extended_perms(AVRULE_XPERMS_DONTAUDIT)) return -1; }
 		        ;
 attribute_role_def	: ATTRIBUTE_ROLE identifier ';'
 			{if (define_attrib_role()) return -1; }
@@ -749,26 +752,26 @@ genfs_context_def	: GENFSCON filesystem path '-' identifier security_context_def
 ipv4_addr_def		: IPV4_ADDR
 			{ if (insert_id(yytext,0)) return -1; }
 			;
-operations		: operation
+xperms		: xperm
 			{ if (insert_separator(0)) return -1; }
-			| nested_operation_set
+			| nested_xperm_set
 			{ if (insert_separator(0)) return -1; }
-			| tilde operation
+			| tilde xperm
                         { if (insert_id("~", 0)) return -1; }
-			| tilde nested_operation_set
+			| tilde nested_xperm_set
 			{ if (insert_id("~", 0)) return -1;
 			  if (insert_separator(0)) return -1; }
 			;
-nested_operation_set	: '{' nested_operation_list '}'
+nested_xperm_set	: '{' nested_xperm_list '}'
 			;
-nested_operation_list	: nested_operation_element
-			| nested_operation_list nested_operation_element
+nested_xperm_list	: nested_xperm_element
+			| nested_xperm_list nested_xperm_element
 			;
-nested_operation_element: operation '-' { if (insert_id("-", 0)) return -1; } operation
-			| operation
-			| nested_operation_set
+nested_xperm_element: xperm '-' { if (insert_id("-", 0)) return -1; } xperm
+			| xperm
+			| nested_xperm_set
 			;
-operation		: number
+xperm		: number
                         { if (insert_id(yytext,0)) return -1; }
 			;
 security_context_def	: identifier ':' identifier ':' identifier opt_mls_range_def
diff --git a/checkpolicy/policy_scan.l b/checkpolicy/policy_scan.l
index 108edbc..e94a917 100644
--- a/checkpolicy/policy_scan.l
+++ b/checkpolicy/policy_scan.l
@@ -142,6 +142,12 @@ AUDITDENY |
 auditdeny		        { return(AUDITDENY); }
 DONTAUDIT |
 dontaudit                       { return(DONTAUDIT); }
+ALLOWXPERM |
+allowxperm		        { return(ALLOWXPERM); }
+AUDITALLOWXPERM |
+auditallowxperm		        { return(AUDITALLOWXPERM); }
+DONTAUDITXPERM |
+dontauditxperm                  { return(DONTAUDITXPERM); }
 SOURCE |
 source			        { return(SOURCE); }
 TARGET |
diff --git a/checkpolicy/test/dispol.c b/checkpolicy/test/dispol.c
index 157361a..0c6b8d8 100644
--- a/checkpolicy/test/dispol.c
+++ b/checkpolicy/test/dispol.c
@@ -54,11 +54,11 @@ int render_access_mask(uint32_t mask, avtab_key_t * key, policydb_t * p,
 	return 0;
 }
 
-#define operation_perm_test(x, p) (1 & (p[x >> 5] >> (x & 0x1f)))
+#define xperms_test(x, p) (1 & (p[x >> 5] >> (x & 0x1f)))
 #define next_bit_in_range(i, p) \
-	((i + 1 < sizeof(p)*8) && operation_perm_test((i + 1), p))
+	((i + 1 < sizeof(p)*8) && xperms_test((i + 1), p))
 
-int render_operations(avtab_operations_t *ops, avtab_key_t * key, FILE * fp)
+int render_ioctl(avtab_extended_perms_t * xperms, FILE * fp)
 {
 	uint16_t value;
 	uint16_t low_bit;
@@ -67,28 +67,28 @@ int render_operations(avtab_operations_t *ops, avtab_key_t * key, FILE * fp)
 	unsigned int in_range = 0;
 
 	fprintf(fp, "{ ");
-	for (bit = 0; bit < sizeof(ops->perms)*8; bit++) {
-		if (!operation_perm_test(bit, ops->perms))
+	for (bit = 0; bit < sizeof(xperms->perms)*8; bit++) {
+		if (!xperms_test(bit, xperms->perms))
 			continue;
 
-		if (in_range && next_bit_in_range(bit, ops->perms)) {
+		if (in_range && next_bit_in_range(bit, xperms->perms)) {
 			/* continue until high value found */
 			continue;
-		} else if (next_bit_in_range(bit, ops->perms)) {
+		} else if (next_bit_in_range(bit, xperms->perms)) {
 			/* low value */
 			low_bit = bit;
 			in_range = 1;
 			continue;
 		}
 
-		if (key->specified & AVTAB_OPNUM) {
-			value = ops->type<<8 | bit;
-			low_value = ops->type<<8 | low_bit;
+		if (xperms->specified & AVTAB_XPERMS_IOCTLFUNCTION) {
+			value = xperms->driver<<8 | bit;
+			low_value = xperms->driver<<8 | low_bit;
 			if (in_range)
 				fprintf(fp, "0x%hx-0x%hx ", low_value, value);
 			else
 				fprintf(fp, "0x%hx ", value);
-		} else if (key->specified & AVTAB_OPTYPE) {
+		} else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) {
 			value = bit << 8;
 			low_value = low_bit << 8;
 			if (in_range)
@@ -104,6 +104,15 @@ int render_operations(avtab_operations_t *ops, avtab_key_t * key, FILE * fp)
 	return 0;
 }
 
+int render_xperms(avtab_extended_perms_t * xperms, FILE * fp)
+{
+	if ((xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) ||
+			(xperms->specified == AVTAB_XPERMS_IOCTLDRIVER))
+		render_ioctl(xperms, fp);
+
+	return 0;
+}
+
 int render_type(uint32_t type, policydb_t * p, FILE * fp)
 {
 	fprintf(fp, "%s", p->p_type_val_to_name[type - 1]);
@@ -197,15 +206,15 @@ int render_av_rule(avtab_key_t * key, avtab_datum_t * datum, uint32_t what,
 			render_type(datum->data, p, fp);
 			fprintf(fp, ";\n");
 		}
-	} else if (key->specified & AVTAB_OP) {
-		if (key->specified & (AVTAB_OPNUM_ALLOWED|AVTAB_OPTYPE_ALLOWED))
-			fprintf(fp, "allow ");
-		else if (key->specified & (AVTAB_OPNUM_AUDITALLOW|AVTAB_OPTYPE_AUDITALLOW))
-			fprintf(fp, "auditallow ");
-		else if (key->specified & (AVTAB_OPNUM_DONTAUDIT|AVTAB_OPTYPE_DONTAUDIT))
-			fprintf(fp, "dontaudit ");
+	} else if (key->specified & AVTAB_XPERMS) {
+		if (key->specified & AVTAB_XPERMS_ALLOWED)
+			fprintf(fp, "allowxperm ");
+		else if (key->specified & AVTAB_XPERMS_AUDITALLOW)
+			fprintf(fp, "auditallowxperm ");
+		else if (key->specified & AVTAB_XPERMS_DONTAUDIT)
+			fprintf(fp, "dontauditxperm ");
 		render_key(key, p, fp);
-		render_operations(datum->ops, key, fp);
+		render_xperms(datum->xperms, fp);
 		fprintf(fp, ";\n");
 	} else {
 		fprintf(fp, "     ERROR: no valid rule type specified\n");
diff --git a/libsepol/include/sepol/policydb/avtab.h b/libsepol/include/sepol/policydb/avtab.h
index 2ea821c..14bc082 100644
--- a/libsepol/include/sepol/policydb/avtab.h
+++ b/libsepol/include/sepol/policydb/avtab.h
@@ -59,28 +59,28 @@ typedef struct avtab_key {
 #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_XPERMS_ALLOWED	0x0100
+#define AVTAB_XPERMS_AUDITALLOW	0x0200
+#define AVTAB_XPERMS_DONTAUDIT	0x0400
+#define AVTAB_XPERMS		(AVTAB_XPERMS_ALLOWED | AVTAB_XPERMS_AUDITALLOW | AVTAB_XPERMS_DONTAUDIT)
 #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;
+typedef struct avtab_extended_perms {
+
+#define AVTAB_XPERMS_IOCTLFUNCTION	0x01
+#define AVTAB_XPERMS_IOCTLDRIVER	0x02
+	/* extension of the avtab_key specified */
+	uint8_t specified;
+	uint8_t driver;
 	uint32_t perms[8];
-} avtab_operations_t;
+} avtab_extended_perms_t;
 
 typedef struct avtab_datum {
 	uint32_t data;		/* access vector or type */
-	avtab_operations_t *ops;
+	avtab_extended_perms_t *xperms;
 } avtab_datum_t;
 
 typedef struct avtab_node *avtab_ptr_t;
diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
index 1d8310c..78b09c4 100644
--- a/libsepol/include/sepol/policydb/policydb.h
+++ b/libsepol/include/sepol/policydb/policydb.h
@@ -241,11 +241,14 @@ 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 */
+typedef struct av_extended_perms {
+#define AVRULE_XPERMS_IOCTLFUNCTION	0x01
+#define AVRULE_XPERMS_IOCTLDRIVER	0x02
+	uint8_t specified;
+	uint8_t driver;
+	/* 256 bits of permissions */
 	uint32_t perms[8];
-} av_operations_t;
+} av_extended_perms_t;
 
 typedef struct avrule {
 /* these typedefs are almost exactly the same as those in avtab.h - they are
@@ -260,24 +263,18 @@ typedef struct avrule {
 #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)
+#define AVRULE_XPERMS_ALLOWED 		0x0100
+#define AVRULE_XPERMS_AUDITALLOW	0x0200
+#define AVRULE_XPERMS_DONTAUDIT		0x0400
+#define AVRULE_XPERMS	(AVRULE_XPERMS_ALLOWED | AVRULE_XPERMS_AUDITALLOW | \
+				AVRULE_XPERMS_DONTAUDIT)
 	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;
+	av_extended_perms_t *xperms;
 	unsigned long line;	/* line number from policy.conf where
 				 * this rule originated  */
 	/* source file name and line number (e.g. .te file) */
@@ -709,11 +706,11 @@ extern int policydb_set_target_platform(policydb_t *p, int platform);
 #define POLICYDB_VERSION_DEFAULT_TYPE	28
 #define POLICYDB_VERSION_CONSTRAINT_NAMES	29
 #define POLICYDB_VERSION_XEN_DEVICETREE		30 /* Xen-specific */
-#define POLICYDB_VERSION_IOCTL_OPERATIONS	30 /* Linux-specific */
+#define POLICYDB_VERSION_XPERMS_IOCTL	30 /* Linux-specific */
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN	POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_IOCTL_OPERATIONS
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_XPERMS_IOCTL
 
 /* Module versions and specific changes*/
 #define MOD_POLICYDB_VERSION_BASE		4
diff --git a/libsepol/src/avtab.c b/libsepol/src/avtab.c
index d3745fe..799b98f 100644
--- a/libsepol/src/avtab.c
+++ b/libsepol/src/avtab.c
@@ -93,7 +93,7 @@ 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;
+	avtab_extended_perms_t *xperms;
 
 	newnode = (avtab_ptr_t) malloc(sizeof(struct avtab_node));
 	if (newnode == NULL)
@@ -101,16 +101,16 @@ avtab_insert_node(avtab_t * h, int hvalue, avtab_ptr_t prev, avtab_key_t * key,
 	memset(newnode, 0, sizeof(struct avtab_node));
 	newnode->key = *key;
 
-	if (key->specified & AVTAB_OP) {
-		ops = calloc(1, sizeof(avtab_operations_t));
-		if (ops == NULL) {
+	if (key->specified & AVTAB_XPERMS) {
+		xperms = calloc(1, sizeof(avtab_extended_perms_t));
+		if (xperms == NULL) {
 			free(newnode);
 			return NULL;
 		}
-		if (datum->ops) /* else caller populates ops*/
-			*ops = *(datum->ops);
+		if (datum->xperms) /* else caller populates xperms */
+			*xperms = *(datum->xperms);
 
-		newnode->datum.ops = ops;
+		newnode->datum.xperms = xperms;
 	} else {
 		newnode->datum = *datum;
 	}
@@ -144,7 +144,8 @@ int avtab_insert(avtab_t * h, avtab_key_t * key, avtab_datum_t * datum)
 		    key->target_type == cur->key.target_type &&
 		    key->target_class == cur->key.target_class &&
 		    (specified & cur->key.specified)) {
-			if (specified & AVTAB_OPNUM)
+			/* Extended permissions are not necessarily unique */
+			if (specified & AVTAB_XPERMS)
 				break;
 			return SEPOL_EEXIST;
 		}
@@ -416,12 +417,9 @@ static uint16_t spec_order[] = {
 	AVTAB_TRANSITION,
 	AVTAB_CHANGE,
 	AVTAB_MEMBER,
-	AVTAB_OPNUM_ALLOWED,
-	AVTAB_OPNUM_AUDITALLOW,
-	AVTAB_OPNUM_DONTAUDIT,
-	AVTAB_OPTYPE_ALLOWED,
-	AVTAB_OPTYPE_AUDITALLOW,
-	AVTAB_OPTYPE_DONTAUDIT
+	AVTAB_XPERMS_ALLOWED,
+	AVTAB_XPERMS_AUDITALLOW,
+	AVTAB_XPERMS_DONTAUDIT
 };
 
 int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a,
@@ -433,14 +431,14 @@ int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a,
 	uint32_t buf32[8], items, items2, val;
 	avtab_key_t key;
 	avtab_datum_t datum;
-	avtab_operations_t ops;
+	avtab_extended_perms_t xperms;
 	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));
+	memset(&xperms, 0, sizeof(avtab_extended_perms_t));
 
 	if (vers < POLICYDB_VERSION_AVTAB) {
 		rc = next_entry(buf32, fp, sizeof(uint32_t));
@@ -533,26 +531,32 @@ int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a,
 		return -1;
 	}
 
-	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);
+	if ((vers < POLICYDB_VERSION_XPERMS_IOCTL) &&
+			(key.specified & AVTAB_XPERMS)) {
+		ERR(fp->handle, "policy version %u does not support extended "
+				"permissions rules and one was specified\n", vers);
 		return -1;
-	} else if (key.specified & AVTAB_OP) {
+	} else if (key.specified & AVTAB_XPERMS) {
 		rc = next_entry(&buf8, fp, sizeof(uint8_t));
 		if (rc < 0) {
 			ERR(fp->handle, "truncated entry");
 			return -1;
 		}
-		ops.type = buf8;
+		xperms.specified = buf8;
+		rc = next_entry(&buf8, fp, sizeof(uint8_t));
+		if (rc < 0) {
+			ERR(fp->handle, "truncated entry");
+			return -1;
+		}
+		xperms.driver = 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;
+		for (i = 0; i < ARRAY_SIZE(xperms.perms); i++)
+			xperms.perms[i] = le32_to_cpu(buf32[i]);
+		datum.xperms = &xperms;
 	} else {
 		rc = next_entry(buf32, fp, sizeof(uint32_t));
 		if (rc < 0) {
diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c
index b999890..478eaff 100644
--- a/libsepol/src/expand.c
+++ b/libsepol/src/expand.c
@@ -1604,24 +1604,25 @@ 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,
-				   av_operations_t *operations)
+				   av_extended_perms_t *xperms)
 {
 	avtab_ptr_t node;
 	avtab_datum_t avdatum;
 	cond_av_list_t *nl;
-	int type_match = 0;
+	int match = 0;
 
-	/* AVTAB_OPNUM entries are not necessarily unique */
-	if (key->specified & AVTAB_OPNUM) {
+	/* AVTAB_XPERMS entries are not necessarily unique */
+	if (key->specified & AVTAB_XPERMS) {
 		node = avtab_search_node(avtab, key);
 		while (node) {
-			if (node->datum.ops->type == operations->type) {
-				type_match = 1;
+			if ((node->datum.xperms->specified == xperms->specified) &&
+				(node->datum.xperms->driver == xperms->driver)) {
+				match = 1;
 				break;
 			}
 			node = avtab_search_node_next(node, key->specified);
 		}
-		if (!type_match)
+		if (!match)
 			node = NULL;
 	} else {
 		node = avtab_search_node(avtab, key);
@@ -1780,11 +1781,11 @@ 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, av_operations_t *operations)
+				int enabled, av_extended_perms_t *extended_perms)
 {
 	avtab_key_t avkey;
 	avtab_datum_t *avdatump;
-	avtab_operations_t *ops;
+	avtab_extended_perms_t *xperms;
 	avtab_ptr_t node;
 	class_perm_node_t *cur;
 	uint32_t spec = 0;
@@ -1802,22 +1803,14 @@ 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) {
+	} else if (specified & AVRULE_XPERMS_ALLOWED) {
+		spec = AVTAB_XPERMS_ALLOWED;
+	} else if (specified & AVRULE_XPERMS_AUDITALLOW) {
+		spec = AVTAB_XPERMS_AUDITALLOW;
+	} else if (specified & AVRULE_XPERMS_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;
+		spec = AVTAB_XPERMS_DONTAUDIT;
 	} else {
 		assert(0);	/* unreachable */
 	}
@@ -1829,7 +1822,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, operations);
+		node = find_avtab_node(handle, avtab, &avkey, cond, extended_perms);
 		if (!node)
 			return EXPAND_RULE_ERROR;
 		if (enabled) {
@@ -1859,20 +1852,21 @@ 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) {
+		} else if (specified & AVRULE_XPERMS) {
+			if (!avdatump->xperms) {
+				xperms = (avtab_extended_perms_t *)
+					calloc(1, sizeof(avtab_extended_perms_t));
+				if (!xperms) {
 					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];
+				node->datum.xperms = xperms;
 			}
+			node->datum.xperms->specified = extended_perms->specified;
+			node->datum.xperms->driver = extended_perms->driver;
+
+			for (i = 0; i < ARRAY_SIZE(xperms->perms); i++)
+				node->datum.xperms->perms[i] |= extended_perms->perms[i];
 		} else {
 			assert(0);	/* should never occur */
 		}
@@ -1897,10 +1891,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 | AVRULE_OP)) {
+			if (source_rule->specified & (AVRULE_AV | AVRULE_XPERMS)) {
 				retval = expand_avrule_helper(handle, source_rule->specified,
 							      cond, i, i, source_rule->perms,
-							      dest_avtab, enabled, source_rule->ops);
+							      dest_avtab, enabled, source_rule->xperms);
 				if (retval != EXPAND_RULE_SUCCESS)
 					return retval;
 			} else {
@@ -1915,10 +1909,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 | AVRULE_OP)) {
+			if (source_rule->specified & (AVRULE_AV | AVRULE_XPERMS)) {
 				retval = expand_avrule_helper(handle, source_rule->specified,
 							      cond, i, j, source_rule->perms,
-							      dest_avtab, enabled, source_rule->ops);
+							      dest_avtab, enabled, source_rule->xperms);
 				if (retval != EXPAND_RULE_SUCCESS)
 					return retval;
 			} else {
@@ -3155,24 +3149,25 @@ static int expand_avtab_insert(avtab_t * a, avtab_key_t * k, avtab_datum_t * d)
 {
 	avtab_ptr_t node;
 	avtab_datum_t *avd;
-	avtab_operations_t *ops;
+	avtab_extended_perms_t *xperms;
 	unsigned int i;
-	unsigned int type_match = 0;
+	unsigned int match = 0;
 
-	if (k->specified & AVTAB_OPNUM) {
+	if (k->specified & AVTAB_XPERMS) {
 		/*
-		 * AVTAB_OPNUM entries are not necessarily unique.
-		 * find node with matching ops->type
+		 * AVTAB_XPERMS entries are not necessarily unique.
+		 * find node with matching xperms
 		 */
 		node = avtab_search_node(a, k);
 		while (node) {
-			if (node->datum.ops->type == d->ops->type) {
-				type_match = 1;
+			if ((node->datum.xperms->specified == d->xperms->specified) &&
+				(node->datum.xperms->driver == d->xperms->driver)) {
+				match = 1;
 				break;
 			}
 			node = avtab_search_node_next(node, k->specified);
 		}
-		if (!type_match)
+		if (!match)
 			node = NULL;
 	} else {
 		node = avtab_search_node(a, k);
@@ -3189,7 +3184,7 @@ static int expand_avtab_insert(avtab_t * a, avtab_key_t * k, avtab_datum_t * d)
 	}
 
 	avd = &node->datum;
-	ops = node->datum.ops;
+	xperms = node->datum.xperms;
 	switch (k->specified & ~AVTAB_ENABLED) {
 	case AVTAB_ALLOWED:
 	case AVTAB_AUDITALLOW:
@@ -3198,14 +3193,11 @@ 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];
+	case AVTAB_XPERMS_ALLOWED:
+	case AVTAB_XPERMS_AUDITALLOW:
+	case AVTAB_XPERMS_DONTAUDIT:
+		for (i = 0; i < ARRAY_SIZE(xperms->perms); i++)
+			xperms->perms[i] |= d->xperms->perms[i];
 		break;
 	default:
 		ERR(NULL, "Type conflict!");
diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
index 8c3c7ac..1677eb5 100644
--- a/libsepol/src/policydb.c
+++ b/libsepol/src/policydb.c
@@ -180,7 +180,7 @@ static struct policydb_compat_info policydb_compat[] = {
 	},
 	{
 	 .type = POLICY_KERN,
-	 .version = POLICYDB_VERSION_IOCTL_OPERATIONS,
+	 .version = POLICYDB_VERSION_XPERMS_IOCTL,
 	 .sym_num = SYM_NUM,
 	 .ocon_num = OCON_NODE6 + 1,
 	 .target_platform = SEPOL_TARGET_SELINUX,
diff --git a/libsepol/src/write.c b/libsepol/src/write.c
index 6e78eb3..d87ea61 100644
--- a/libsepol/src/write.c
+++ b/libsepol/src/write.c
@@ -221,28 +221,32 @@ static int avtab_write_item(policydb_t * p,
 	items = put_entry(buf16, sizeof(uint16_t), 4, fp);
 	if (items != 4)
 		return POLICYDB_ERROR;
-	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);
+	if ((p->policyvers < POLICYDB_VERSION_XPERMS_IOCTL) &&
+			(cur->key.specified & AVTAB_XPERMS)) {
+		ERR(fp->handle, "policy version %u does not support ioctl extended"
+				"permissions rules and one was specified", p->policyvers);
 		return POLICYDB_ERROR;
 	}
 
 	if (p->target_platform != SEPOL_TARGET_SELINUX &&
-			(cur->key.specified & AVTAB_OP)) {
+			(cur->key.specified & AVTAB_XPERMS)) {
 		ERR(fp->handle, "Target platform %s does not support ioctl "
-				"operation rules and one was specified",
+				"extended permissions 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;
+	if (cur->key.specified & AVTAB_XPERMS) {
+		buf8 = cur->datum.xperms->specified;
 		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]);
+		buf8 = cur->datum.xperms->driver;
+		items = put_entry(&buf8, sizeof(uint8_t),1,fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+		for (i = 0; i < ARRAY_SIZE(cur->datum.xperms->perms); i++)
+			buf32[i] = cpu_to_le32(cur->datum.xperms->perms[i]);
 		items = put_entry(buf32, sizeof(uint32_t),8,fp);
 		if (items != 8)
 			return POLICYDB_ERROR;
@@ -1546,9 +1550,9 @@ static int avrule_write(avrule_t * avrule, struct policy_file *fp)
 	uint32_t buf[32], len;
 	class_perm_node_t *cur;
 
-	if (avrule->specified & AVRULE_OP) {
-		ERR(fp->handle, "module policy does not support ioctl operation"
-				" rules and one was specified");
+	if (avrule->specified & AVRULE_XPERMS) {
+		ERR(fp->handle, "module policy does not support extended"
+				" permissions rules and one was specified");
 		return POLICYDB_ERROR;
 	}
 
-- 
2.2.0.rc0.207.ga3a616c

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] checkpolicy: switch operations to extended perms
  2015-06-12 16:01 [PATCH] checkpolicy: switch operations to extended perms Jeff Vander Stoep
@ 2015-06-15 13:32 ` Stephen Smalley
  0 siblings, 0 replies; 2+ messages in thread
From: Stephen Smalley @ 2015-06-15 13:32 UTC (permalink / raw)
  To: Jeff Vander Stoep, selinux

On 06/12/2015 12:01 PM, Jeff Vander Stoep wrote:
> The ioctl operations code is being renamed to the more generic
> "extended permissions." This commit brings the policy compiler
> up to date with the kernel patch.
> 
> Signed-off-by: Jeff Vander Stoep <jeffv@google.com>

Thanks, applied.

> ---
>  checkpolicy/policy_define.c                | 343 +++++++++++++++--------------
>  checkpolicy/policy_define.h                |   2 +-
>  checkpolicy/policy_parse.y                 |  43 ++--
>  checkpolicy/policy_scan.l                  |   6 +
>  checkpolicy/test/dispol.c                  |  47 ++--
>  libsepol/include/sepol/policydb/avtab.h    |  26 +--
>  libsepol/include/sepol/policydb/policydb.h |  33 ++-
>  libsepol/src/avtab.c                       |  54 ++---
>  libsepol/src/expand.c                      | 102 ++++-----
>  libsepol/src/policydb.c                    |   2 +-
>  libsepol/src/write.c                       |  30 +--
>  11 files changed, 363 insertions(+), 325 deletions(-)
> 
> diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c
> index 093bded..8c01739 100644
> --- a/checkpolicy/policy_define.c
> +++ b/checkpolicy/policy_define.c
> @@ -1728,32 +1728,31 @@ avrule_t *define_cond_pol_list(avrule_t * avlist, avrule_t * sl)
>  	return sl;
>  }
>  
> -#define operation_perm_test(x, p) (1 & (p[x >> 5] >> (x & 0x1f)))
> -#define operation_perm_set(x, p) (p[x >> 5] |= (1 << (x & 0x1f)))
> -#define operation_perm_clear(x, p) (p[x >> 5] &= ~(1 << (x & 0x1f)))
> +#define xperm_test(x, p) (1 & (p[x >> 5] >> (x & 0x1f)))
> +#define xperm_set(x, p) (p[x >> 5] |= (1 << (x & 0x1f)))
> +#define xperm_clear(x, p) (p[x >> 5] &= ~(1 << (x & 0x1f)))
>  
> -typedef struct av_operations_range {
> +typedef struct av_ioctl_range {
>  	uint16_t low;
>  	uint16_t high;
> -} av_operations_range_t;
> +} av_ioctl_range_t;
>  
> -struct av_operations_range_list {
> +struct av_ioctl_range_list {
>  	uint8_t omit;
> -	av_operations_range_t range;
> -	struct av_operations_range_list *next;
> +	av_ioctl_range_t range;
> +	struct av_ioctl_range_list *next;
>  };
>  
> -int avrule_sort_operations(
> -		struct av_operations_range_list **rangehead)
> +int avrule_sort_ioctls(struct av_ioctl_range_list **rangehead)
>  {
> -	struct av_operations_range_list *r, *r2, *sorted, *sortedhead = NULL;
> +	struct av_ioctl_range_list *r, *r2, *sorted, *sortedhead = NULL;
>  
>  	/* order list by range.low */
>  	for (r = *rangehead; r != NULL; r = r->next) {
> -		sorted = malloc(sizeof(struct av_operations_range_list));
> +		sorted = malloc(sizeof(struct av_ioctl_range_list));
>  		if (sorted == NULL)
>  			goto error;
> -		memcpy(sorted, r, sizeof(struct av_operations_range_list));
> +		memcpy(sorted, r, sizeof(struct av_ioctl_range_list));
>  		sorted->next = NULL;
>  		if (sortedhead == NULL) {
>  			sortedhead = sorted;
> @@ -1792,9 +1791,9 @@ error:
>  	return -1;
>  }
>  
> -int avrule_merge_operations(struct av_operations_range_list **rangehead)
> +int avrule_merge_ioctls(struct av_ioctl_range_list **rangehead)
>  {
> -	struct av_operations_range_list *r, *tmp;
> +	struct av_ioctl_range_list *r, *tmp;
>  	r = *rangehead;
>  	while (r != NULL && r->next != NULL) {
>  		/* merge */
> @@ -1812,14 +1811,14 @@ int avrule_merge_operations(struct av_operations_range_list **rangehead)
>  	return 0;
>  }
>  
> -int avrule_read_operations(struct av_operations_range_list **rangehead)
> +int avrule_read_ioctls(struct av_ioctl_range_list **rangehead)
>  {
>  	char *id;
> -	struct av_operations_range_list *rnew, *r = NULL;
> +	struct av_ioctl_range_list *rnew, *r = NULL;
>  	*rangehead = NULL;
>  	uint8_t omit = 0;
>  
> -	/* read in all the operations */
> +	/* read in all the ioctl commands */
>  	while ((id = queue_remove(id_queue))) {
>  		if (strcmp(id,"~") == 0) {
>  			/* these are values to be omitted */
> @@ -1837,7 +1836,7 @@ int avrule_read_operations(struct av_operations_range_list **rangehead)
>  			free(id);
>  		} else {
>  			/* read in new low value */
> -			rnew = malloc(sizeof(struct av_operations_range_list));
> +			rnew = malloc(sizeof(struct av_ioctl_range_list));
>  			if (rnew == NULL)
>  				goto error;
>  			rnew->next = NULL;
> @@ -1862,11 +1861,11 @@ error:
>  }
>  
>  /* flip to included ranges */
> -int avrule_omit_operations(struct av_operations_range_list **rangehead)
> +int avrule_omit_ioctls(struct av_ioctl_range_list **rangehead)
>  {
> -	struct av_operations_range_list *rnew, *r, *newhead, *r2;
> +	struct av_ioctl_range_list *rnew, *r, *newhead, *r2;
>  
> -	rnew = calloc(1, sizeof(struct av_operations_range_list));
> +	rnew = calloc(1, sizeof(struct av_ioctl_range_list));
>  	if (!rnew)
>  		goto error;
>  
> @@ -1884,7 +1883,7 @@ int avrule_omit_operations(struct av_operations_range_list **rangehead)
>  
>  	while (r) {
>  		r2->range.high = r->range.low - 1;
> -		rnew = calloc(1, sizeof(struct av_operations_range_list));
> +		rnew = calloc(1, sizeof(struct av_ioctl_range_list));
>  		if (!rnew)
>  			goto error;
>  		r2->next = rnew;
> @@ -1910,27 +1909,27 @@ error:
>  	return -1;
>  }
>  
> -int avrule_operation_ranges(struct av_operations_range_list **rangelist)
> +int avrule_ioctl_ranges(struct av_ioctl_range_list **rangelist)
>  {
> -	struct av_operations_range_list *rangehead;
> +	struct av_ioctl_range_list *rangehead;
>  	uint8_t omit;
>  
>  	/* read in ranges to include and omit */
> -	if (avrule_read_operations(&rangehead))
> +	if (avrule_read_ioctls(&rangehead))
>  		return -1;
>  	omit = rangehead->omit;
>  	if (rangehead == NULL) {
> -		yyerror("error processing ioctl operations");
> +		yyerror("error processing ioctl commands");
>  		return -1;
>  	}
> -	/* sort and merge the input operations */
> -	if (avrule_sort_operations(&rangehead))
> +	/* sort and merge the input ioctls */
> +	if (avrule_sort_ioctls(&rangehead))
>  		return -1;
> -	if (avrule_merge_operations(&rangehead))
> +	if (avrule_merge_ioctls(&rangehead))
>  		return -1;
>  	/* flip ranges if these are ommited*/
>  	if (omit) {
> -		if (avrule_omit_operations(&rangehead))
> +		if (avrule_omit_ioctls(&rangehead))
>  			return -1;
>  	}
>  
> @@ -1938,7 +1937,7 @@ int avrule_operation_ranges(struct av_operations_range_list **rangelist)
>  	return 0;
>  }
>  
> -int define_te_avtab_operation_helper(int which, avrule_t ** rule)
> +int define_te_avtab_xperms_helper(int which, avrule_t ** rule)
>  {
>  	char *id;
>  	class_perm_node_t *perms, *tail = NULL, *cur_perms = NULL;
> @@ -1959,7 +1958,7 @@ int define_te_avtab_operation_helper(int which, avrule_t ** rule)
>  	avrule->line = policydb_lineno;
>  	avrule->source_line = source_lineno;
>  	avrule->source_filename = strdup(source_file);
> -	avrule->ops = NULL;
> +	avrule->xperms = NULL;
>  	if (!avrule->source_filename) {
>  		yyerror("out of memory");
>  		return -1;
> @@ -2023,95 +2022,102 @@ out:
>  }
>  
>  /* index of the u32 containing the permission */
> -#define OP_IDX(x) (x >> 5)
> +#define XPERM_IDX(x) (x >> 5)
>  /* set bits 0 through x-1 within the u32 */
> -#define OP_SETBITS(x) ((1 << (x & 0x1f)) - 1)
> +#define XPERM_SETBITS(x) ((1 << (x & 0x1f)) - 1)
>  /* low value for this u32 */
> -#define OP_LOW(x) (x << 5)
> +#define XPERM_LOW(x) (x << 5)
>  /* high value for this u32 */
> -#define OP_HIGH(x) (((x + 1) << 5) - 1)
> -void avrule_operation_setrangebits(uint16_t low, uint16_t high, av_operations_t *ops)
> +#define XPERM_HIGH(x) (((x + 1) << 5) - 1)
> +void avrule_xperm_setrangebits(uint16_t low, uint16_t high,
> +				av_extended_perms_t *xperms)
>  {
>  	unsigned int i;
>  	uint16_t h = high + 1;
> -	/* for each u32 that this low-high range touches, set type permissions */
> -	for (i = OP_IDX(low); i <= OP_IDX(high); i++) {
> +	/* for each u32 that this low-high range touches, set driver permissions */
> +	for (i = XPERM_IDX(low); i <= XPERM_IDX(high); i++) {
>  		/* set all bits in u32 */
> -		if ((low <= OP_LOW(i)) && (high >= OP_HIGH(i)))
> -			ops->perms[i] |= ~0U;
> +		if ((low <= XPERM_LOW(i)) && (high >= XPERM_HIGH(i)))
> +			xperms->perms[i] |= ~0U;
>  		/* set low bits */
> -		else if ((low <= OP_LOW(i)) && (high < OP_HIGH(i)))
> -			ops->perms[i] |= OP_SETBITS(h);
> +		else if ((low <= XPERM_LOW(i)) && (high < XPERM_HIGH(i)))
> +			xperms->perms[i] |= XPERM_SETBITS(h);
>  		/* set high bits */
> -		else if ((low > OP_LOW(i)) && (high >= OP_HIGH(i)))
> -			ops->perms[i] |= ~0U - OP_SETBITS(low);
> +		else if ((low > XPERM_LOW(i)) && (high >= XPERM_HIGH(i)))
> +			xperms->perms[i] |= ~0U - XPERM_SETBITS(low);
>  		/* set middle bits */
> -		else if ((low > OP_LOW(i)) && (high <= OP_HIGH(i)))
> -			ops->perms[i] |= OP_SETBITS(h) - OP_SETBITS(low);
> +		else if ((low > XPERM_LOW(i)) && (high <= XPERM_HIGH(i)))
> +			xperms->perms[i] |= XPERM_SETBITS(h) - XPERM_SETBITS(low);
>  	}
>  }
>  
> -int avrule_operation_used(av_operations_t *ops)
> +int avrule_xperms_used(av_extended_perms_t *xperms)
>  {
>  	unsigned int i;
>  
> -	for (i = 0; i < sizeof(ops->perms)/sizeof(ops->perms[0]); i++) {
> -		if (ops->perms[i])
> +	for (i = 0; i < sizeof(xperms->perms)/sizeof(xperms->perms[0]); i++) {
> +		if (xperms->perms[i])
>  			return 1;
>  	}
>  	return 0;
>  }
>  
> -#define OP_TYPE(x) (x >> 8)
> -#define OP_NUM(x) (x & 0xff)
> -#define OP_CMD(type, num) ((type << 8) + num)
> -int avrule_operation_partialtype(struct av_operations_range_list *rangelist,
> -				av_operations_t *complete_type,
> -				av_operations_t **operations)
> +/*
> + * using definitions found in kernel document ioctl-number.txt
> + * The kernel components of an ioctl command are:
> + * dir, size, driver, and fucntion. Only the driver and function fields
> + * are considered here
> + */
> +#define IOC_DRIV(x) (x >> 8)
> +#define IOC_FUNC(x) (x & 0xff)
> +#define IOC_CMD(driver, func) ((driver << 8) + func)
> +int avrule_ioctl_partialdriver(struct av_ioctl_range_list *rangelist,
> +				av_extended_perms_t *complete_driver,
> +				av_extended_perms_t **extended_perms)
>  {
> -	struct av_operations_range_list *r;
> -	av_operations_t *ops;
> +	struct av_ioctl_range_list *r;
> +	av_extended_perms_t *xperms;
>  	uint8_t low, high;
>  
> -	ops = calloc(1, sizeof(av_operations_t));
> -	if (!ops) {
> +	xperms = calloc(1, sizeof(av_extended_perms_t));
> +	if (!xperms) {
>  		yyerror("out of memory");
>  		return - 1;
>  	}
>  
>  	r = rangelist;
>  	while(r) {
> -		low = OP_TYPE(r->range.low);
> -		high = OP_TYPE(r->range.high);
> -		if (complete_type) {
> -			if (!operation_perm_test(low, complete_type->perms))
> -				operation_perm_set(low, ops->perms);
> -			if (!operation_perm_test(high, complete_type->perms))
> -				operation_perm_set(high, ops->perms);
> +		low = IOC_DRIV(r->range.low);
> +		high = IOC_DRIV(r->range.high);
> +		if (complete_driver) {
> +			if (!xperm_test(low, complete_driver->perms))
> +				xperm_set(low, xperms->perms);
> +			if (!xperm_test(high, complete_driver->perms))
> +				xperm_set(high, xperms->perms);
>  		} else {
> -			operation_perm_set(low, ops->perms);
> -			operation_perm_set(high, ops->perms);
> +			xperm_set(low, xperms->perms);
> +			xperm_set(high, xperms->perms);
>  		}
>  		r = r->next;
>  	}
> -	if (avrule_operation_used(ops)) {
> -		*operations = ops;
> +	if (avrule_xperms_used(xperms)) {
> +		*extended_perms = xperms;
>  	} else {
> -		free(ops);
> -		*operations = NULL;
> +		free(xperms);
> +		*extended_perms = NULL;
>  	}
>  	return 0;
>  
>  }
>  
> -int avrule_operation_completetype(struct av_operations_range_list *rangelist,
> -			av_operations_t **operations)
> +int avrule_ioctl_completedriver(struct av_ioctl_range_list *rangelist,
> +			av_extended_perms_t **extended_perms)
>  {
> -	struct av_operations_range_list *r;
> -	av_operations_t *ops;
> +	struct av_ioctl_range_list *r;
> +	av_extended_perms_t *xperms;
>  	uint16_t low, high;
> -	ops = calloc(1, sizeof(av_operations_t));
> -	if (!ops) {
> +	xperms = calloc(1, sizeof(av_extended_perms_t));
> +	if (!xperms) {
>  		yyerror("out of memory");
>  		return - 1;
>  	}
> @@ -2119,83 +2125,86 @@ int avrule_operation_completetype(struct av_operations_range_list *rangelist,
>  	r = rangelist;
>  	while(r) {
>  		/*
> -		 * Any type that has numbers 0x00 - 0xff is a complete type,
> +		 * Any driver code that has sequence 0x00 - 0xff is a complete code,
>  		 *
> -		 * if command number = 0xff, then round high up to next type,
> -		 * else 0x00 - 0xfe keep current type
> +		 * if command number = 0xff, then round high up to next code,
> +		 * else 0x00 - 0xfe keep current code
>  		 * of this range. temporarily u32 for the + 1
>  		 * to account for possible rollover before right shift
>  		 */
> -		high = OP_TYPE((uint32_t) (r->range.high + 1));
> -		/* if 0x00 keep current type else 0x01 - 0xff round up to next type */
> -		low = OP_TYPE(r->range.low);
> -		if (OP_NUM(r->range.low))
> +		high = IOC_DRIV((uint32_t) (r->range.high + 1));
> +		/* if 0x00 keep current driver code else 0x01 - 0xff round up to next code*/
> +		low = IOC_DRIV(r->range.low);
> +		if (IOC_FUNC(r->range.low))
>  			low++;
>  		if (high > low)
> -			avrule_operation_setrangebits(low, high - 1, ops);
> +			avrule_xperm_setrangebits(low, high - 1, xperms);
>  		r = r->next;
>  	}
> -	if (avrule_operation_used(ops)) {
> -		*operations = ops;
> +	if (avrule_xperms_used(xperms)) {
> +		xperms->driver = 0x00;
> +		xperms->specified = AVRULE_XPERMS_IOCTLDRIVER;
> +		*extended_perms = xperms;
>  	} else {
> -		free(ops);
> -		*operations = NULL;
> +		free(xperms);
> +		*extended_perms = NULL;
>  	}
>  	return 0;
>  }
>  
> -int avrule_operation_num(struct av_operations_range_list *rangelist,
> -		av_operations_t **operations, unsigned int type)
> +int avrule_ioctl_func(struct av_ioctl_range_list *rangelist,
> +		av_extended_perms_t **extended_perms, unsigned int driver)
>  {
> -	struct av_operations_range_list *r;
> -	av_operations_t *ops;
> +	struct av_ioctl_range_list *r;
> +	av_extended_perms_t *xperms;
>  	uint16_t low, high;
>  
> -	*operations = NULL;
> -	ops = calloc(1, sizeof(av_operations_t));
> -	if (!ops) {
> +	*extended_perms = NULL;
> +	xperms = calloc(1, sizeof(av_extended_perms_t));
> +	if (!xperms) {
>  		yyerror("out of memory");
>  		return - 1;
>  	}
>  
>  	r = rangelist;
> -	/* for the passed in types, find the ranges that apply */
> +	/* for the passed in driver code, find the ranges that apply */
>  	while (r) {
>  		low = r->range.low;
>  		high = r->range.high;
> -		if ((type != OP_TYPE(low)) && (type != OP_TYPE(high))) {
> +		if ((driver != IOC_DRIV(low)) && (driver != IOC_DRIV(high))) {
>  			r = r->next;
>  			continue;
>  		}
>  
> -		if (type == OP_TYPE(low)) {
> -			if (high > OP_CMD(type, 0xff))
> -				high = OP_CMD(type, 0xff);
> +		if (driver == IOC_DRIV(low)) {
> +			if (high > IOC_CMD(driver, 0xff))
> +				high = IOC_CMD(driver, 0xff);
>  
>  		} else {
> -			if (low < OP_CMD(type, 0))
> -				low = OP_CMD(type, 0);
> +			if (low < IOC_CMD(driver, 0))
> +				low = IOC_CMD(driver, 0);
>  		}
>  
> -		low = OP_NUM(low);
> -		high = OP_NUM(high);
> -		avrule_operation_setrangebits(low, high, ops);
> -		ops->type = type;
> +		low = IOC_FUNC(low);
> +		high = IOC_FUNC(high);
> +		avrule_xperm_setrangebits(low, high, xperms);
> +		xperms->driver = driver;
> +		xperms->specified = AVRULE_XPERMS_IOCTLFUNCTION;
>  		r = r->next;
>  	}
>  
> -	if (avrule_operation_used(ops)) {
> -		*operations = ops;
> +	if (avrule_xperms_used(xperms)) {
> +		*extended_perms = xperms;
>  	} else {
> -		free(ops);
> -		*operations = NULL;
> +		free(xperms);
> +		*extended_perms = NULL;
>  	}
>  	return 0;
>  }
>  
> -void avrule_operation_freeranges(struct av_operations_range_list *rangelist)
> +void avrule_ioctl_freeranges(struct av_ioctl_range_list *rangelist)
>  {
> -	struct av_operations_range_list *r, *tmp;
> +	struct av_ioctl_range_list *r, *tmp;
>  	r = rangelist;
>  	while (r) {
>  		tmp = r;
> @@ -2204,12 +2213,12 @@ void avrule_operation_freeranges(struct av_operations_range_list *rangelist)
>  	}
>  }
>  
> -unsigned int operation_for_each_bit(unsigned int *bit, av_operations_t *ops)
> +unsigned int xperms_for_each_bit(unsigned int *bit, av_extended_perms_t *xperms)
>  {
>  	unsigned int i;
> -	for (i = *bit; i < sizeof(ops->perms)*8; i++) {
> -		if (operation_perm_test(i,ops->perms)) {
> -			operation_perm_clear(i, ops->perms);
> +	for (i = *bit; i < sizeof(xperms->perms)*8; i++) {
> +		if (xperm_test(i,xperms->perms)) {
> +			xperm_clear(i, xperms->perms);
>  			*bit = i;
>  			return 1;
>  		}
> @@ -2261,35 +2270,22 @@ int avrule_cpy(avrule_t *dest, avrule_t *src)
>  	return 0;
>  }
>  
> -int define_te_avtab_operation(int which)
> +int define_te_avtab_ioctl(avrule_t *avrule_template)
>  {
> -	char *id;
> -	avrule_t *avrule_template;
>  	avrule_t *avrule;
> -	struct av_operations_range_list *rangelist;
> -	av_operations_t *complete_type, *partial_type, *ops;
> +	struct av_ioctl_range_list *rangelist;
> +	av_extended_perms_t *complete_driver, *partial_driver, *xperms;
>  	unsigned int i;
>  
> -	if (pass == 1) {
> -		for (i = 0; i < 4; i++) {
> -			while ((id = queue_remove(id_queue)))
> -				free(id);
> -		}
> -		return 0;
> -	}
> -
> -	/* populate avrule template with source/target/tclass */
> -	if (define_te_avtab_operation_helper(which, &avrule_template))
> -		return -1;
>  
> -	/* organize operation ranges */
> -	if (avrule_operation_ranges(&rangelist))
> +	/* organize ioctl ranges */
> +	if (avrule_ioctl_ranges(&rangelist))
>  		return -1;
>  
> -	/* create rule for ioctl operation types that are entirely enabled */
> -	if (avrule_operation_completetype(rangelist, &complete_type))
> +	/* create rule for ioctl driver types that are entirely enabled */
> +	if (avrule_ioctl_completedriver(rangelist, &complete_driver))
>  		return -1;
> -	if (complete_type) {
> +	if (complete_driver) {
>  		avrule = (avrule_t *) calloc(1, sizeof(avrule_t));
>  		if (!avrule) {
>  			yyerror("out of memory");
> @@ -2297,31 +2293,28 @@ int define_te_avtab_operation(int which)
>  		}
>  		if (avrule_cpy(avrule, avrule_template))
>  			return -1;
> -		avrule->ops = complete_type;
> -		if (which == AVRULE_OPNUM_ALLOWED)
> -			avrule->specified = AVRULE_OPTYPE_ALLOWED;
> -		else if (which == AVRULE_OPNUM_AUDITALLOW)
> -			avrule->specified = AVRULE_OPTYPE_AUDITALLOW;
> -		else if (which == AVRULE_OPNUM_DONTAUDIT)
> -			avrule->specified = AVRULE_OPTYPE_DONTAUDIT;
> -
> +		avrule->xperms = complete_driver;
>  		append_avrule(avrule);
>  	}
>  
> -	/* flag ioctl types that are partially enabled */
> -	if (avrule_operation_partialtype(rangelist, complete_type, &partial_type))
> +	/* flag ioctl driver codes that are partially enabled */
> +	if (avrule_ioctl_partialdriver(rangelist, complete_driver, &partial_driver))
>  		return -1;
>  
> -	if (!partial_type || !avrule_operation_used(partial_type))
> +	if (!partial_driver || !avrule_xperms_used(partial_driver))
>  		goto done;
>  
> -	/* create rule for each partially enabled type */
> +	/*
> +	 * 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 (operation_for_each_bit(&i, partial_type)) {
> -		if (avrule_operation_num(rangelist, &ops, i))
> +	while (xperms_for_each_bit(&i, partial_driver)) {
> +		if (avrule_ioctl_func(rangelist, &xperms, i))
>  			return -1;
>  
> -		if (ops) {
> +		if (xperms) {
>  			avrule = (avrule_t *) calloc(1, sizeof(avrule_t));
>  			if (!avrule) {
>  				yyerror("out of memory");
> @@ -2329,15 +2322,45 @@ int define_te_avtab_operation(int which)
>  			}
>  			if (avrule_cpy(avrule, avrule_template))
>  				return -1;
> -			avrule->ops = ops;
> +			avrule->xperms = xperms;
>  			append_avrule(avrule);
>  		}
>  	}
>  
>  done:
> -	if (partial_type)
> -		free(partial_type);
> +	if (partial_driver)
> +		free(partial_driver);
> +
> +	return 0;
> +}
> +
> +int define_te_avtab_extended_perms(int which)
> +{
> +	char *id;
> +	unsigned int i;
> +	avrule_t *avrule_template;
> +
> +	if (pass == 1) {
> +		for (i = 0; i < 4; i++) {
> +			while ((id = queue_remove(id_queue)))
> +				free(id);
> +		}
> +		return 0;
> +	}
>  
> +	/* populate avrule template with source/target/tclass */
> +	if (define_te_avtab_xperms_helper(which, &avrule_template))
> +		return -1;
> +
> +	id = queue_remove(id_queue);
> +	if (strcmp(id,"ioctl") == 0) {
> +		if (define_te_avtab_ioctl(avrule_template))
> +			return -1;
> +		free(id);
> +	} else {
> +		yyerror("only ioctl extended permissions are supported");
> +		return -1;
> +	}
>  	return 0;
>  }
>  
> @@ -2365,7 +2388,7 @@ int define_te_avtab_helper(int which, avrule_t ** rule)
>  	avrule->line = policydb_lineno;
>  	avrule->source_line = source_lineno;
>  	avrule->source_filename = strdup(source_file);
> -	avrule->ops = NULL;
> +	avrule->xperms = NULL;
>  	if (!avrule->source_filename) {
>  		yyerror("out of memory");
>  		return -1;
> diff --git a/checkpolicy/policy_define.h b/checkpolicy/policy_define.h
> index 43c7c08..964baae 100644
> --- a/checkpolicy/policy_define.h
> +++ b/checkpolicy/policy_define.h
> @@ -58,7 +58,7 @@ int define_roleattribute(void);
>  int define_filename_trans(void);
>  int define_sens(void);
>  int define_te_avtab(int which);
> -int define_te_avtab_operation(int which);
> +int define_te_avtab_extended_perms(int which);
>  int define_typealias(void);
>  int define_typeattribute(void);
>  int define_typebounds(void);
> diff --git a/checkpolicy/policy_parse.y b/checkpolicy/policy_parse.y
> index 059b7b8..d8b8ac0 100644
> --- a/checkpolicy/policy_parse.y
> +++ b/checkpolicy/policy_parse.y
> @@ -126,6 +126,9 @@ typedef int (* require_func_t)(int pass);
>  %token AUDITALLOW
>  %token AUDITDENY
>  %token DONTAUDIT
> +%token ALLOWXPERM
> +%token AUDITALLOWXPERM
> +%token DONTAUDITXPERM
>  %token SOURCE
>  %token TARGET
>  %token SAMEUSER
> @@ -457,9 +460,9 @@ te_avtab_def		: allow_def
>  			| auditdeny_def
>  			| dontaudit_def
>  			| neverallow_def
> -			| operation_allow_def
> -			| operation_auditallow_def
> -			| operation_dontaudit_def
> +			| xperm_allow_def
> +			| xperm_auditallow_def
> +			| xperm_dontaudit_def
>  			;
>  allow_def		: ALLOW names names ':' names names  ';'
>  			{if (define_te_avtab(AVRULE_ALLOWED)) return -1; }
> @@ -476,14 +479,14 @@ dontaudit_def		: DONTAUDIT names names ':' names names ';'
>  neverallow_def		: NEVERALLOW names names ':' names names  ';'
>  			{if (define_te_avtab(AVRULE_NEVERALLOW)) return -1; }
>  		        ;
> -operation_allow_def	: ALLOW names names ':' names  operations ';'
> -			{if (define_te_avtab_operation(AVRULE_OPNUM_ALLOWED)) return -1; }
> +xperm_allow_def		: ALLOWXPERM names names ':' names identifier xperms ';'
> +			{if (define_te_avtab_extended_perms(AVRULE_XPERMS_ALLOWED)) return -1; }
>  		        ;
> -operation_auditallow_def: AUDITALLOW names names ':' names operations ';'
> -			{if (define_te_avtab_operation(AVRULE_OPNUM_AUDITALLOW)) return -1; }
> +xperm_auditallow_def	: AUDITALLOWXPERM names names ':' names identifier xperms ';'
> +			{if (define_te_avtab_extended_perms(AVRULE_XPERMS_AUDITALLOW)) return -1; }
>  		        ;
> -operation_dontaudit_def	: DONTAUDIT names names ':' names operations ';'
> -			{if (define_te_avtab_operation(AVRULE_OPNUM_DONTAUDIT)) return -1; }
> +xperm_dontaudit_def	: DONTAUDITXPERM names names ':' names identifier xperms ';'
> +			{if (define_te_avtab_extended_perms(AVRULE_XPERMS_DONTAUDIT)) return -1; }
>  		        ;
>  attribute_role_def	: ATTRIBUTE_ROLE identifier ';'
>  			{if (define_attrib_role()) return -1; }
> @@ -749,26 +752,26 @@ genfs_context_def	: GENFSCON filesystem path '-' identifier security_context_def
>  ipv4_addr_def		: IPV4_ADDR
>  			{ if (insert_id(yytext,0)) return -1; }
>  			;
> -operations		: operation
> +xperms		: xperm
>  			{ if (insert_separator(0)) return -1; }
> -			| nested_operation_set
> +			| nested_xperm_set
>  			{ if (insert_separator(0)) return -1; }
> -			| tilde operation
> +			| tilde xperm
>                          { if (insert_id("~", 0)) return -1; }
> -			| tilde nested_operation_set
> +			| tilde nested_xperm_set
>  			{ if (insert_id("~", 0)) return -1;
>  			  if (insert_separator(0)) return -1; }
>  			;
> -nested_operation_set	: '{' nested_operation_list '}'
> +nested_xperm_set	: '{' nested_xperm_list '}'
>  			;
> -nested_operation_list	: nested_operation_element
> -			| nested_operation_list nested_operation_element
> +nested_xperm_list	: nested_xperm_element
> +			| nested_xperm_list nested_xperm_element
>  			;
> -nested_operation_element: operation '-' { if (insert_id("-", 0)) return -1; } operation
> -			| operation
> -			| nested_operation_set
> +nested_xperm_element: xperm '-' { if (insert_id("-", 0)) return -1; } xperm
> +			| xperm
> +			| nested_xperm_set
>  			;
> -operation		: number
> +xperm		: number
>                          { if (insert_id(yytext,0)) return -1; }
>  			;
>  security_context_def	: identifier ':' identifier ':' identifier opt_mls_range_def
> diff --git a/checkpolicy/policy_scan.l b/checkpolicy/policy_scan.l
> index 108edbc..e94a917 100644
> --- a/checkpolicy/policy_scan.l
> +++ b/checkpolicy/policy_scan.l
> @@ -142,6 +142,12 @@ AUDITDENY |
>  auditdeny		        { return(AUDITDENY); }
>  DONTAUDIT |
>  dontaudit                       { return(DONTAUDIT); }
> +ALLOWXPERM |
> +allowxperm		        { return(ALLOWXPERM); }
> +AUDITALLOWXPERM |
> +auditallowxperm		        { return(AUDITALLOWXPERM); }
> +DONTAUDITXPERM |
> +dontauditxperm                  { return(DONTAUDITXPERM); }
>  SOURCE |
>  source			        { return(SOURCE); }
>  TARGET |
> diff --git a/checkpolicy/test/dispol.c b/checkpolicy/test/dispol.c
> index 157361a..0c6b8d8 100644
> --- a/checkpolicy/test/dispol.c
> +++ b/checkpolicy/test/dispol.c
> @@ -54,11 +54,11 @@ int render_access_mask(uint32_t mask, avtab_key_t * key, policydb_t * p,
>  	return 0;
>  }
>  
> -#define operation_perm_test(x, p) (1 & (p[x >> 5] >> (x & 0x1f)))
> +#define xperms_test(x, p) (1 & (p[x >> 5] >> (x & 0x1f)))
>  #define next_bit_in_range(i, p) \
> -	((i + 1 < sizeof(p)*8) && operation_perm_test((i + 1), p))
> +	((i + 1 < sizeof(p)*8) && xperms_test((i + 1), p))
>  
> -int render_operations(avtab_operations_t *ops, avtab_key_t * key, FILE * fp)
> +int render_ioctl(avtab_extended_perms_t * xperms, FILE * fp)
>  {
>  	uint16_t value;
>  	uint16_t low_bit;
> @@ -67,28 +67,28 @@ int render_operations(avtab_operations_t *ops, avtab_key_t * key, FILE * fp)
>  	unsigned int in_range = 0;
>  
>  	fprintf(fp, "{ ");
> -	for (bit = 0; bit < sizeof(ops->perms)*8; bit++) {
> -		if (!operation_perm_test(bit, ops->perms))
> +	for (bit = 0; bit < sizeof(xperms->perms)*8; bit++) {
> +		if (!xperms_test(bit, xperms->perms))
>  			continue;
>  
> -		if (in_range && next_bit_in_range(bit, ops->perms)) {
> +		if (in_range && next_bit_in_range(bit, xperms->perms)) {
>  			/* continue until high value found */
>  			continue;
> -		} else if (next_bit_in_range(bit, ops->perms)) {
> +		} else if (next_bit_in_range(bit, xperms->perms)) {
>  			/* low value */
>  			low_bit = bit;
>  			in_range = 1;
>  			continue;
>  		}
>  
> -		if (key->specified & AVTAB_OPNUM) {
> -			value = ops->type<<8 | bit;
> -			low_value = ops->type<<8 | low_bit;
> +		if (xperms->specified & AVTAB_XPERMS_IOCTLFUNCTION) {
> +			value = xperms->driver<<8 | bit;
> +			low_value = xperms->driver<<8 | low_bit;
>  			if (in_range)
>  				fprintf(fp, "0x%hx-0x%hx ", low_value, value);
>  			else
>  				fprintf(fp, "0x%hx ", value);
> -		} else if (key->specified & AVTAB_OPTYPE) {
> +		} else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) {
>  			value = bit << 8;
>  			low_value = low_bit << 8;
>  			if (in_range)
> @@ -104,6 +104,15 @@ int render_operations(avtab_operations_t *ops, avtab_key_t * key, FILE * fp)
>  	return 0;
>  }
>  
> +int render_xperms(avtab_extended_perms_t * xperms, FILE * fp)
> +{
> +	if ((xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) ||
> +			(xperms->specified == AVTAB_XPERMS_IOCTLDRIVER))
> +		render_ioctl(xperms, fp);
> +
> +	return 0;
> +}
> +
>  int render_type(uint32_t type, policydb_t * p, FILE * fp)
>  {
>  	fprintf(fp, "%s", p->p_type_val_to_name[type - 1]);
> @@ -197,15 +206,15 @@ int render_av_rule(avtab_key_t * key, avtab_datum_t * datum, uint32_t what,
>  			render_type(datum->data, p, fp);
>  			fprintf(fp, ";\n");
>  		}
> -	} else if (key->specified & AVTAB_OP) {
> -		if (key->specified & (AVTAB_OPNUM_ALLOWED|AVTAB_OPTYPE_ALLOWED))
> -			fprintf(fp, "allow ");
> -		else if (key->specified & (AVTAB_OPNUM_AUDITALLOW|AVTAB_OPTYPE_AUDITALLOW))
> -			fprintf(fp, "auditallow ");
> -		else if (key->specified & (AVTAB_OPNUM_DONTAUDIT|AVTAB_OPTYPE_DONTAUDIT))
> -			fprintf(fp, "dontaudit ");
> +	} else if (key->specified & AVTAB_XPERMS) {
> +		if (key->specified & AVTAB_XPERMS_ALLOWED)
> +			fprintf(fp, "allowxperm ");
> +		else if (key->specified & AVTAB_XPERMS_AUDITALLOW)
> +			fprintf(fp, "auditallowxperm ");
> +		else if (key->specified & AVTAB_XPERMS_DONTAUDIT)
> +			fprintf(fp, "dontauditxperm ");
>  		render_key(key, p, fp);
> -		render_operations(datum->ops, key, fp);
> +		render_xperms(datum->xperms, fp);
>  		fprintf(fp, ";\n");
>  	} else {
>  		fprintf(fp, "     ERROR: no valid rule type specified\n");
> diff --git a/libsepol/include/sepol/policydb/avtab.h b/libsepol/include/sepol/policydb/avtab.h
> index 2ea821c..14bc082 100644
> --- a/libsepol/include/sepol/policydb/avtab.h
> +++ b/libsepol/include/sepol/policydb/avtab.h
> @@ -59,28 +59,28 @@ typedef struct avtab_key {
>  #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_XPERMS_ALLOWED	0x0100
> +#define AVTAB_XPERMS_AUDITALLOW	0x0200
> +#define AVTAB_XPERMS_DONTAUDIT	0x0400
> +#define AVTAB_XPERMS		(AVTAB_XPERMS_ALLOWED | AVTAB_XPERMS_AUDITALLOW | AVTAB_XPERMS_DONTAUDIT)
>  #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;
> +typedef struct avtab_extended_perms {
> +
> +#define AVTAB_XPERMS_IOCTLFUNCTION	0x01
> +#define AVTAB_XPERMS_IOCTLDRIVER	0x02
> +	/* extension of the avtab_key specified */
> +	uint8_t specified;
> +	uint8_t driver;
>  	uint32_t perms[8];
> -} avtab_operations_t;
> +} avtab_extended_perms_t;
>  
>  typedef struct avtab_datum {
>  	uint32_t data;		/* access vector or type */
> -	avtab_operations_t *ops;
> +	avtab_extended_perms_t *xperms;
>  } avtab_datum_t;
>  
>  typedef struct avtab_node *avtab_ptr_t;
> diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
> index 1d8310c..78b09c4 100644
> --- a/libsepol/include/sepol/policydb/policydb.h
> +++ b/libsepol/include/sepol/policydb/policydb.h
> @@ -241,11 +241,14 @@ 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 */
> +typedef struct av_extended_perms {
> +#define AVRULE_XPERMS_IOCTLFUNCTION	0x01
> +#define AVRULE_XPERMS_IOCTLDRIVER	0x02
> +	uint8_t specified;
> +	uint8_t driver;
> +	/* 256 bits of permissions */
>  	uint32_t perms[8];
> -} av_operations_t;
> +} av_extended_perms_t;
>  
>  typedef struct avrule {
>  /* these typedefs are almost exactly the same as those in avtab.h - they are
> @@ -260,24 +263,18 @@ typedef struct avrule {
>  #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)
> +#define AVRULE_XPERMS_ALLOWED 		0x0100
> +#define AVRULE_XPERMS_AUDITALLOW	0x0200
> +#define AVRULE_XPERMS_DONTAUDIT		0x0400
> +#define AVRULE_XPERMS	(AVRULE_XPERMS_ALLOWED | AVRULE_XPERMS_AUDITALLOW | \
> +				AVRULE_XPERMS_DONTAUDIT)
>  	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;
> +	av_extended_perms_t *xperms;
>  	unsigned long line;	/* line number from policy.conf where
>  				 * this rule originated  */
>  	/* source file name and line number (e.g. .te file) */
> @@ -709,11 +706,11 @@ extern int policydb_set_target_platform(policydb_t *p, int platform);
>  #define POLICYDB_VERSION_DEFAULT_TYPE	28
>  #define POLICYDB_VERSION_CONSTRAINT_NAMES	29
>  #define POLICYDB_VERSION_XEN_DEVICETREE		30 /* Xen-specific */
> -#define POLICYDB_VERSION_IOCTL_OPERATIONS	30 /* Linux-specific */
> +#define POLICYDB_VERSION_XPERMS_IOCTL	30 /* Linux-specific */
>  
>  /* Range of policy versions we understand*/
>  #define POLICYDB_VERSION_MIN	POLICYDB_VERSION_BASE
> -#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_IOCTL_OPERATIONS
> +#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_XPERMS_IOCTL
>  
>  /* Module versions and specific changes*/
>  #define MOD_POLICYDB_VERSION_BASE		4
> diff --git a/libsepol/src/avtab.c b/libsepol/src/avtab.c
> index d3745fe..799b98f 100644
> --- a/libsepol/src/avtab.c
> +++ b/libsepol/src/avtab.c
> @@ -93,7 +93,7 @@ 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;
> +	avtab_extended_perms_t *xperms;
>  
>  	newnode = (avtab_ptr_t) malloc(sizeof(struct avtab_node));
>  	if (newnode == NULL)
> @@ -101,16 +101,16 @@ avtab_insert_node(avtab_t * h, int hvalue, avtab_ptr_t prev, avtab_key_t * key,
>  	memset(newnode, 0, sizeof(struct avtab_node));
>  	newnode->key = *key;
>  
> -	if (key->specified & AVTAB_OP) {
> -		ops = calloc(1, sizeof(avtab_operations_t));
> -		if (ops == NULL) {
> +	if (key->specified & AVTAB_XPERMS) {
> +		xperms = calloc(1, sizeof(avtab_extended_perms_t));
> +		if (xperms == NULL) {
>  			free(newnode);
>  			return NULL;
>  		}
> -		if (datum->ops) /* else caller populates ops*/
> -			*ops = *(datum->ops);
> +		if (datum->xperms) /* else caller populates xperms */
> +			*xperms = *(datum->xperms);
>  
> -		newnode->datum.ops = ops;
> +		newnode->datum.xperms = xperms;
>  	} else {
>  		newnode->datum = *datum;
>  	}
> @@ -144,7 +144,8 @@ int avtab_insert(avtab_t * h, avtab_key_t * key, avtab_datum_t * datum)
>  		    key->target_type == cur->key.target_type &&
>  		    key->target_class == cur->key.target_class &&
>  		    (specified & cur->key.specified)) {
> -			if (specified & AVTAB_OPNUM)
> +			/* Extended permissions are not necessarily unique */
> +			if (specified & AVTAB_XPERMS)
>  				break;
>  			return SEPOL_EEXIST;
>  		}
> @@ -416,12 +417,9 @@ static uint16_t spec_order[] = {
>  	AVTAB_TRANSITION,
>  	AVTAB_CHANGE,
>  	AVTAB_MEMBER,
> -	AVTAB_OPNUM_ALLOWED,
> -	AVTAB_OPNUM_AUDITALLOW,
> -	AVTAB_OPNUM_DONTAUDIT,
> -	AVTAB_OPTYPE_ALLOWED,
> -	AVTAB_OPTYPE_AUDITALLOW,
> -	AVTAB_OPTYPE_DONTAUDIT
> +	AVTAB_XPERMS_ALLOWED,
> +	AVTAB_XPERMS_AUDITALLOW,
> +	AVTAB_XPERMS_DONTAUDIT
>  };
>  
>  int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a,
> @@ -433,14 +431,14 @@ int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a,
>  	uint32_t buf32[8], items, items2, val;
>  	avtab_key_t key;
>  	avtab_datum_t datum;
> -	avtab_operations_t ops;
> +	avtab_extended_perms_t xperms;
>  	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));
> +	memset(&xperms, 0, sizeof(avtab_extended_perms_t));
>  
>  	if (vers < POLICYDB_VERSION_AVTAB) {
>  		rc = next_entry(buf32, fp, sizeof(uint32_t));
> @@ -533,26 +531,32 @@ int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a,
>  		return -1;
>  	}
>  
> -	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);
> +	if ((vers < POLICYDB_VERSION_XPERMS_IOCTL) &&
> +			(key.specified & AVTAB_XPERMS)) {
> +		ERR(fp->handle, "policy version %u does not support extended "
> +				"permissions rules and one was specified\n", vers);
>  		return -1;
> -	} else if (key.specified & AVTAB_OP) {
> +	} else if (key.specified & AVTAB_XPERMS) {
>  		rc = next_entry(&buf8, fp, sizeof(uint8_t));
>  		if (rc < 0) {
>  			ERR(fp->handle, "truncated entry");
>  			return -1;
>  		}
> -		ops.type = buf8;
> +		xperms.specified = buf8;
> +		rc = next_entry(&buf8, fp, sizeof(uint8_t));
> +		if (rc < 0) {
> +			ERR(fp->handle, "truncated entry");
> +			return -1;
> +		}
> +		xperms.driver = 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;
> +		for (i = 0; i < ARRAY_SIZE(xperms.perms); i++)
> +			xperms.perms[i] = le32_to_cpu(buf32[i]);
> +		datum.xperms = &xperms;
>  	} else {
>  		rc = next_entry(buf32, fp, sizeof(uint32_t));
>  		if (rc < 0) {
> diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c
> index b999890..478eaff 100644
> --- a/libsepol/src/expand.c
> +++ b/libsepol/src/expand.c
> @@ -1604,24 +1604,25 @@ 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,
> -				   av_operations_t *operations)
> +				   av_extended_perms_t *xperms)
>  {
>  	avtab_ptr_t node;
>  	avtab_datum_t avdatum;
>  	cond_av_list_t *nl;
> -	int type_match = 0;
> +	int match = 0;
>  
> -	/* AVTAB_OPNUM entries are not necessarily unique */
> -	if (key->specified & AVTAB_OPNUM) {
> +	/* AVTAB_XPERMS entries are not necessarily unique */
> +	if (key->specified & AVTAB_XPERMS) {
>  		node = avtab_search_node(avtab, key);
>  		while (node) {
> -			if (node->datum.ops->type == operations->type) {
> -				type_match = 1;
> +			if ((node->datum.xperms->specified == xperms->specified) &&
> +				(node->datum.xperms->driver == xperms->driver)) {
> +				match = 1;
>  				break;
>  			}
>  			node = avtab_search_node_next(node, key->specified);
>  		}
> -		if (!type_match)
> +		if (!match)
>  			node = NULL;
>  	} else {
>  		node = avtab_search_node(avtab, key);
> @@ -1780,11 +1781,11 @@ 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, av_operations_t *operations)
> +				int enabled, av_extended_perms_t *extended_perms)
>  {
>  	avtab_key_t avkey;
>  	avtab_datum_t *avdatump;
> -	avtab_operations_t *ops;
> +	avtab_extended_perms_t *xperms;
>  	avtab_ptr_t node;
>  	class_perm_node_t *cur;
>  	uint32_t spec = 0;
> @@ -1802,22 +1803,14 @@ 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) {
> +	} else if (specified & AVRULE_XPERMS_ALLOWED) {
> +		spec = AVTAB_XPERMS_ALLOWED;
> +	} else if (specified & AVRULE_XPERMS_AUDITALLOW) {
> +		spec = AVTAB_XPERMS_AUDITALLOW;
> +	} else if (specified & AVRULE_XPERMS_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;
> +		spec = AVTAB_XPERMS_DONTAUDIT;
>  	} else {
>  		assert(0);	/* unreachable */
>  	}
> @@ -1829,7 +1822,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, operations);
> +		node = find_avtab_node(handle, avtab, &avkey, cond, extended_perms);
>  		if (!node)
>  			return EXPAND_RULE_ERROR;
>  		if (enabled) {
> @@ -1859,20 +1852,21 @@ 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) {
> +		} else if (specified & AVRULE_XPERMS) {
> +			if (!avdatump->xperms) {
> +				xperms = (avtab_extended_perms_t *)
> +					calloc(1, sizeof(avtab_extended_perms_t));
> +				if (!xperms) {
>  					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];
> +				node->datum.xperms = xperms;
>  			}
> +			node->datum.xperms->specified = extended_perms->specified;
> +			node->datum.xperms->driver = extended_perms->driver;
> +
> +			for (i = 0; i < ARRAY_SIZE(xperms->perms); i++)
> +				node->datum.xperms->perms[i] |= extended_perms->perms[i];
>  		} else {
>  			assert(0);	/* should never occur */
>  		}
> @@ -1897,10 +1891,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 | AVRULE_OP)) {
> +			if (source_rule->specified & (AVRULE_AV | AVRULE_XPERMS)) {
>  				retval = expand_avrule_helper(handle, source_rule->specified,
>  							      cond, i, i, source_rule->perms,
> -							      dest_avtab, enabled, source_rule->ops);
> +							      dest_avtab, enabled, source_rule->xperms);
>  				if (retval != EXPAND_RULE_SUCCESS)
>  					return retval;
>  			} else {
> @@ -1915,10 +1909,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 | AVRULE_OP)) {
> +			if (source_rule->specified & (AVRULE_AV | AVRULE_XPERMS)) {
>  				retval = expand_avrule_helper(handle, source_rule->specified,
>  							      cond, i, j, source_rule->perms,
> -							      dest_avtab, enabled, source_rule->ops);
> +							      dest_avtab, enabled, source_rule->xperms);
>  				if (retval != EXPAND_RULE_SUCCESS)
>  					return retval;
>  			} else {
> @@ -3155,24 +3149,25 @@ static int expand_avtab_insert(avtab_t * a, avtab_key_t * k, avtab_datum_t * d)
>  {
>  	avtab_ptr_t node;
>  	avtab_datum_t *avd;
> -	avtab_operations_t *ops;
> +	avtab_extended_perms_t *xperms;
>  	unsigned int i;
> -	unsigned int type_match = 0;
> +	unsigned int match = 0;
>  
> -	if (k->specified & AVTAB_OPNUM) {
> +	if (k->specified & AVTAB_XPERMS) {
>  		/*
> -		 * AVTAB_OPNUM entries are not necessarily unique.
> -		 * find node with matching ops->type
> +		 * AVTAB_XPERMS entries are not necessarily unique.
> +		 * find node with matching xperms
>  		 */
>  		node = avtab_search_node(a, k);
>  		while (node) {
> -			if (node->datum.ops->type == d->ops->type) {
> -				type_match = 1;
> +			if ((node->datum.xperms->specified == d->xperms->specified) &&
> +				(node->datum.xperms->driver == d->xperms->driver)) {
> +				match = 1;
>  				break;
>  			}
>  			node = avtab_search_node_next(node, k->specified);
>  		}
> -		if (!type_match)
> +		if (!match)
>  			node = NULL;
>  	} else {
>  		node = avtab_search_node(a, k);
> @@ -3189,7 +3184,7 @@ static int expand_avtab_insert(avtab_t * a, avtab_key_t * k, avtab_datum_t * d)
>  	}
>  
>  	avd = &node->datum;
> -	ops = node->datum.ops;
> +	xperms = node->datum.xperms;
>  	switch (k->specified & ~AVTAB_ENABLED) {
>  	case AVTAB_ALLOWED:
>  	case AVTAB_AUDITALLOW:
> @@ -3198,14 +3193,11 @@ 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];
> +	case AVTAB_XPERMS_ALLOWED:
> +	case AVTAB_XPERMS_AUDITALLOW:
> +	case AVTAB_XPERMS_DONTAUDIT:
> +		for (i = 0; i < ARRAY_SIZE(xperms->perms); i++)
> +			xperms->perms[i] |= d->xperms->perms[i];
>  		break;
>  	default:
>  		ERR(NULL, "Type conflict!");
> diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
> index 8c3c7ac..1677eb5 100644
> --- a/libsepol/src/policydb.c
> +++ b/libsepol/src/policydb.c
> @@ -180,7 +180,7 @@ static struct policydb_compat_info policydb_compat[] = {
>  	},
>  	{
>  	 .type = POLICY_KERN,
> -	 .version = POLICYDB_VERSION_IOCTL_OPERATIONS,
> +	 .version = POLICYDB_VERSION_XPERMS_IOCTL,
>  	 .sym_num = SYM_NUM,
>  	 .ocon_num = OCON_NODE6 + 1,
>  	 .target_platform = SEPOL_TARGET_SELINUX,
> diff --git a/libsepol/src/write.c b/libsepol/src/write.c
> index 6e78eb3..d87ea61 100644
> --- a/libsepol/src/write.c
> +++ b/libsepol/src/write.c
> @@ -221,28 +221,32 @@ static int avtab_write_item(policydb_t * p,
>  	items = put_entry(buf16, sizeof(uint16_t), 4, fp);
>  	if (items != 4)
>  		return POLICYDB_ERROR;
> -	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);
> +	if ((p->policyvers < POLICYDB_VERSION_XPERMS_IOCTL) &&
> +			(cur->key.specified & AVTAB_XPERMS)) {
> +		ERR(fp->handle, "policy version %u does not support ioctl extended"
> +				"permissions rules and one was specified", p->policyvers);
>  		return POLICYDB_ERROR;
>  	}
>  
>  	if (p->target_platform != SEPOL_TARGET_SELINUX &&
> -			(cur->key.specified & AVTAB_OP)) {
> +			(cur->key.specified & AVTAB_XPERMS)) {
>  		ERR(fp->handle, "Target platform %s does not support ioctl "
> -				"operation rules and one was specified",
> +				"extended permissions 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;
> +	if (cur->key.specified & AVTAB_XPERMS) {
> +		buf8 = cur->datum.xperms->specified;
>  		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]);
> +		buf8 = cur->datum.xperms->driver;
> +		items = put_entry(&buf8, sizeof(uint8_t),1,fp);
> +		if (items != 1)
> +			return POLICYDB_ERROR;
> +		for (i = 0; i < ARRAY_SIZE(cur->datum.xperms->perms); i++)
> +			buf32[i] = cpu_to_le32(cur->datum.xperms->perms[i]);
>  		items = put_entry(buf32, sizeof(uint32_t),8,fp);
>  		if (items != 8)
>  			return POLICYDB_ERROR;
> @@ -1546,9 +1550,9 @@ static int avrule_write(avrule_t * avrule, struct policy_file *fp)
>  	uint32_t buf[32], len;
>  	class_perm_node_t *cur;
>  
> -	if (avrule->specified & AVRULE_OP) {
> -		ERR(fp->handle, "module policy does not support ioctl operation"
> -				" rules and one was specified");
> +	if (avrule->specified & AVRULE_XPERMS) {
> +		ERR(fp->handle, "module policy does not support extended"
> +				" permissions rules and one was specified");
>  		return POLICYDB_ERROR;
>  	}
>  
> 

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2015-06-15 13:32 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-06-12 16:01 [PATCH] checkpolicy: switch operations to extended perms Jeff Vander Stoep
2015-06-15 13:32 ` Stephen Smalley

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.