[PATCH] Add neverallow support for ioctl extended permissions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Neverallow rules for ioctl extended permissions will pass in two
cases:
1. If extended permissions exist for the source-target-class set
   the test will pass if the neverallow values are excluded.
2. If extended permissions do not exist for the source-target-class
   set the test will pass if the ioctl permission is not granted.

Signed-off-by: Jeff Vander Stoep <jeffv@xxxxxxxxxx>
---
 checkpolicy/policy_define.c                |  38 +++++-
 checkpolicy/policy_parse.y                 |   5 +
 checkpolicy/policy_scan.l                  |   8 +-
 checkpolicy/test/dispol.c                  |  62 +--------
 libsepol/include/sepol/policydb/avtab.h    |   1 +
 libsepol/include/sepol/policydb/policydb.h |  10 +-
 libsepol/include/sepol/policydb/util.h     |   2 +
 libsepol/src/assertion.c                   | 194 +++++++++++++++++++++++++++--
 libsepol/src/expand.c                      |  23 +++-
 libsepol/src/util.c                        |  72 +++++++++++
 10 files changed, 331 insertions(+), 84 deletions(-)

diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c
index 7f32029..ee20fea 100644
--- a/checkpolicy/policy_define.c
+++ b/checkpolicy/policy_define.c
@@ -1729,10 +1729,6 @@ avrule_t *define_cond_pol_list(avrule_t * avlist, avrule_t * sl)
 	return sl;
 }
 
-#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_ioctl_range {
 	uint16_t low;
 	uint16_t high;
@@ -1942,6 +1938,8 @@ int define_te_avtab_xperms_helper(int which, avrule_t ** rule)
 {
 	char *id;
 	class_perm_node_t *perms, *tail = NULL, *cur_perms = NULL;
+	class_datum_t *cladatum;
+	perm_datum_t *perdatum = NULL;
 	ebitmap_t tclasses;
 	ebitmap_node_t *node;
 	avrule_t *avrule;
@@ -1968,7 +1966,7 @@ int define_te_avtab_xperms_helper(int which, avrule_t ** rule)
 	while ((id = queue_remove(id_queue))) {
 		if (set_types
 		    (&avrule->stypes, id, &add,
-		     which == AVRULE_NEVERALLOW ? 1 : 0)) {
+		     which == AVRULE_XPERMS_NEVERALLOW ? 1 : 0)) {
 			ret = -1;
 			goto out;
 		}
@@ -1982,7 +1980,7 @@ int define_te_avtab_xperms_helper(int which, avrule_t ** rule)
 		}
 		if (set_types
 		    (&avrule->ttypes, id, &add,
-		     which == AVRULE_NEVERALLOW ? 1 : 0)) {
+		     which == AVRULE_XPERMS_NEVERALLOW ? 1 : 0)) {
 			ret = -1;
 			goto out;
 		}
@@ -1994,6 +1992,7 @@ int define_te_avtab_xperms_helper(int which, avrule_t ** rule)
 		goto out;
 
 	perms = NULL;
+	id = queue_head(id_queue);
 	ebitmap_for_each_bit(&tclasses, node, i) {
 		if (!ebitmap_node_get_bit(node, i))
 			continue;
@@ -2011,6 +2010,29 @@ int define_te_avtab_xperms_helper(int which, avrule_t ** rule)
 		if (tail)
 			tail->next = cur_perms;
 		tail = cur_perms;
+
+		cladatum = policydbp->class_val_to_struct[i];
+		perdatum = hashtab_search(cladatum->permissions.table, id);
+		if (!perdatum) {
+			if (cladatum->comdatum) {
+				perdatum = hashtab_search(cladatum->comdatum->
+							permissions.table,
+							id);
+			}
+		}
+		if (!perdatum) {
+			yyerror2("permission %s is not defined"
+				     " for class %s", id,
+				     policydbp->p_class_val_to_name[i]);
+			continue;
+		} else if (!is_perm_in_scope (id, policydbp->p_class_val_to_name[i])) {
+			yyerror2("permission %s of class %s is"
+			     " not within scope", id,
+			     policydbp->p_class_val_to_name[i]);
+			continue;
+		} else {
+			cur_perms->data |= 1U << (perdatum->s.value - 1);
+		}
 	}
 
 	ebitmap_destroy(&tclasses);
