SELinux: per-command whitelisting of ioctls

 note that this patch depends on a prior patch that is already in
 android-3.4 but has not apparently found its way into the msm 3.4
 branches (but is included in exynos and tegra),
 https://android-review.googlesource.com/#/c/92962/

Extend the generic ioctl permission check with support for per-command
filtering. Source/target/class sets including the ioctl permission may
additionally include a set of commands. Example:

allow <source> <target>:<class> { 0x8910-0x8926 0x892A-0x8935 }
auditallow <source> <target>:<class> 0x892A

When ioctl commands are omitted only the permissions are checked. This
feature is intended to provide finer granularity for the ioctl
permission which may be too imprecise in some circumstances. For
example, the same driver may use ioctls to provide important and
benign functionality such as driver version or socket type as well as
dangerous capabilities such as debugging features, read/write/execute
to physical memory or access to sensitive data. Per-command filtering
provides a mechanism to reduce the attack surface of the kernel, and
limit applications to the subset of commands required.

The format of the policy binary has been modified to include ioctl
commands, and the policy version number has been incremented to
POLICYDB_VERSION_IOCTL_OPERATIONS=30 to account for the format change.

Bug: 20350607
Bug: 18087110
Change-Id: Ibf0e36728f6f3f0d5af56ccdeddee40800af689d
Signed-off-by: Jeff Vander Stoep <jeffv@google.com>
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index f977b03..ff1a188 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -34,13 +34,14 @@
 #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS	27
 #define POLICYDB_VERSION_DEFAULT_TYPE	28
 #define POLICYDB_VERSION_CONSTRAINT_NAMES	29
+#define POLICYDB_VERSION_IOCTL_OPERATIONS	30
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN   POLICYDB_VERSION_BASE
 #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
 #define POLICYDB_VERSION_MAX	CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
 #else
-#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_CONSTRAINT_NAMES
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_IOCTL_OPERATIONS
 #endif
 
 /* Mask for just the mount related flags */
@@ -103,11 +104,40 @@
 	u32 flags;
 };
 
+#define security_operation_set(perms, x) (perms[x >> 5] |= 1 << (x & 0x1f))
+#define security_operation_test(perms, x) (1 & (perms[x >> 5] >> (x & 0x1f)))
+
+struct operation_perm {
+	u32 perms[8];
+};
+
+struct operation_decision {
+	u8 type;
+	u8 specified;
+	struct operation_perm *allowed;
+	struct operation_perm *auditallow;
+	struct operation_perm *dontaudit;
+};
+
+#define OPERATION_ALLOWED 1
+#define OPERATION_AUDITALLOW 2
+#define OPERATION_DONTAUDIT 4
+#define OPERATION_ALL (OPERATION_ALLOWED | OPERATION_AUDITALLOW |\
+			OPERATION_DONTAUDIT)
+struct operation {
+	u16 len;	/* length of operation decision chain */
+	u32 type[8];	/* 256 types */
+};
+
 /* definitions of av_decision.flags */
 #define AVD_FLAGS_PERMISSIVE	0x0001
 
 void security_compute_av(u32 ssid, u32 tsid,
-			 u16 tclass, struct av_decision *avd);
+			 u16 tclass, struct av_decision *avd,
+			 struct operation *ops);
+
+void security_compute_operation(u32 ssid, u32 tsid, u16 tclass,
+			 u8 type, struct operation_decision *od);
 
 void security_compute_av_user(u32 ssid, u32 tsid,
 			     u16 tclass, struct av_decision *avd);