#include #include #include #include #include #include #include #include #include #include #include #define EQUALS 0 #define NOT 1 #define ANY 2 void usage(char *arg0) { fprintf(stderr, "%s -s -t -c -p -P \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; }