@@ -2246,6 +2268,10 @@ int avrule_cpy(avrule_t *dest, avrule_t *src)
 	}
 	dest->line = src->line;
 	dest->source_filename = strdup(source_file);
+	if (!dest->source_filename) {
+		yyerror("out of memory");
+		return -1;
+	}
 	dest->source_line = src->source_line;
 
 	/* increment through the class perms and copy over */
diff --git a/checkpolicy/policy_parse.y b/checkpolicy/policy_parse.y
index d8b8ac0..3b6a2f8 100644
--- a/checkpolicy/policy_parse.y
+++ b/checkpolicy/policy_parse.y
@@ -129,6 +129,7 @@ typedef int (* require_func_t)(int pass);
 %token ALLOWXPERM
 %token AUDITALLOWXPERM
 %token DONTAUDITXPERM
+%token NEVERALLOWXPERM
 %token SOURCE
 %token TARGET
 %token SAMEUSER
@@ -463,6 +464,7 @@ te_avtab_def		: allow_def
 			| xperm_allow_def
 			| xperm_auditallow_def
 			| xperm_dontaudit_def
+			| xperm_neverallow_def
 			;
 allow_def		: ALLOW names names ':' names names  ';'
 			{if (define_te_avtab(AVRULE_ALLOWED)) return -1; }
@@ -488,6 +490,9 @@ xperm_auditallow_def	: AUDITALLOWXPERM names names ':' names identifier xperms '
 xperm_dontaudit_def	: DONTAUDITXPERM names names ':' names identifier xperms ';'
 			{if (define_te_avtab_extended_perms(AVRULE_XPERMS_DONTAUDIT)) return -1; }
 		        ;
+xperm_neverallow_def	: NEVERALLOWXPERM names names ':' names identifier xperms ';'
+			{if (define_te_avtab_extended_perms(AVRULE_XPERMS_NEVERALLOW)) return -1; }
+		        ;
 attribute_role_def	: ATTRIBUTE_ROLE identifier ';'
 			{if (define_attrib_role()) return -1; }
 		        ;
diff --git a/checkpolicy/policy_scan.l b/checkpolicy/policy_scan.l
index e94a917..22da338 100644
--- a/checkpolicy/policy_scan.l
+++ b/checkpolicy/policy_scan.l
@@ -143,11 +143,13 @@ auditdeny		        { return(AUDITDENY); }
 DONTAUDIT |
 dontaudit                       { return(DONTAUDIT); }
 ALLOWXPERM |
-allowxperm		        { return(ALLOWXPERM); }
+allowxperm			{ return(ALLOWXPERM); }
 AUDITALLOWXPERM |
-auditallowxperm		        { return(AUDITALLOWXPERM); }
+auditallowxperm			{ return(AUDITALLOWXPERM); }
 DONTAUDITXPERM |
-dontauditxperm                  { return(DONTAUDITXPERM); }
+dontauditxperm			{ return(DONTAUDITXPERM); }
+NEVERALLOWXPERM |
+neverallowxperm			{ return(NEVERALLOWXPERM); }
 SOURCE |
 source			        { return(SOURCE); }
 TARGET |
diff --git a/checkpolicy/test/dispol.c b/checkpolicy/test/dispol.c
index 0c6b8d8..86f5688 100644
--- a/checkpolicy/test/dispol.c
+++ b/checkpolicy/test/dispol.c
@@ -54,65 +54,6 @@ int render_access_mask(uint32_t mask, avtab_key_t * key, policydb_t * p,
 	return 0;
 }
 
