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