| #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> |
| #include <sepol/policydb/expand.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; |
| } |
| |
| |
| int expand_and_check(int s_op, uint32_t source_type, |
| int t_op, uint32_t target_type, |
| int c_op, uint32_t target_class, |
| perm_datum_t *perm, policydb_t *policy, avtab_t *avtab) { |
| avtab_t exp_avtab; |
| avtab_ptr_t cur; |
| unsigned int i; |
| int match; |
| |
| if (avtab_init(&exp_avtab)) { |
| fputs("out of memory\n", stderr); |
| return -1; |
| } |
| |
| if (expand_avtab(policy, avtab, &exp_avtab)) { |
| fputs("out of memory\n", stderr); |
| avtab_destroy(&exp_avtab); |
| return -1; |
| } |
| |
| for (i = 0; i < exp_avtab.nslot; i++) { |
| for (cur = exp_avtab.htable[i]; cur; cur = cur->next) { |
| match = 1; |
| match &= check(s_op, source_type, cur->key.source_type); |
| match &= check(t_op, target_type, cur->key.target_type); |
| match &= check(c_op, target_class, cur->key.target_class); |
| match &= check_perm(cur, perm); |
| if (match) { |
| avtab_destroy(&exp_avtab); |
| return 1; |
| } |
| } |
| } |
| |
| avtab_destroy(&exp_avtab); |
| return 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; |
| int match; |
| |
| key.source_type = key.target_type = key.target_class = 0; |
| |
| 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; |
| |
| /* Check unconditional rules after attribute expansion. */ |
| match = expand_and_check(s_op, key.source_type, |
| t_op, key.target_type, |
| c_op, key.target_class, |
| perm, policy, &policy->te_avtab); |
| if (match) |
| return match; |
| |
| /* Check conditional rules after attribute expansion. */ |
| return expand_and_check(s_op, key.source_type, |
| t_op, key.target_type, |
| c_op, key.target_class, |
| perm, policy, &policy->te_cond_avtab); |
| } |
| |
| 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; |
| |
| 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; |
| } |