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 struct genfs_iter {
21     genfs_t *genfs;
22     ocontext_t *ocon;
23 };
24 
init_genfs_iter(void * policydbp)25 void *init_genfs_iter(void *policydbp)
26 {
27     struct genfs_iter *out = (struct genfs_iter *)
28                             calloc(1, sizeof(struct genfs_iter));
29 
30     if (!out) {
31         std::cerr << "Failed to allocate genfs iterator" << std::endl;
32         return nullptr;
33     }
34 
35     policydb_t *db = static_cast<policydb_t *>(policydbp);
36 
37     out->genfs = db->genfs;
38     out->ocon = db->genfs->head;
39 
40     return static_cast<void *>(out);
41 }
42 
43 /*
44  * print genfs path into *out buffer.
45  *
46  * Returns -1 on error.
47  * Returns 0 on successfully retrieving a genfs entry.
48  * Returns 1 on successfully retrieving the final genfs entry.
49  */
get_genfs(char * out,size_t max_size,void * policydbp,void * genfs_iterp)50 int get_genfs(char *out, size_t max_size, void *policydbp, void *genfs_iterp)
51 {
52     size_t len;
53     struct genfs_iter *i = static_cast<struct genfs_iter *>(genfs_iterp);
54     policydb_t *db = static_cast<policydb_t *>(policydbp);
55 
56     len = snprintf(out, max_size, "%s %s %s:%s:%s:s0",
57             i->genfs->fstype,
58             i->ocon->u.name,
59             db->p_user_val_to_name[i->ocon->context->user-1],
60             db->p_role_val_to_name[i->ocon->context->role-1],
61             db->p_type_val_to_name[i->ocon->context->type-1]);
62 
63     if (len >= max_size) {
64         std::cerr << "genfs path exceeds buffer size." << std::endl;
65         return -1;
66     }
67 
68     i->ocon = i->ocon->next;
69     if (i->ocon == nullptr) {
70         if (i->genfs->next != nullptr) {
71             i->genfs = i->genfs->next;
72             i->ocon = i->genfs->head;
73         } else {
74             return 1;
75         }
76     }
77 
78     return 0;
79 }
80 
destroy_genfs_iter(void * genfs_iterp)81 void destroy_genfs_iter(void *genfs_iterp)
82 {
83     struct genfs_iter *genfs_i = static_cast<struct genfs_iter *>(genfs_iterp);
84     free(genfs_i);
85 }
86 
87 #define TYPE_ITER_LOOKUP   0
88 #define TYPE_ITER_ALLTYPES 1
89 #define TYPE_ITER_ALLATTRS 2
90 struct type_iter {
91     unsigned int alltypes;
92     type_datum *d;
93     ebitmap_node *n;
94     unsigned int length;
95     unsigned int bit;
96 };
97 
init_type_iter(void * policydbp,const char * type,bool is_attr)98 void *init_type_iter(void *policydbp, const char *type, bool is_attr)
99 {
100     policydb_t *db = static_cast<policydb_t *>(policydbp);
101     struct type_iter *out = (struct type_iter *)
102                             calloc(1, sizeof(struct type_iter));
103 
104     if (!out) {
105         std::cerr << "Failed to allocate type type iterator" << std::endl;
106         return nullptr;
107     }
108 
109     if (type == nullptr) {
110         out->length = db->p_types.nprim;
111         out->bit = 0;
112         if (is_attr)
113             out->alltypes = TYPE_ITER_ALLATTRS;
114         else
115             out->alltypes = TYPE_ITER_ALLTYPES;
116     } else {
117         out->alltypes = TYPE_ITER_LOOKUP;
118         out->d = static_cast<type_datum *>(hashtab_search(db->p_types.table, type));
119         if (out->d == nullptr) {
120             std::cerr << "\"" << type << "\" does not exist" << std::endl;
121             free(out);
122             return nullptr;
123         }
124         if (is_attr && out->d->flavor != TYPE_ATTRIB) {
125             std::cerr << "\"" << type << "\" MUST be an attribute in the policy" << std::endl;
126             free(out);
127             return nullptr;
128         } else if (!is_attr && out->d->flavor != TYPE_TYPE) {
129             std::cerr << "\"" << type << "\" MUST be a type in the policy" << std::endl;
130             free(out);
131             return nullptr;
132         }
133 
134         if (is_attr) {
135             out->bit = ebitmap_start(&db->attr_type_map[out->d->s.value - 1], &out->n);
136             out->length = ebitmap_length(&db->attr_type_map[out->d->s.value - 1]);
137         } else {
138             out->bit = ebitmap_start(&db->type_attr_map[out->d->s.value - 1], &out->n);
139             out->length = ebitmap_length(&db->type_attr_map[out->d->s.value - 1]);
140         }
141     }
142 
143     return static_cast<void *>(out);
144 }
145 
destroy_type_iter(void * type_iterp)146 void destroy_type_iter(void *type_iterp)
147 {
148     struct type_iter *type_i = static_cast<struct type_iter *>(type_iterp);
149     free(type_i);
150 }
151 
152 /*
153  * print type into *out buffer.
154  *
155  * Returns -1 on error.
156  * Returns 0 on successfully reading an avtab entry.
157  * Returns 1 on complete
158  */
get_type(char * out,size_t max_size,void * policydbp,void * type_iterp)159 int get_type(char *out, size_t max_size, void *policydbp, void *type_iterp)
160 {
161     size_t len;
162     policydb_t *db = static_cast<policydb_t *>(policydbp);
163     struct type_iter *i = static_cast<struct type_iter *>(type_iterp);
164 
165     if (!i->alltypes) {
166         for (; i->bit < i->length; i->bit = ebitmap_next(&i->n, i->bit)) {
167             if (!ebitmap_node_get_bit(i->n, i->bit)) {
168                 continue;
169             }
170             break;
171         }
172     }
173     while (i->bit < i->length &&
174            ((i->alltypes == TYPE_ITER_ALLATTRS
175             && db->type_val_to_struct[i->bit]->flavor != TYPE_ATTRIB)
176             || (i->alltypes == TYPE_ITER_ALLTYPES
177             && db->type_val_to_struct[i->bit]->flavor != TYPE_TYPE))) {
178         i->bit++;
179     }
180     if (i->bit >= i->length)
181         return 1;
182     len = snprintf(out, max_size, "%s", db->p_type_val_to_name[i->bit]);
183     if (len >= max_size) {
184         std::cerr << "type name exceeds buffer size." << std::endl;
185         return -1;
186     }
187     i->alltypes ? i->bit++ : i->bit = ebitmap_next(&i->n, i->bit);
188     return 0;
189 }
190 
load_policy(const char * policy_path)191 void *load_policy(const char *policy_path)
192 {
193     FILE *fp;
194     policydb_t *db;
195 
196     fp = fopen(policy_path, "re");
197     if (!fp) {
198         std::cerr << "Invalid or non-existing policy file: " << policy_path << std::endl;
199         return nullptr;
200     }
201 
202     db = (policydb_t *) calloc(1, sizeof(policydb_t));
203     if (!db) {
204         std::cerr << "Failed to allocate memory for policy db." << std::endl;
205         fclose(fp);
206         return nullptr;
207     }
208 
209     sidtab_t sidtab;
210     sepol_set_sidtab(&sidtab);
211     sepol_set_policydb(db);
212 
213     struct stat sb;
214     if (fstat(fileno(fp), &sb)) {
215         std::cerr << "Failed to stat the policy file" << std::endl;
216         free(db);
217         fclose(fp);
218         return nullptr;
219     }
220 
221     auto unmap = [=](void *ptr) { munmap(ptr, sb.st_size); };
222     std::unique_ptr<void, decltype(unmap)> map(
223         mmap(nullptr, sb.st_size, PROT_READ, MAP_PRIVATE, fileno(fp), 0), unmap);
224     if (!map) {
225         std::cerr << "Failed to map the policy file" << std::endl;
226         free(db);
227         fclose(fp);
228         return nullptr;
229     }
230 
231     struct policy_file pf;
232     policy_file_init(&pf);
233     pf.type = PF_USE_MEMORY;
234     pf.data = static_cast<char *>(map.get());
235     pf.len = sb.st_size;
236     if (policydb_init(db)) {
237         std::cerr << "Failed to initialize policydb" << std::endl;
238         free(db);
239         fclose(fp);
240         return nullptr;
241     }
242 
243     if (policydb_read(db, &pf, 0)) {
244         std::cerr << "Failed to read binary policy" << std::endl;
245         policydb_destroy(db);
246         free(db);
247         fclose(fp);
248         return nullptr;
249     }
250 
251     return static_cast<void *>(db);
252 }
253 
254 /* items needed to iterate over the avtab */
255 struct avtab_iter {
256     avtab_t *avtab;
257     uint32_t i;
258     avtab_ptr_t cur;
259 };
260 
261 /*
262  * print allow rule into *out buffer.
263  *
264  * Returns -1 on error.
265  * Returns 0 on successfully reading an avtab entry.
266  * Returns 1 on complete
267  */
get_avtab_allow_rule(char * out,size_t max_size,policydb_t * db,struct avtab_iter * avtab_i)268 static int get_avtab_allow_rule(char *out, size_t max_size, policydb_t *db,
269                                  struct avtab_iter *avtab_i)
270 {
271     size_t len;
272 
273     for (; avtab_i->i < avtab_i->avtab->nslot; (avtab_i->i)++) {
274         if (avtab_i->cur == nullptr) {
275             avtab_i->cur = avtab_i->avtab->htable[avtab_i->i];
276         }
277         for (; avtab_i->cur; avtab_i->cur = (avtab_i->cur)->next) {
278             if (!((avtab_i->cur)->key.specified & AVTAB_ALLOWED)) continue;
279 
280             len = snprintf(out, max_size, "allow,%s,%s,%s,%s",
281                     db->p_type_val_to_name[(avtab_i->cur)->key.source_type - 1],
282                     db->p_type_val_to_name[(avtab_i->cur)->key.target_type - 1],
283                     db->p_class_val_to_name[(avtab_i->cur)->key.target_class - 1],
284                     sepol_av_to_string(db, (avtab_i->cur)->key.target_class, (avtab_i->cur)->datum.data));
285             avtab_i->cur = (avtab_i->cur)->next;
286             if (!(avtab_i->cur))
287                 (avtab_i->i)++;
288             if (len >= max_size) {
289                 std::cerr << "Allow rule exceeds buffer size." << std::endl;
290                 return -1;
291             }
292             return 0;
293         }
294         avtab_i->cur = nullptr;
295     }
296 
297     return 1;
298 }
299 
get_allow_rule(char * out,size_t len,void * policydbp,void * avtab_iterp)300 int get_allow_rule(char *out, size_t len, void *policydbp, void *avtab_iterp)
301 {
302     policydb_t *db = static_cast<policydb_t *>(policydbp);
303     struct avtab_iter *avtab_i = static_cast<struct avtab_iter *>(avtab_iterp);
304 
305     return get_avtab_allow_rule(out, len, db, avtab_i);
306 }
307 
init_avtab_common(avtab_t * in)308 static avtab_iter *init_avtab_common(avtab_t *in)
309 {
310     struct avtab_iter *out = (struct avtab_iter *)
311                             calloc(1, sizeof(struct avtab_iter));
312     if (!out) {
313         std::cerr << "Failed to allocate avtab iterator" << std::endl;
314         return nullptr;
315     }
316 
317     out->avtab = in;
318     return out;
319 }
320 
init_avtab(void * policydbp)321 void *init_avtab(void *policydbp)
322 {
323     policydb_t *p = static_cast<policydb_t *>(policydbp);
324     return static_cast<void *>(init_avtab_common(&p->te_avtab));
325 }
326 
init_cond_avtab(void * policydbp)327 void *init_cond_avtab(void *policydbp)
328 {
329     policydb_t *p = static_cast<policydb_t *>(policydbp);
330     return static_cast<void *>(init_avtab_common(&p->te_cond_avtab));
331 }
332 
destroy_avtab(void * avtab_iterp)333 void destroy_avtab(void *avtab_iterp)
334 {
335     struct avtab_iter *avtab_i = static_cast<struct avtab_iter *>(avtab_iterp);
336     free(avtab_i);
337 }
338 
339 /*
340  * <sepol/policydb/expand.h->conditional.h> uses 'bool' as a variable name
341  * inside extern "C" { .. } construct, which clang doesn't like.
342  * So, declare the function we need from expand.h ourselves.
343  */
344 extern "C" int expand_avtab(policydb_t *p, avtab_t *a, avtab_t *expa);
345 
init_expanded_avtab_common(avtab_t * in,policydb_t * p)346 static avtab_iter *init_expanded_avtab_common(avtab_t *in, policydb_t *p)
347 {
348     struct avtab_iter *out = (struct avtab_iter *)
349                             calloc(1, sizeof(struct avtab_iter));
350     if (!out) {
351         std::cerr << "Failed to allocate avtab iterator" << std::endl;
352         return nullptr;
353     }
354 
355     avtab_t *avtab = (avtab_t *) calloc(1, sizeof(avtab_t));
356 
357     if (!avtab) {
358         std::cerr << "Failed to allocate avtab" << std::endl;
359         free(out);
360         return nullptr;
361     }
362 
363     out->avtab = avtab;
364     if (avtab_init(out->avtab)) {
365         std::cerr << "Failed to initialize avtab" << std::endl;
366         free(avtab);
367         free(out);
368         return nullptr;
369     }
370 
371     if (expand_avtab(p, in, out->avtab)) {
372         std::cerr << "Failed to expand avtab" << std::endl;
373         free(avtab);
374         free(out);
375         return nullptr;
376     }
377     return out;
378 }
379 
init_expanded_avtab(void * policydbp)380 void *init_expanded_avtab(void *policydbp)
381 {
382     policydb_t *p = static_cast<policydb_t *>(policydbp);
383     return static_cast<void *>(init_expanded_avtab_common(&p->te_avtab, p));
384 }
385 
init_expanded_cond_avtab(void * policydbp)386 void *init_expanded_cond_avtab(void *policydbp)
387 {
388     policydb_t *p = static_cast<policydb_t *>(policydbp);
389     return static_cast<void *>(init_expanded_avtab_common(&p->te_cond_avtab, p));
390 }
391 
destroy_expanded_avtab(void * avtab_iterp)392 void destroy_expanded_avtab(void *avtab_iterp)
393 {
394     struct avtab_iter *avtab_i = static_cast<struct avtab_iter *>(avtab_iterp);
395     avtab_destroy(avtab_i->avtab);
396     free(avtab_i->avtab);
397     free(avtab_i);
398 }
399 
destroy_policy(void * policydbp)400 void destroy_policy(void *policydbp)
401 {
402     policydb_t *p = static_cast<policydb_t *>(policydbp);
403     policydb_destroy(p);
404 }
405