-#define xperms_test(x, p) (1 & (p[x >> 5] >> (x & 0x1f)))
-#define next_bit_in_range(i, p) \
-	((i + 1 < sizeof(p)*8) && xperms_test((i + 1), p))
-
-int render_ioctl(avtab_extended_perms_t * xperms, FILE * fp)
-{
-	uint16_t value;
-	uint16_t low_bit;
-	uint16_t low_value;
-	unsigned int bit;
-	unsigned int in_range = 0;
-
-	fprintf(fp, "{ ");
-	for (bit = 0; bit < sizeof(xperms->perms)*8; bit++) {
-		if (!xperms_test(bit, xperms->perms))
-			continue;
-
-		if (in_range && next_bit_in_range(bit, xperms->perms)) {
-			/* continue until high value found */
-			continue;
-		} else if (next_bit_in_range(bit, xperms->perms)) {
-			/* low value */
-			low_bit = bit;
-			in_range = 1;
-			continue;
-		}
-
-		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 (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) {
-			value = bit << 8;
-			low_value = low_bit << 8;
-			if (in_range)
-				fprintf(fp, "0x%hx-0x%hx ", low_value, (uint16_t) (value|0xff));
-			else
-				fprintf(fp, "0x%hx-0x%hx ", value, (uint16_t) (value|0xff));
-
-		}
-		if (in_range)
-			in_range = 0;
-	}
-	fprintf(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]);
@@ -214,8 +155,7 @@ int render_av_rule(avtab_key_t * key, avtab_datum_t * datum, uint32_t what,
 		else if (key->specified & AVTAB_XPERMS_DONTAUDIT)
 			fprintf(fp, "dontauditxperm ");
 		render_key(key, p, fp);
-		render_xperms(datum->xperms, fp);
-		fprintf(fp, ";\n");
+		fprintf(fp, "%s;\n", sepol_extended_perms_to_string(datum->xperms));
 	} else {
 		fprintf(fp, "     ERROR: no valid rule type specified\n");
 		return -1;
diff --git a/libsepol/include/sepol/policydb/avtab.h b/libsepol/include/sepol/policydb/avtab.h
index 14bc082..d3ea84e 100644
--- a/libsepol/include/sepol/policydb/avtab.h
+++ b/libsepol/include/sepol/policydb/avtab.h
@@ -62,6 +62,7 @@ typedef struct avtab_key {
 #define AVTAB_XPERMS_ALLOWED	0x0100
 #define AVTAB_XPERMS_AUDITALLOW	0x0200
 #define AVTAB_XPERMS_DONTAUDIT	0x0400
+#define AVTAB_XPERMS_NEVERALLOW	0x0800
 #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 */
diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
index 5da016b..26cec13 100644
--- a/libsepol/include/sepol/policydb/policydb.h
+++ b/libsepol/include/sepol/policydb/policydb.h
@@ -241,13 +241,18 @@ typedef struct class_perm_node {
 	struct class_perm_node *next;
 } class_perm_node_t;
 
+#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)))
+#define EXTENDED_PERMS_LEN 8
+
 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];
+	uint32_t perms[EXTENDED_PERMS_LEN];
 } av_extended_perms_t;
 
 typedef struct avrule {
@@ -266,8 +271,9 @@ typedef struct avrule {
 #define AVRULE_XPERMS_ALLOWED 		0x0100
 #define AVRULE_XPERMS_AUDITALLOW	0x0200
 #define AVRULE_XPERMS_DONTAUDIT		0x0400
+#define AVRULE_XPERMS_NEVERALLOW	0x0800
 #define AVRULE_XPERMS	(AVRULE_XPERMS_ALLOWED | AVRULE_XPERMS_AUDITALLOW | \
-				AVRULE_XPERMS_DONTAUDIT)
+				AVRULE_XPERMS_DONTAUDIT | AVRULE_XPERMS_NEVERALLOW)
 	uint32_t specified;
 #define RULE_SELF 1
 	uint32_t flags;
diff --git a/libsepol/include/sepol/policydb/util.h b/libsepol/include/sepol/policydb/util.h
index cb97ccf..fa12661 100644
--- a/libsepol/include/sepol/policydb/util.h
+++ b/libsepol/include/sepol/policydb/util.h
@@ -32,6 +32,8 @@ extern int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a);
 extern char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass,
 				sepol_access_vector_t av);
 
