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