diff --git a/tools/Android.mk b/tools/Android.mk index 384158832..727a4d3c9 100644 --- a/tools/Android.mk +++ b/tools/Android.mk @@ -5,7 +5,7 @@ include $(CLEAR_VARS) LOCAL_MODULE := checkseapp LOCAL_MODULE_TAGS := optional LOCAL_C_INCLUDES := external/libsepol/include/ -LOCAL_CFLAGS := -DLINK_SEPOL_STATIC +LOCAL_CFLAGS := -DLINK_SEPOL_STATIC -Wall -Werror LOCAL_SRC_FILES := check_seapp.c LOCAL_STATIC_LIBRARIES := libsepol @@ -18,6 +18,7 @@ LOCAL_MODULE := checkfc LOCAL_MODULE_TAGS := optional LOCAL_C_INCLUDES := external/libsepol/include \ external/libselinux/include +LOCAL_CFLAGS := -Wall -Werror LOCAL_SRC_FILES := checkfc.c LOCAL_STATIC_LIBRARIES := libsepol libselinux @@ -38,9 +39,21 @@ include $(CLEAR_VARS) LOCAL_MODULE := sepolicy-check LOCAL_MODULE_TAGS := optional -LOCAL_C_INCLUDES := external/libsepol/include \ - external/libselinux/include +LOCAL_C_INCLUDES := external/libsepol/include +LOCAL_CFLAGS := -Wall -Werror LOCAL_SRC_FILES := sepolicy-check.c -LOCAL_STATIC_LIBRARIES := libsepol libselinux +LOCAL_STATIC_LIBRARIES := libsepol + +include $(BUILD_HOST_EXECUTABLE) + +################################### +include $(CLEAR_VARS) + +LOCAL_MODULE := sepolicy-analyze +LOCAL_MODULE_TAGS := optional +LOCAL_C_INCLUDES := external/libsepol/include +LOCAL_CFLAGS := -Wall -Werror +LOCAL_SRC_FILES := sepolicy-analyze.c +LOCAL_STATIC_LIBRARIES := libsepol include $(BUILD_HOST_EXECUTABLE) diff --git a/tools/check_seapp.c b/tools/check_seapp.c index 3ecd7b9ed..ed781bfca 100644 --- a/tools/check_seapp.c +++ b/tools/check_seapp.c @@ -476,7 +476,7 @@ static bool rule_map_validate(const rule_map *rm) { bool found_name = false; bool found_seinfo = false; char *name = NULL; - key_map *tmp; + const key_map *tmp; for(i=0; i < rm->length; i++) { tmp = &(rm->m[i]); diff --git a/tools/sepolicy-analyze.c b/tools/sepolicy-analyze.c new file mode 100644 index 000000000..9b3d444c9 --- /dev/null +++ b/tools/sepolicy-analyze.c @@ -0,0 +1,379 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void usage(char *arg0) +{ + fprintf(stderr, "%s [-e|--equiv] [-d|--diff] -P \n", arg0); + exit(1); +} + +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; +} + +static int insert_type_rule(avtab_key_t * k, avtab_datum_t * d, + struct avtab_node *type_rules) +{ + struct avtab_node *p, *c, *n; + + for (p = type_rules, c = type_rules->next; c; p = c, c = c->next) { + /* + * Find the insertion point, keeping the list + * ordered by source type, then target type, then + * target class. + */ + if (k->source_type < c->key.source_type) + break; + if (k->source_type == c->key.source_type && + k->target_type < c->key.target_type) + break; + if (k->source_type == c->key.source_type && + k->target_type == c->key.target_type && + k->target_class <= c->key.target_class) + break; + } + + if (c && + k->source_type == c->key.source_type && + k->target_type == c->key.target_type && + k->target_class == c->key.target_class) { + c->datum.data |= d->data; + return 0; + } + + /* Insert the rule */ + n = malloc(sizeof(struct avtab_node)); + if (!n) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + + n->key = *k; + n->datum = *d; + n->next = p->next; + p->next = n; + return 0; +} + +static int create_type_rules_helper(avtab_key_t * k, avtab_datum_t * d, + void *args) +{ + struct avtab_node *type_rules = args; + avtab_key_t key; + + /* + * Insert the rule into the list for + * the source type. The source type value + * is cleared as we want to compare against other type + * rules with different source types. + */ + key = *k; + key.source_type = 0; + if (k->source_type == k->target_type) { + /* Clear target type as well; this is a self rule. */ + key.target_type = 0; + } + if (insert_type_rule(&key, d, &type_rules[k->source_type - 1])) + return -1; + + if (k->source_type == k->target_type) + return 0; + + /* + * If the target type differs, then we also + * insert the rule into the list for the target + * type. We clear the target type value so that + * we can compare against other type rules with + * different target types. + */ + key = *k; + key.target_type = 0; + if (insert_type_rule(&key, d, &type_rules[k->target_type - 1])) + return -1; + + return 0; +} + +static int create_type_rules(avtab_key_t * k, avtab_datum_t * d, void *args) +{ + if (k->specified & AVTAB_ALLOWED) + return create_type_rules_helper(k, d, args); + return 0; +} + +static int create_type_rules_cond(avtab_key_t * k, avtab_datum_t * d, + void *args) +{ + if ((k->specified & (AVTAB_ALLOWED|AVTAB_ENABLED)) == + (AVTAB_ALLOWED|AVTAB_ENABLED)) + return create_type_rules_helper(k, d, args); + return 0; +} + +static void free_type_rules(struct avtab_node *l) +{ + struct avtab_node *tmp; + + while (l) { + tmp = l; + l = l->next; + free(tmp); + } +} + +static void display_allow(policydb_t *policydb, struct avtab_node *n, int idx, + uint32_t perms) +{ + printf(" allow %s %s:%s { %s };\n", + policydb->p_type_val_to_name[n->key.source_type + ? n->key.source_type - 1 : idx], + n->key.target_type == n->key.source_type ? "self" : + policydb->p_type_val_to_name[n->key.target_type + ? n->key.target_type - 1 : idx], + policydb->p_class_val_to_name[n->key.target_class - 1], + sepol_av_to_string + (policydb, n->key.target_class, perms)); +} + +static int find_match(policydb_t *policydb, struct avtab_node *l1, + int idx1, struct avtab_node *l2, int idx2) +{ + struct avtab_node *c; + uint32_t perms1, perms2; + + for (c = l2; c; c = c->next) { + if (l1->key.source_type < c->key.source_type) + break; + if (l1->key.source_type == c->key.source_type && + l1->key.target_type < c->key.target_type) + break; + if (l1->key.source_type == c->key.source_type && + l1->key.target_type == c->key.target_type && + l1->key.target_class <= c->key.target_class) + break; + } + + if (c && + l1->key.source_type == c->key.source_type && + l1->key.target_type == c->key.target_type && + l1->key.target_class == c->key.target_class) { + perms1 = l1->datum.data & ~c->datum.data; + perms2 = c->datum.data & ~l1->datum.data; + if (perms1 || perms2) { + if (perms1) + display_allow(policydb, l1, idx1, perms1); + if (perms2) + display_allow(policydb, c, idx2, perms2); + printf("\n"); + return 1; + } + } + + return 0; +} + +static int analyze_types(policydb_t * policydb, char equiv, char diff) +{ + avtab_t exp_avtab, exp_cond_avtab; + struct avtab_node *type_rules, *l1, *l2; + struct type_datum *type; + size_t i, j; + + /* + * Create a list of access vector rules for each type + * from the access vector table. + */ + type_rules = malloc(sizeof(struct avtab_node) * policydb->p_types.nprim); + if (!type_rules) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + memset(type_rules, 0, sizeof(struct avtab_node) * policydb->p_types.nprim); + + if (avtab_init(&exp_avtab) || avtab_init(&exp_cond_avtab)) { + fputs("out of memory\n", stderr); + return -1; + } + + if (expand_avtab(policydb, &policydb->te_avtab, &exp_avtab)) { + fputs("out of memory\n", stderr); + avtab_destroy(&exp_avtab); + return -1; + } + + if (expand_avtab(policydb, &policydb->te_cond_avtab, &exp_cond_avtab)) { + fputs("out of memory\n", stderr); + avtab_destroy(&exp_avtab); + return -1; + } + + if (avtab_map(&exp_avtab, create_type_rules, type_rules)) + exit(1); + + if (avtab_map(&exp_cond_avtab, create_type_rules_cond, type_rules)) + exit(1); + + avtab_destroy(&exp_avtab); + avtab_destroy(&exp_cond_avtab); + + /* + * Compare the type lists and identify similar types. + */ + for (i = 0; i < policydb->p_types.nprim - 1; i++) { + if (!type_rules[i].next) + continue; + type = policydb->type_val_to_struct[i]; + if (type->flavor) { + free_type_rules(type_rules[i].next); + type_rules[i].next = NULL; + continue; + } + for (j = i + 1; j < policydb->p_types.nprim; j++) { + type = policydb->type_val_to_struct[j]; + if (type->flavor) { + free_type_rules(type_rules[j].next); + type_rules[j].next = NULL; + continue; + } + for (l1 = type_rules[i].next, l2 = type_rules[j].next; + l1 && l2; l1 = l1->next, l2 = l2->next) { + if (l1->key.source_type != l2->key.source_type) + break; + if (l1->key.target_type != l2->key.target_type) + break; + if (l1->key.target_class != l2->key.target_class + || l1->datum.data != l2->datum.data) + break; + } + if (l1 || l2) { + if (diff) { + printf + ("Types %s and %s differ, starting with:\n", + policydb->p_type_val_to_name[i], + policydb->p_type_val_to_name[j]); + + if (l1 && l2) { + if (find_match(policydb, l1, i, l2, j)) + continue; + if (find_match(policydb, l2, j, l1, i)) + continue; + } + if (l1) + display_allow(policydb, l1, i, l1->datum.data); + if (l2) + display_allow(policydb, l2, j, l2->datum.data); + printf("\n"); + } + continue; + } + free_type_rules(type_rules[j].next); + type_rules[j].next = NULL; + if (equiv) { + printf("Types %s and %s are equivalent.\n", + policydb->p_type_val_to_name[i], + policydb->p_type_val_to_name[j]); + } + } + free_type_rules(type_rules[i].next); + type_rules[i].next = NULL; + } + + free(type_rules); + return 0; +} + +int main(int argc, char **argv) +{ + char *policy = NULL; + struct policy_file pf; + policydb_t policydb; + char ch; + char equiv = 0, diff = 0; + + struct option long_options[] = { + {"equiv", no_argument, NULL, 'e'}, + {"diff", no_argument, NULL, 'd'}, + {"policy", required_argument, NULL, 'P'}, + {NULL, 0, NULL, 0} + }; + + while ((ch = getopt_long(argc, argv, "edP:", long_options, NULL)) != -1) { + switch (ch) { + case 'e': + equiv = 1; + break; + case 'd': + diff = 1; + break; + case 'P': + policy = optarg; + break; + default: + usage(argv[0]); + } + } + + if (!policy || (!equiv && !diff)) + usage(argv[0]); + + if (load_policy(policy, &policydb, &pf)) + exit(1); + + analyze_types(&policydb, equiv, diff); + + policydb_destroy(&policydb); + + return 0; +} diff --git a/tools/sepolicy-check.c b/tools/sepolicy-check.c index ad75d16d8..713e7c16a 100644 --- a/tools/sepolicy-check.c +++ b/tools/sepolicy-check.c @@ -1,11 +1,3 @@ -/* - * This was derived from public domain works with updates to - * work with more modern SELinux libraries. - * - * It is released into the public domain. - * - */ - #include #include #include @@ -133,6 +125,8 @@ int check_rule(char *s, char *t, char *c, char *p, policydb_t *policy) { 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) {