#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct genfs_iter { genfs_t *genfs; ocontext_t *ocon; }; void *init_genfs_iter(void *policydbp) { struct genfs_iter *out = (struct genfs_iter *) calloc(1, sizeof(struct genfs_iter)); if (!out) { std::cerr << "Failed to allocate genfs iterator" << std::endl; return NULL; } policydb_t *db = static_cast(policydbp); out->genfs = db->genfs; out->ocon = db->genfs->head; return static_cast(out); } /* * print genfs path into *out buffer. * * Returns -1 on error. * Returns 0 on successfully retrieving a genfs entry. * Returns 1 on successfully retrieving the final genfs entry. */ int get_genfs(char *out, size_t max_size, void *policydbp, void *genfs_iterp) { size_t len; struct genfs_iter *i = static_cast(genfs_iterp); policydb_t *db = static_cast(policydbp); len = snprintf(out, max_size, "%s %s %s:%s:%s:s0", i->genfs->fstype, i->ocon->u.name, db->p_user_val_to_name[i->ocon->context->user-1], db->p_role_val_to_name[i->ocon->context->role-1], db->p_type_val_to_name[i->ocon->context->type-1]); if (len >= max_size) { std::cerr << "genfs path exceeds buffer size." << std::endl; return -1; } i->ocon = i->ocon->next; if (i->ocon == NULL) { if (i->genfs->next != NULL) { i->genfs = i->genfs->next; i->ocon = i->genfs->head; } else { return 1; } } return 0; } void destroy_genfs_iter(void *genfs_iterp) { struct genfs_iter *genfs_i = static_cast(genfs_iterp); free(genfs_i); } #define TYPE_ITER_LOOKUP 0 #define TYPE_ITER_ALLTYPES 1 #define TYPE_ITER_ALLATTRS 2 struct type_iter { unsigned int alltypes; type_datum *d; ebitmap_node *n; unsigned int length; unsigned int bit; }; void *init_type_iter(void *policydbp, const char *type, bool is_attr) { policydb_t *db = static_cast(policydbp); struct type_iter *out = (struct type_iter *) calloc(1, sizeof(struct type_iter)); if (!out) { std::cerr << "Failed to allocate type type iterator" << std::endl; return NULL; } if (type == NULL) { out->length = db->p_types.nprim; out->bit = 0; if (is_attr) out->alltypes = TYPE_ITER_ALLATTRS; else out->alltypes = TYPE_ITER_ALLTYPES; } else { out->alltypes = TYPE_ITER_LOOKUP; out->d = static_cast(hashtab_search(db->p_types.table, type)); if (is_attr && out->d->flavor != TYPE_ATTRIB) { std::cerr << "\"" << type << "\" MUST be an attribute in the policy" << std::endl; free(out); return NULL; } else if (!is_attr && out->d->flavor !=TYPE_TYPE) { std::cerr << "\"" << type << "\" MUST be a type in the policy" << std::endl; free(out); return NULL; } if (is_attr) { out->bit = ebitmap_start(&db->attr_type_map[out->d->s.value - 1], &out->n); out->length = ebitmap_length(&db->attr_type_map[out->d->s.value - 1]); } else { out->bit = ebitmap_start(&db->type_attr_map[out->d->s.value - 1], &out->n); out->length = ebitmap_length(&db->type_attr_map[out->d->s.value - 1]); } } return static_cast(out); } void destroy_type_iter(void *type_iterp) { struct type_iter *type_i = static_cast(type_iterp); free(type_i); } /* * print type into *out buffer. * * Returns -1 on error. * Returns 0 on successfully reading an avtab entry. * Returns 1 on complete */ int get_type(char *out, size_t max_size, void *policydbp, void *type_iterp) { size_t len; policydb_t *db = static_cast(policydbp); struct type_iter *i = static_cast(type_iterp); if (!i->alltypes) { for (; i->bit < i->length; i->bit = ebitmap_next(&i->n, i->bit)) { if (!ebitmap_node_get_bit(i->n, i->bit)) { continue; } break; } } while (i->bit < i->length && ((i->alltypes == TYPE_ITER_ALLATTRS && db->type_val_to_struct[i->bit]->flavor != TYPE_ATTRIB) || (i->alltypes == TYPE_ITER_ALLTYPES && db->type_val_to_struct[i->bit]->flavor != TYPE_TYPE))) { i->bit++; } if (i->bit >= i->length) return 1; len = snprintf(out, max_size, "%s", db->p_type_val_to_name[i->bit]); if (len >= max_size) { std::cerr << "type name exceeds buffer size." << std::endl; return -1; } i->alltypes ? i->bit++ : i->bit = ebitmap_next(&i->n, i->bit); return 0; } void *load_policy(const char *policy_path) { FILE *fp; policydb_t *db; fp = fopen(policy_path, "re"); if (!fp) { std::cerr << "Invalid or non-existing policy file: " << policy_path << std::endl; return NULL; } db = (policydb_t *) calloc(1, sizeof(policydb_t)); if (!db) { std::cerr << "Failed to allocate memory for policy db." << std::endl; fclose(fp); return NULL; } sidtab_t sidtab; sepol_set_sidtab(&sidtab); sepol_set_policydb(db); struct stat sb; if (fstat(fileno(fp), &sb)) { std::cerr << "Failed to stat the policy file" << std::endl; free(db); fclose(fp); return NULL; } auto unmap = [=](void *ptr) { munmap(ptr, sb.st_size); }; std::unique_ptr map( mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fileno(fp), 0), unmap); if (!map) { std::cerr << "Failed to map the policy file" << std::endl; free(db); fclose(fp); return NULL; } struct policy_file pf; policy_file_init(&pf); pf.type = PF_USE_MEMORY; pf.data = static_cast(map.get()); pf.len = sb.st_size; if (policydb_init(db)) { std::cerr << "Failed to initialize policydb" << std::endl; free(db); fclose(fp); return NULL; } if (policydb_read(db, &pf, 0)) { std::cerr << "Failed to read binary policy" << std::endl; policydb_destroy(db); free(db); fclose(fp); return NULL; } return static_cast(db); } /* items needed to iterate over the avtab */ struct avtab_iter { avtab_t *avtab; uint32_t i; avtab_ptr_t cur; }; /* * print allow rule into *out buffer. * * Returns -1 on error. * Returns 0 on successfully reading an avtab entry. * Returns 1 on complete */ static int get_avtab_allow_rule(char *out, size_t max_size, policydb_t *db, struct avtab_iter *avtab_i) { size_t len; for (; avtab_i->i < avtab_i->avtab->nslot; (avtab_i->i)++) { if (avtab_i->cur == NULL) { avtab_i->cur = avtab_i->avtab->htable[avtab_i->i]; } for (; avtab_i->cur; avtab_i->cur = (avtab_i->cur)->next) { if (!((avtab_i->cur)->key.specified & AVTAB_ALLOWED)) continue; len = snprintf(out, max_size, "allow,%s,%s,%s,%s", db->p_type_val_to_name[(avtab_i->cur)->key.source_type - 1], db->p_type_val_to_name[(avtab_i->cur)->key.target_type - 1], db->p_class_val_to_name[(avtab_i->cur)->key.target_class - 1], sepol_av_to_string(db, (avtab_i->cur)->key.target_class, (avtab_i->cur)->datum.data)); avtab_i->cur = (avtab_i->cur)->next; if (!(avtab_i->cur)) (avtab_i->i)++; if (len >= max_size) { std::cerr << "Allow rule exceeds buffer size." << std::endl; return -1; } return 0; } avtab_i->cur = NULL; } return 1; } int get_allow_rule(char *out, size_t len, void *policydbp, void *avtab_iterp) { policydb_t *db = static_cast(policydbp); struct avtab_iter *avtab_i = static_cast(avtab_iterp); return get_avtab_allow_rule(out, len, db, avtab_i); } static avtab_iter *init_avtab_common(avtab_t *in) { struct avtab_iter *out = (struct avtab_iter *) calloc(1, sizeof(struct avtab_iter)); if (!out) { std::cerr << "Failed to allocate avtab iterator" << std::endl; return NULL; } out->avtab = in; return out; } void *init_avtab(void *policydbp) { policydb_t *p = static_cast(policydbp); return static_cast(init_avtab_common(&p->te_avtab)); } void *init_cond_avtab(void *policydbp) { policydb_t *p = static_cast(policydbp); return static_cast(init_avtab_common(&p->te_cond_avtab)); } void destroy_avtab(void *avtab_iterp) { struct avtab_iter *avtab_i = static_cast(avtab_iterp); free(avtab_i); } /* * conditional.h> uses 'bool' as a variable name * inside extern "C" { .. } construct, which clang doesn't like. * So, declare the function we need from expand.h ourselves. */ extern "C" int expand_avtab(policydb_t *p, avtab_t *a, avtab_t *expa); static avtab_iter *init_expanded_avtab_common(avtab_t *in, policydb_t *p) { struct avtab_iter *out = (struct avtab_iter *) calloc(1, sizeof(struct avtab_iter)); if (!out) { std::cerr << "Failed to allocate avtab iterator" << std::endl; return NULL; } avtab_t *avtab = (avtab_t *) calloc(1, sizeof(avtab_t)); if (!avtab) { std::cerr << "Failed to allocate avtab" << std::endl; free(out); return NULL; } out->avtab = avtab; if (avtab_init(out->avtab)) { std::cerr << "Failed to initialize avtab" << std::endl; free(avtab); free(out); return NULL; } if (expand_avtab(p, in, out->avtab)) { std::cerr << "Failed to expand avtab" << std::endl; free(avtab); free(out); return NULL; } return out; } void *init_expanded_avtab(void *policydbp) { policydb_t *p = static_cast(policydbp); return static_cast(init_expanded_avtab_common(&p->te_avtab, p)); } void *init_expanded_cond_avtab(void *policydbp) { policydb_t *p = static_cast(policydbp); return static_cast(init_expanded_avtab_common(&p->te_cond_avtab, p)); } void destroy_expanded_avtab(void *avtab_iterp) { struct avtab_iter *avtab_i = static_cast(avtab_iterp); avtab_destroy(avtab_i->avtab); free(avtab_i->avtab); free(avtab_i); } void destroy_policy(void *policydbp) { policydb_t *p = static_cast(policydbp); policydb_destroy(p); }