+char *sepol_extended_perms_to_string(avtab_extended_perms_t *xperms);
+
 /*
  * The tokenize function may be used to
  * replace sscanf
diff --git a/libsepol/src/assertion.c b/libsepol/src/assertion.c
index d9afbde..5aec658 100644
--- a/libsepol/src/assertion.c
+++ b/libsepol/src/assertion.c
@@ -1,8 +1,8 @@
 /* Authors: Joshua Brindle <jbrindle@xxxxxxxxxx>
- *              
- * Assertion checker for avtab entries, taken from 
+ *
+ * Assertion checker for avtab entries, taken from
  * checkpolicy.c by Stephen Smalley <sds@xxxxxxxxxxxxx>
- *              
+ *
  * Copyright (C) 2005 Tresys Technology, LLC
  *
  *  This library is free software; you can redistribute it and/or
@@ -25,12 +25,14 @@
 #include <sepol/policydb/expand.h>
 #include <sepol/policydb/util.h>
 
+#include "private.h"
 #include "debug.h"
 
 struct avtab_match_args {
 	sepol_handle_t *handle;
 	policydb_t *p;
 	avrule_t *avrule;
+	avtab_t *avtab;
 	unsigned long errors;
 };
 
@@ -73,6 +75,125 @@ static int match_any_class_permissions(class_perm_node_t *cp, uint32_t class, ui
 	return 1;
 }
 
+static int extended_permissions_and(uint32_t *perms1, uint32_t *perms2) {
+	size_t i;
+	for (i = 0; i < EXTENDED_PERMS_LEN; i++) {
+		if (perms1[i] & perms2[i])
+			return 1;
+	}
+
+	return 0;
+}
+
+static int check_extended_permissions(av_extended_perms_t *neverallow, avtab_extended_perms_t *allow)
+{
+	int rc = 0;
+	if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION)
+			&& (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) {
+		if (neverallow->driver == allow->driver)
+			rc = extended_permissions_and(neverallow->perms, allow->perms);
+	} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION)
+			&& (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
+		rc = xperm_test(neverallow->driver, allow->perms);
+	} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER)
+			&& (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) {
+		rc = xperm_test(allow->driver, neverallow->perms);
+	} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER)
+			&& (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
+		rc = extended_permissions_and(neverallow->perms, allow->perms);
+	}
+
+	return rc;
+}
+
+/* Compute which allowed extended permissions violate the neverallow rule */
+static void extended_permissions_violated(avtab_extended_perms_t *result,
+					av_extended_perms_t *neverallow,
+					avtab_extended_perms_t *allow)
+{
+	size_t i;
+	if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION)
+			&& (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) {
+		result->specified = AVTAB_XPERMS_IOCTLFUNCTION;
+		result->driver = allow->driver;
+		for (i = 0; i < EXTENDED_PERMS_LEN; i++)
+			result->perms[i] = neverallow->perms[i] & allow->perms[i];
+	} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION)
+			&& (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
+		result->specified = AVTAB_XPERMS_IOCTLFUNCTION;
+		result->driver = neverallow->driver;
+		memcpy(result->perms, neverallow->perms, sizeof(result->perms));
+	} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER)
+			&& (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) {
+		result->specified = AVTAB_XPERMS_IOCTLFUNCTION;
+		result->driver = allow->driver;
+		memcpy(result->perms, allow->perms, sizeof(result->perms));
+	} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER)
+			&& (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
+		result->specified = AVTAB_XPERMS_IOCTLDRIVER;
+		for (i = 0; i < EXTENDED_PERMS_LEN; i++)
+			result->perms[i] = neverallow->perms[i] & allow->perms[i];
+	}
+}
+
+/* Same scenarios of interest as check_assertion_extended_permissions */
+static int report_assertion_extended_permissions(sepol_handle_t *handle,
+				policydb_t *p, const avrule_t *avrule,
+				unsigned int stype, unsigned int ttype,
+				const class_perm_node_t *curperm, uint32_t perms,
+				avtab_key_t *k, avtab_t *avtab)
+{
+	avtab_ptr_t node;
+	avtab_key_t tmp_key;
+	avtab_extended_perms_t *xperms;
+	avtab_extended_perms_t error;
+	int rc = 1;
+	int ret = 0;
+
+	memcpy(&tmp_key, k, sizeof(avtab_key_t));
+	tmp_key.specified = AVTAB_XPERMS_ALLOWED;
+
+	for (node = avtab_search_node(avtab, &tmp_key);
+	     node;
+	     node = avtab_search_node_next(node, tmp_key.specified)) {
+		xperms = node->datum.xperms;
+		if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
+				&& (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER))
+			continue;
+
+		rc = check_extended_permissions(avrule->xperms, xperms);
+		/* failure on the extended permission check_extended_permissionss */
+		if (rc) {
+			extended_permissions_violated(&error, avrule->xperms, xperms);
+			ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of policy.conf) violated by\n"
+					"allowxperm %s %s:%s %s;",
+					avrule->source_line, avrule->source_filename, avrule->line,
+					p->p_type_val_to_name[stype],
+					p->p_type_val_to_name[ttype],
+					p->p_class_val_to_name[curperm->tclass - 1],
+					sepol_extended_perms_to_string(&error));
+
+			rc = 0;
+			ret++;
+		}
+
+	}
+
+	/* failure on the regular permissions */
+	if (rc) {
+		ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of policy.conf) violated by\n"
+				"allow %s %s:%s {%s };",
+				avrule->source_line, avrule->source_filename, avrule->line,
+				p->p_type_val_to_name[stype],
+				p->p_type_val_to_name[ttype],
+				p->p_class_val_to_name[curperm->tclass - 1],
+				sepol_av_to_string(p, curperm->tclass, perms));
+		ret++;
+
+	}
+
+	return ret;
+}
 
 static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void *args)
 {
@@ -80,6 +201,7 @@ static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void
 	struct avtab_match_args *a = (struct avtab_match_args *)args;
 	sepol_handle_t *handle = a->handle;
 	policydb_t *p = a->p;
+	avtab_t *avtab = a->avtab;
 	avrule_t *avrule = a->avrule;
 	class_perm_node_t *cp;
 	uint32_t perms;
@@ -122,6 +244,7 @@ static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void
 		goto exit;
 
 	for (cp = avrule->perms; cp; cp = cp->next) {
+
 		perms = cp->data & d->data;
 		if ((cp->tclass != k->target_class) || !perms) {
 			continue;
@@ -133,12 +256,17 @@ static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void
 			ebitmap_for_each_bit(&tgt_matches, tnode, j) {
 				if (!ebitmap_node_get_bit(tnode, j))
 					continue;
-				a->errors++;
-				report_failure(handle, p, avrule, i, j, cp, perms);
+
+				if (avrule->specified == AVRULE_XPERMS_NEVERALLOW) {
+					a->errors += report_assertion_extended_permissions(handle,p, avrule,
+											i, j, cp, perms, k, avtab);
+				} else {
+					a->errors++;
+					report_failure(handle, p, avrule, i, j, cp, perms);
+				}
 			}
 		}
 	}
-
 	goto exit;
 
 oom:
@@ -175,12 +303,57 @@ oom:
 	return rc;
 }
 
