You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
296 lines
6.6 KiB
296 lines
6.6 KiB
#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; |
|
}
|
|
|