1#include <stdio.h>
2#include <string>
3#include <sstream>
4#include <stdlib.h>
5#include <unistd.h>
6#include <iostream>
7#include <sys/mman.h>
8#include <sys/stat.h>
9#include <sepol/policydb/avtab.h>
10#include <sepol/policydb/policydb.h>
11#include <sepol/policydb/services.h>
12#include <sepol/policydb/util.h>
13#include <sys/types.h>
14#include <fstream>
15
16#include <android-base/file.h>
17#include <android-base/strings.h>
18#include <sepol_wrap.h>
19
20
21struct type_iter {
22    type_datum *d;
23    ebitmap_node *n;
24    unsigned int length;
25    unsigned int bit;
26};
27
28void *init_type_iter(void *policydbp, const char *type, bool is_attr)
29{
30    policydb_t *db = static_cast<policydb_t *>(policydbp);
31    struct type_iter *out = (struct type_iter *)
32                            calloc(1, sizeof(struct type_iter));
33
34    if (!out) {
35        std::cerr << "Failed to allocate type type iterator" << std::endl;
36        return NULL;
37    }
38
39    out->d = static_cast<type_datum *>(hashtab_search(db->p_types.table, type));
40    if (is_attr && out->d->flavor != TYPE_ATTRIB) {
41        std::cerr << "\"" << type << "\" MUST be an attribute in the policy" << std::endl;
42        free(out);
43        return NULL;
44    } else if (!is_attr && out->d->flavor !=TYPE_TYPE) {
45        std::cerr << "\"" << type << "\" MUST be a type in the policy" << std::endl;
46        free(out);
47        return NULL;
48    }
49
50    if (is_attr) {
51        out->bit = ebitmap_start(&db->attr_type_map[out->d->s.value - 1], &out->n);
52        out->length = ebitmap_length(&db->attr_type_map[out->d->s.value - 1]);
53    } else {
54        out->bit = ebitmap_start(&db->type_attr_map[out->d->s.value - 1], &out->n);
55        out->length = ebitmap_length(&db->type_attr_map[out->d->s.value - 1]);
56    }
57
58    return static_cast<void *>(out);
59}
60
61void destroy_type_iter(void *type_iterp)
62{
63    struct type_iter *type_i = static_cast<struct type_iter *>(type_iterp);
64    free(type_i);
65}
66
67/*
68 * print allow rule into *out buffer.
69 *
70 * Returns -1 on error.
71 * Returns 0 on successfully reading an avtab entry.
72 * Returns 1 on complete
73 */
74int get_type(char *out, size_t max_size, void *policydbp, void *type_iterp)
75{
76    size_t len;
77    policydb_t *db = static_cast<policydb_t *>(policydbp);
78    struct type_iter *i = static_cast<struct type_iter *>(type_iterp);
79
80    for (; i->bit < i->length; i->bit = ebitmap_next(&i->n, i->bit)) {
81        if (!ebitmap_node_get_bit(i->n, i->bit)) {
82            continue;
83        }
84        len = snprintf(out, max_size, "%s", db->p_type_val_to_name[i->bit]);
85        if (len >= max_size) {
86               std::cerr << "type name exceeds buffer size." << std::endl;
87               return -1;
88        }
89        i->bit = ebitmap_next(&i->n, i->bit);
90        return 0;
91    }
92
93    return 1;
94}
95
96void *load_policy(const char *policy_path)
97{
98    FILE *fp;
99    policydb_t *db;
100
101    fp = fopen(policy_path, "re");
102    if (!fp) {
103        std::cerr << "Invalid or non-existing policy file: " << policy_path << std::endl;
104        return NULL;
105    }
106
107    db = (policydb_t *) calloc(1, sizeof(policydb_t));
108    if (!db) {
109        std::cerr << "Failed to allocate memory for policy db." << std::endl;
110        fclose(fp);
111        return NULL;
112    }
113
114    sidtab_t sidtab;
115    sepol_set_sidtab(&sidtab);
116    sepol_set_policydb(db);
117
118    struct stat sb;
119    if (fstat(fileno(fp), &sb)) {
120        std::cerr << "Failed to stat the policy file" << std::endl;
121        free(db);
122        fclose(fp);
123        return NULL;
124    }
125
126    auto unmap = [=](void *ptr) { munmap(ptr, sb.st_size); };
127    std::unique_ptr<void, decltype(unmap)> map(
128        mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fileno(fp), 0), unmap);
129    if (!map) {
130        std::cerr << "Failed to map the policy file" << std::endl;
131        free(db);
132        fclose(fp);
133        return NULL;
134    }
135
136    struct policy_file pf;
137    policy_file_init(&pf);
138    pf.type = PF_USE_MEMORY;
139    pf.data = static_cast<char *>(map.get());
140    pf.len = sb.st_size;
141    if (policydb_init(db)) {
142        std::cerr << "Failed to initialize policydb" << std::endl;
143        free(db);
144        fclose(fp);
145        return NULL;
146    }
147
148    if (policydb_read(db, &pf, 0)) {
149        std::cerr << "Failed to read binary policy" << std::endl;
150        policydb_destroy(db);
151        free(db);
152        fclose(fp);
153        return NULL;
154    }
155
156    return static_cast<void *>(db);
157}
158
159/* items needed to iterate over the avtab */
160struct avtab_iter {
161    avtab_t avtab;
162    uint32_t i;
163    avtab_ptr_t cur;
164};
165
166/*
167 * print allow rule into *out buffer.
168 *
169 * Returns -1 on error.
170 * Returns 0 on successfully reading an avtab entry.
171 * Returns 1 on complete
172 */
173static int get_avtab_allow_rule(char *out, size_t max_size, policydb_t *db,
174                                 struct avtab_iter *avtab_i)
175{
176    size_t len;
177
178    for (; avtab_i->i < avtab_i->avtab.nslot; (avtab_i->i)++) {
179        if (avtab_i->cur == NULL) {
180            avtab_i->cur = avtab_i->avtab.htable[avtab_i->i];
181        }
182        for (; avtab_i->cur; avtab_i->cur = (avtab_i->cur)->next) {
183            if (!((avtab_i->cur)->key.specified & AVTAB_ALLOWED)) continue;
184
185            len = snprintf(out, max_size, "allow,%s,%s,%s,%s",
186                    db->p_type_val_to_name[(avtab_i->cur)->key.source_type - 1],
187                    db->p_type_val_to_name[(avtab_i->cur)->key.target_type - 1],
188                    db->p_class_val_to_name[(avtab_i->cur)->key.target_class - 1],
189                    sepol_av_to_string(db, (avtab_i->cur)->key.target_class, (avtab_i->cur)->datum.data));
190            avtab_i->cur = (avtab_i->cur)->next;
191            if (!(avtab_i->cur))
192                (avtab_i->i)++;
193            if (len >= max_size) {
194                std::cerr << "Allow rule exceeds buffer size." << std::endl;
195                return -1;
196            }
197            return 0;
198        }
199        avtab_i->cur = NULL;
200    }
201
202    return 1;
203}
204
205int get_allow_rule(char *out, size_t len, void *policydbp, void *avtab_iterp)
206{
207    policydb_t *db = static_cast<policydb_t *>(policydbp);
208    struct avtab_iter *avtab_i = static_cast<struct avtab_iter *>(avtab_iterp);
209
210    return get_avtab_allow_rule(out, len, db, avtab_i);
211}
212
213/*
214 * <sepol/policydb/expand.h->conditional.h> uses 'bool' as a variable name
215 * inside extern "C" { .. } construct, which clang doesn't like.
216 * So, declare the function we need from expand.h ourselves.
217 */
218extern "C" int expand_avtab(policydb_t *p, avtab_t *a, avtab_t *expa);
219
220static avtab_iter *init_avtab_common(avtab_t *in, policydb_t *p)
221{
222    struct avtab_iter *out = (struct avtab_iter *)
223                            calloc(1, sizeof(struct avtab_iter));
224    if (!out) {
225        std::cerr << "Failed to allocate avtab" << std::endl;
226        return NULL;
227    }
228
229    if (avtab_init(&out->avtab)) {
230        std::cerr << "Failed to initialize avtab" << std::endl;
231        free(out);
232        return NULL;
233    }
234
235    if (expand_avtab(p, in, &out->avtab)) {
236        std::cerr << "Failed to expand avtab" << std::endl;
237        free(out);
238        return NULL;
239    }
240    return out;
241}
242
243void *init_avtab(void *policydbp)
244{
245    policydb_t *p = static_cast<policydb_t *>(policydbp);
246    return static_cast<void *>(init_avtab_common(&p->te_avtab, p));
247}
248
249void *init_cond_avtab(void *policydbp)
250{
251    policydb_t *p = static_cast<policydb_t *>(policydbp);
252    return static_cast<void *>(init_avtab_common(&p->te_cond_avtab, p));
253}
254
255void destroy_avtab(void *avtab_iterp)
256{
257    struct avtab_iter *avtab_i = static_cast<struct avtab_iter *>(avtab_iterp);
258    avtab_destroy(&avtab_i->avtab);
259    free(avtab_i);
260}
261
262void destroy_policy(void *policydbp)
263{
264    policydb_t *p = static_cast<policydb_t *>(policydbp);
265    policydb_destroy(p);
266}
267