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 
21 struct type_iter {
22     type_datum *d;
23     ebitmap_node *n;
24     unsigned int length;
25     unsigned int bit;
26 };
27 
init_type_iter(void * policydbp,const char * type,bool is_attr)28 void *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 
destroy_type_iter(void * type_iterp)61 void 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  */
get_type(char * out,size_t max_size,void * policydbp,void * type_iterp)74 int 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 
load_policy(const char * policy_path)96 void *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 */
160 struct 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  */
get_avtab_allow_rule(char * out,size_t max_size,policydb_t * db,struct avtab_iter * avtab_i)173 static 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 
get_allow_rule(char * out,size_t len,void * policydbp,void * avtab_iterp)205 int 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  */
218 extern "C" int expand_avtab(policydb_t *p, avtab_t *a, avtab_t *expa);
219 
init_avtab_common(avtab_t * in,policydb_t * p)220 static 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 
init_avtab(void * policydbp)243 void *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 
init_cond_avtab(void * policydbp)249 void *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 
destroy_avtab(void * avtab_iterp)255 void 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 
destroy_policy(void * policydbp)262 void destroy_policy(void *policydbp)
263 {
264     policydb_t *p = static_cast<policydb_t *>(policydbp);
265     policydb_destroy(p);
266 }
267