+/*
+ * If the ioctl permission is granted in check_assertion_avtab_match for the
+ * source/target/class matching the current avrule neverallow, a lookup is
+ * performed to determine if extended permissions exist for the source/target/class.
+ *
+ * Four scenarios of interest:
+ * 1. PASS - the ioctl permission is not granted for this source/target/class
+ *    This case is handled in check_assertion_avtab_match
+ * 2. PASS - The ioctl permission is granted AND the extended permission
+ *    is NOT granted
+ * 3. FAIL - The ioctl permission is granted AND no extended permissions
+ *    exist
+ * 4. FAIL - The ioctl permission is granted AND the extended permission is
+ *    granted
+ */
+static int check_assertion_extended_permissions(avrule_t *avrule, avtab_t *avtab,
+						avtab_key_t *k)
+{
+	avtab_ptr_t node;
+	avtab_key_t tmp_key;
+	avtab_extended_perms_t *xperms;
+	av_extended_perms_t *neverallow_xperms = avrule->xperms;
+	int rc = 1;
+
+	memcpy(&tmp_key, k, sizeof(avtab_key_t));
+	tmp_key.specified = AVTAB_XPERMS_ALLOWED;
+
+	for (node = avtab_search_node(avtab, &tmp_key);
+	     node;
+	     node = avtab_search_node_next(node, tmp_key.specified)) {
+		xperms = node->datum.xperms;
+		if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
+				&& (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER))
+			continue;
+
+		rc = check_extended_permissions(neverallow_xperms, xperms);
+		if (rc)
+			break;
+	}
+
+	return rc;
+}
+
+
 static int check_assertion_avtab_match(avtab_key_t *k, avtab_datum_t *d, void *args)
 {
 	int rc;
 	struct avtab_match_args *a = (struct avtab_match_args *)args;
 	policydb_t *p = a->p;
 	avrule_t *avrule = a->avrule;
+	avtab_t *avtab = a->avtab;
 
 	if (k->specified != AVTAB_ALLOWED)
 		goto exit;
@@ -212,6 +385,11 @@ static int check_assertion_avtab_match(avtab_key_t *k, avtab_datum_t *d, void *a
 	if (rc == 0)
 		goto exit;
 
+	if (avrule->specified == AVRULE_XPERMS_NEVERALLOW) {
+		rc = check_assertion_extended_permissions(avrule, avtab, k);
+		if (rc == 0)
+			goto exit;
+	}
 	return 1;
 
 exit:
@@ -231,10 +409,12 @@ int check_assertion(policydb_t *p, avrule_t *avrule)
 	args.p = p;
 	args.avrule = avrule;
 	args.errors = 0;
+	args.avtab = &p->te_avtab;
 
 	rc = avtab_map(&p->te_avtab, check_assertion_avtab_match, &args);
 
 	if (rc == 0) {
+		args.avtab = &p->te_cond_avtab;
 		rc = avtab_map(&p->te_cond_avtab, check_assertion_avtab_match, &args);
 	}
 
@@ -256,7 +436,7 @@ int check_assertions(sepol_handle_t * handle, policydb_t * p,
 	}
 
 	for (a = avrules; a != NULL; a = a->next) {
-		if (!(a->specified & AVRULE_NEVERALLOW))
+		if (!(a->specified & (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW)))
 			continue;
 		rc = check_assertion(p, a);
 		if (rc) {
diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c
index 7b99f40..9047c6d 100644
--- a/libsepol/src/expand.c
+++ b/libsepol/src/expand.c
@@ -1948,6 +1948,8 @@ static int convert_and_expand_rule(sepol_handle_t * handle,
 
 	if (!do_neverallow && source_rule->specified & AVRULE_NEVERALLOW)
 		return EXPAND_RULE_SUCCESS;
+	if (source_rule->specified & AVRULE_XPERMS_NEVERALLOW)
+		return EXPAND_RULE_SUCCESS;
 
 	ebitmap_init(&stypes);
 	ebitmap_init(&ttypes);
@@ -2378,7 +2380,8 @@ int expand_rule(sepol_handle_t * handle,
 	int retval;
 	ebitmap_t stypes, ttypes;
 
-	if (source_rule->specified & AVRULE_NEVERALLOW)
+	if ((source_rule->specified & AVRULE_NEVERALLOW)
+		|| (source_rule->specified & AVRULE_XPERMS_NEVERALLOW))
 		return 1;
 
 	ebitmap_init(&stypes);
@@ -2592,6 +2595,7 @@ static int copy_neverallow(policydb_t * dest_pol, uint32_t * typemap,
 	ebitmap_t stypes, ttypes;
 	avrule_t *avrule;
 	class_perm_node_t *cur_perm, *new_perm, *tail_perm;
+	av_extended_perms_t *xperms = NULL;
 
 	ebitmap_init(&stypes);
 	ebitmap_init(&ttypes);
@@ -2608,7 +2612,7 @@ static int copy_neverallow(policydb_t * dest_pol, uint32_t * typemap,
 		return -1;
 
 	avrule_init(avrule);
-	avrule->specified = AVRULE_NEVERALLOW;
+	avrule->specified = source_rule->specified;
 	avrule->line = source_rule->line;
 	avrule->flags = source_rule->flags;
 	avrule->source_line = source_rule->source_line;
@@ -2647,6 +2651,15 @@ static int copy_neverallow(policydb_t * dest_pol, uint32_t * typemap,
 		cur_perm = cur_perm->next;
 	}
 
+	/* copy over extended permissions */
+	if (source_rule->xperms) {
+		xperms = calloc(1, sizeof(av_extended_perms_t));
+		if (!xperms)
+			goto err;
+		memcpy(xperms, source_rule->xperms, sizeof(av_extended_perms_t));
+		avrule->xperms = xperms;
+	}
+
 	/* just prepend the avrule to the first branch; it'll never be
 	   written to disk */
 	if (!dest_pol->global->branch_list->avrules)
@@ -2672,6 +2685,7 @@ static int copy_neverallow(policydb_t * dest_pol, uint32_t * typemap,
 		free(cur_perm);
 		cur_perm = tail_perm;
 	}
+	free(xperms);
 	free(avrule);
 	return -1;
 }
@@ -2724,16 +2738,15 @@ static int copy_and_expand_avrule_block(expand_state_t * state)
 		cur_avrule = decl->avrules;
 		while (cur_avrule != NULL) {
 			if (!(state->expand_neverallow)
-			    && cur_avrule->specified & AVRULE_NEVERALLOW) {
+			    && cur_avrule->specified & (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW)) {
 				/* copy this over directly so that assertions are checked later */
 				if (copy_neverallow
 				    (state->out, state->typemap, cur_avrule))
 					ERR(state->handle,
 					    "Error while copying neverallow.");
 			} else {
-				if (cur_avrule->specified & AVRULE_NEVERALLOW) {
+				if (cur_avrule->specified & (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW))
 					state->out->unsupported_format = 1;
-				}
 				if (convert_and_expand_rule
 				    (state->handle, state->out, state->typemap,
 				     cur_avrule, &state->out->te_avtab, NULL,
diff --git a/libsepol/src/util.c b/libsepol/src/util.c
index 6e285d5..ff8f7f2 100644
--- a/libsepol/src/util.c
+++ b/libsepol/src/util.c
@@ -119,6 +119,78 @@ char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass,
 	return avbuf;
 }
 
+#define next_bit_in_range(i, p) ((i + 1 < sizeof(p)*8) && xperm_test((i + 1), p))
+
+char *sepol_extended_perms_to_string(avtab_extended_perms_t *xperms)
+{
+	uint16_t value;
+	uint16_t low_bit;
+	uint16_t low_value;
+	unsigned int bit;
+	unsigned int in_range = 0;
+	static char xpermsbuf[2048];
+	xpermsbuf[0] = '\0';
+	char *p;
+	int len, xpermslen = 0;
+	p = xpermsbuf;
+
+	if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
+		&& (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER))
+		return NULL;
+
+	len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "ioctl { ");
+	p += len;
+	xpermslen += len;
+
+	for (bit = 0; bit < sizeof(xperms->perms)*8; bit++) {
+		if (!xperm_test(bit, xperms->perms))
+			continue;
+
+		if (in_range && next_bit_in_range(bit, xperms->perms)) {
+			/* continue until high value found */
+			continue;
+		} else if (next_bit_in_range(bit, xperms->perms)) {
+			/* low value */
+			low_bit = bit;
+			in_range = 1;
+			continue;
+		}
+
+		if (xperms->specified & AVTAB_XPERMS_IOCTLFUNCTION) {
+			value = xperms->driver<<8 | bit;
+			low_value = xperms->driver<<8 | low_bit;
+			if (in_range) {
+				len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", low_value, value);
+			} else {
+				len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx ", value);
+			}
+		} else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) {
+			value = bit << 8;
+			low_value = low_bit << 8;
+			if (in_range) {
+				len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", low_value, (uint16_t) (value|0xff));
+			} else {
+				len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", value, (uint16_t) (value|0xff));
+			}
+
+		}
+
+		if (len < 0 || (size_t) len >= (sizeof(xpermsbuf) - xpermslen))
+			return NULL;
+
+		p += len;
+		xpermslen += len;
+		if (in_range)
+			in_range = 0;
+	}
+
+	len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "}");
+	if (len < 0 || (size_t) len >= (sizeof(xpermsbuf) - xpermslen))
+		return NULL;
+
+	return xpermsbuf;
+}
+
 /*
  * The tokenize and tokenize_str functions may be used to
  * replace sscanf to read tokens from buffers.
-- 
2.6.0.rc0.131.gf624c3d

_______________________________________________
Selinux mailing list
Selinux@xxxxxxxxxxxxx
To unsubscribe, send email to Selinux-leave@xxxxxxxxxxxxx.
To get help, send an email containing "help" to Selinux-request@xxxxxxxxxxxxx.



[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux