From 01aaeb6a82ca23744fd629e8522697f0fcac8c13 Mon Sep 17 00:00:00 2001
From: Geremy Condra <gcondra@google.com>
Date: Thu, 22 Aug 2013 18:23:37 -0700
Subject: [PATCH] Add sepolicy-check, a utility for auditing selinux policy.

This is based on Joshua Brindle's sepolicy-inject.

Change-Id: Ie75bd56a2996481592dcfe7ad302b52f381d5b18
---
 tools/Android.mk       |  11 ++
 tools/sepolicy-check.c | 267 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 278 insertions(+)
 create mode 100644 tools/sepolicy-check.c

diff --git a/tools/Android.mk b/tools/Android.mk
index ab30c3ced..384158832 100644
--- a/tools/Android.mk
+++ b/tools/Android.mk
@@ -33,3 +33,14 @@ LOCAL_IS_HOST_MODULE := true
 LOCAL_MODULE_TAGS := optional
 
 include $(BUILD_PREBUILT)
+###################################
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := sepolicy-check
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := external/libsepol/include \
+                    external/libselinux/include
+LOCAL_SRC_FILES := sepolicy-check.c
+LOCAL_STATIC_LIBRARIES := libsepol libselinux
+
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/tools/sepolicy-check.c b/tools/sepolicy-check.c
new file mode 100644
index 000000000..ea198e260
--- /dev/null
+++ b/tools/sepolicy-check.c
@@ -0,0 +1,267 @@
+/*
+ * This was derived from public domain works with updates to
+ * work with more modern SELinux libraries.
+ *
+ * It is released into the public domain.
+ *
+ */
+
+#include <getopt.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/services.h>
+
+#define EQUALS 0
+#define NOT 1
+#define ANY 2
+
+void usage(char *arg0) {
+	fprintf(stderr, "%s -s <source> -t <target> -c <class> -p <perm> -P <policy file>\n", arg0);
+	exit(1);
+}
+
+void *cmalloc(size_t s) {
+	void *t = malloc(s);
+	if (t == NULL) {
+		fprintf(stderr, "Out of memory\n");
+		exit(1);
+	}
+	return t;
+}
+
+int parse_ops(char **arg) {
+	switch (*arg[0]) {
+		case '-':
+			*arg = *arg + 1;
+			return NOT;
+		case '*':
+			return ANY;
+		default:
+			return EQUALS;
+	}
+}
+
+int check(int op, uint16_t arg1, uint16_t arg2) {
+	switch (op) {
+		case EQUALS:
+			return arg1 == arg2;
+		case NOT:
+			return arg1 != arg2;
+		case ANY:
+			return 1;
+		default:
+			fprintf(stderr, "Bad op while checking!");
+			return 2;
+	}
+}
+
+int check_perm(avtab_ptr_t current, perm_datum_t *perm) {
+	uint16_t perm_bitmask = 1U << (perm->s.value - 1);
+	return (current->datum.data & perm_bitmask) != 0;
+}
+
+/*
+ * Checks to see if a rule matching the given arguments already exists.
+ *
+ * The format for the arguments is as follows:
+ *
+ * - A bare string is treated as a literal and will be matched by equality.
+ * - A string starting with "-" will be matched by inequality.
+ * - A string starting with "*" will be treated as a wildcard.
+ *
+ * The return codes for this function are as follows:
+ *
+ * - 0 indicates a successful return without a match
+ * - 1 indicates a successful return with a match
+ * - -1 indicates an error
+ */
+int check_rule(char *s, char *t, char *c, char *p, policydb_t *policy) {
+	type_datum_t *src = NULL;
+	type_datum_t *tgt = NULL;
+	class_datum_t *cls = NULL;
+	perm_datum_t *perm = NULL;
+	int s_op = parse_ops(&s);
+	int t_op = parse_ops(&t);
+	int c_op = parse_ops(&c);
+	int p_op = parse_ops(&p);
+	avtab_key_t key;
+	avtab_ptr_t cur;
+	unsigned int i;
+	int match;
+
+	if (s_op != ANY) {
+		src = hashtab_search(policy->p_types.table, s);
+		if (src == NULL) {
+			fprintf(stderr, "source type %s does not exist\n", s);
+			return -1;
+		}
+	}
+	if (t_op != ANY) {
+		tgt = hashtab_search(policy->p_types.table, t);
+		if (tgt == NULL) {
+			fprintf(stderr, "target type %s does not exist\n", t);
+			return -1;
+		}
+	}
+	if (c_op != ANY) {
+		cls = hashtab_search(policy->p_classes.table, c);
+		if (cls == NULL) {
+			fprintf(stderr, "class %s does not exist\n", c);
+			return -1;
+		}
+	}
+	if (p_op != ANY) {
+		perm = hashtab_search(cls->permissions.table, p);
+		if (perm == NULL) {
+			if (cls->comdatum == NULL) {
+				fprintf(stderr, "perm %s does not exist in class %s\n", p, c);
+				return -1;
+			}
+			perm = hashtab_search(cls->comdatum->permissions.table, p);
+			if (perm == NULL) {
+				fprintf(stderr, "perm %s does not exist in class %s\n", p, c);
+				return -1;
+			}
+		}
+	}
+
+	if (s_op != ANY)
+		key.source_type = src->s.value;
+	if (t_op != ANY)
+		key.target_type = tgt->s.value;
+	if (c_op != ANY)
+		key.target_class = cls->s.value;
+
+	for (i = 0; i < policy->te_avtab.nslot; i++) {
+		for (cur = policy->te_avtab.htable[i]; cur; cur = cur->next) {
+			match = 1;
+			match &= check(s_op, key.source_type, cur->key.source_type);
+			match &= check(t_op, key.target_type, cur->key.target_type);
+			match &= check(c_op, key.target_class, cur->key.target_class);
+			match &= check_perm(cur, perm);
+			if (match)
+				return 1;
+		}
+	}
+
+	return 0;
+}
+
+int load_policy(char *filename, policydb_t *policydb, struct policy_file *pf) {
+	int fd;
+	struct stat sb;
+	void *map;
+	int ret;
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0) {
+		fprintf(stderr, "Can't open '%s':  %s\n", filename, strerror(errno));
+		return 1;
+	}
+	if (fstat(fd, &sb) < 0) {
+		fprintf(stderr, "Can't stat '%s':  %s\n", filename, strerror(errno));
+		close(fd);
+		return 1;
+	}
+	map = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+	if (map == MAP_FAILED) {
+		fprintf(stderr, "Can't mmap '%s':  %s\n", filename, strerror(errno));
+		close(fd);
+		return 1;
+	}
+
+	policy_file_init(pf);
+	pf->type = PF_USE_MEMORY;
+	pf->data = map;
+	pf->len = sb.st_size;
+	if (policydb_init(policydb)) {
+		fprintf(stderr, "Could not initialize policydb!\n");
+		close(fd);
+		munmap(map, sb.st_size);
+		return 1;
+	}
+	ret = policydb_read(policydb, pf, 0);
+	if (ret) {
+		fprintf(stderr, "error(s) encountered while parsing configuration\n");
+		close(fd);
+		munmap(map, sb.st_size);
+		return 1;
+	}
+
+	return 0;
+}
+
+
+int main(int argc, char **argv)
+{
+	char *policy = NULL, *source = NULL, *target = NULL, *class = NULL, *perm = NULL;
+	policydb_t policydb;
+	struct policy_file pf;
+	sidtab_t sidtab;
+	char ch;
+	int match = 1;
+
+	struct option long_options[] = {
+			{"source", required_argument, NULL, 's'},
+			{"target", required_argument, NULL, 't'},
+			{"class", required_argument, NULL, 'c'},
+			{"perm", required_argument, NULL, 'p'},
+			{"policy", required_argument, NULL, 'P'},
+			{NULL, 0, NULL, 0}
+	};
+
+	while ((ch = getopt_long(argc, argv, "s:t:c:p:P:", long_options, NULL)) != -1) {
+		switch (ch) {
+			case 's':
+				source = optarg;
+				break;
+			case 't':
+				target = optarg;
+				break;
+			case 'c':
+				class = optarg;
+				break;
+			case 'p':
+				perm = optarg;
+				break;
+			case 'P':
+				policy = optarg;
+				break;
+			default:
+				usage(argv[0]);
+		}
+	}
+
+	if (!source || !target || !class || !perm || !policy)
+		usage(argv[0]);
+
+	sepol_set_policydb(&policydb);
+	sepol_set_sidtab(&sidtab);
+
+	if (load_policy(policy, &policydb, &pf))
+		goto out;
+
+	if (policydb_load_isids(&policydb, &sidtab))
+		goto out;
+
+	match = check_rule(source, target, class, perm, &policydb);
+	if (match < 0) {
+		fprintf(stderr, "Error checking rules!\n");
+		goto out;
+	} else if (match > 0) {
+		printf("Match found!\n");
+		goto out;
+	}
+
+	match = 0;
+
+out:
+	policydb_destroy(&policydb);
+	return match;
+}
-- 
GitLab