1 /*
2 * Generalized labeling frontend for userspace object managers.
3 *
4 * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil>
5 */
6
7 #include <sys/types.h>
8 #include <ctype.h>
9 #include <errno.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/stat.h>
14 #include <selinux/selinux.h>
15 #include "callbacks.h"
16 #include "label_internal.h"
17
18 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
19
20 #ifdef NO_MEDIA_BACKEND
21 #define CONFIG_MEDIA_BACKEND(fnptr) NULL
22 #else
23 #define CONFIG_MEDIA_BACKEND(fnptr) &fnptr
24 #endif
25
26 #ifdef NO_X_BACKEND
27 #define CONFIG_X_BACKEND(fnptr) NULL
28 #else
29 #define CONFIG_X_BACKEND(fnptr) &fnptr
30 #endif
31
32 #ifdef NO_DB_BACKEND
33 #define CONFIG_DB_BACKEND(fnptr) NULL
34 #else
35 #define CONFIG_DB_BACKEND(fnptr) &fnptr
36 #endif
37
38 #ifdef NO_ANDROID_BACKEND
39 #define CONFIG_ANDROID_BACKEND(fnptr) NULL
40 #else
41 #define CONFIG_ANDROID_BACKEND(fnptr) (&(fnptr))
42 #endif
43
44 typedef int (*selabel_initfunc)(struct selabel_handle *rec,
45 const struct selinux_opt *opts,
46 unsigned nopts);
47
48 static selabel_initfunc initfuncs[] = {
49 &selabel_file_init,
50 CONFIG_MEDIA_BACKEND(selabel_media_init),
51 CONFIG_X_BACKEND(selabel_x_init),
52 CONFIG_DB_BACKEND(selabel_db_init),
53 CONFIG_ANDROID_BACKEND(selabel_property_init),
54 CONFIG_ANDROID_BACKEND(selabel_service_init),
55 };
56
selabel_is_digest_set(const struct selinux_opt * opts,unsigned n,struct selabel_digest * entry)57 static inline struct selabel_digest *selabel_is_digest_set
58 (const struct selinux_opt *opts,
59 unsigned n,
60 struct selabel_digest *entry)
61 {
62 struct selabel_digest *digest = NULL;
63
64 while (n--) {
65 if (opts[n].type == SELABEL_OPT_DIGEST &&
66 opts[n].value == (char *)1) {
67 digest = calloc(1, sizeof(*digest));
68 if (!digest)
69 goto err;
70
71 digest->digest = calloc(1, DIGEST_SPECFILE_SIZE + 1);
72 if (!digest->digest)
73 goto err;
74
75 digest->specfile_list = calloc(DIGEST_FILES_MAX,
76 sizeof(char *));
77 if (!digest->specfile_list)
78 goto err;
79
80 entry = digest;
81 return entry;
82 }
83 }
84 return NULL;
85
86 err:
87 if (digest) {
88 free(digest->digest);
89 free(digest->specfile_list);
90 free(digest);
91 }
92 return NULL;
93 }
94
selabel_digest_fini(struct selabel_digest * ptr)95 static void selabel_digest_fini(struct selabel_digest *ptr)
96 {
97 int i;
98
99 free(ptr->digest);
100 free(ptr->hashbuf);
101
102 if (ptr->specfile_list) {
103 for (i = 0; ptr->specfile_list[i]; i++)
104 free(ptr->specfile_list[i]);
105 free(ptr->specfile_list);
106 }
107 free(ptr);
108 }
109
110 /*
111 * Validation functions
112 */
113
selabel_is_validate_set(const struct selinux_opt * opts,unsigned n)114 static inline int selabel_is_validate_set(const struct selinux_opt *opts,
115 unsigned n)
116 {
117 while (n--)
118 if (opts[n].type == SELABEL_OPT_VALIDATE)
119 return !!opts[n].value;
120
121 return 0;
122 }
123
selabel_validate(struct selabel_handle * rec,struct selabel_lookup_rec * contexts)124 int selabel_validate(struct selabel_handle *rec,
125 struct selabel_lookup_rec *contexts)
126 {
127 int rc = 0;
128
129 if (!rec->validating || contexts->validated)
130 goto out;
131
132 rc = selinux_validate(&contexts->ctx_raw);
133 if (rc < 0)
134 goto out;
135
136 contexts->validated = 1;
137 out:
138 return rc;
139 }
140
141 /* Public API helpers */
selabel_fini(struct selabel_handle * rec,struct selabel_lookup_rec * lr,int translating)142 static int selabel_fini(struct selabel_handle *rec,
143 struct selabel_lookup_rec *lr,
144 int translating)
145 {
146 #ifdef OHOS_FC_INIT
147 char *path = NULL;
148 if (rec->spec_file != NULL) {
149 path = rec->spec_file[0];
150 }
151 if (compat_validate(rec, lr, path, lr->lineno))
152 return -1;
153 #else
154 if (compat_validate(rec, lr, rec->spec_file, lr->lineno))
155 return -1;
156 #endif
157
158 if (translating && !lr->ctx_trans &&
159 selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans))
160 return -1;
161
162 return 0;
163 }
164
165 static struct selabel_lookup_rec *
selabel_lookup_common(struct selabel_handle * rec,int translating,const char * key,int type)166 selabel_lookup_common(struct selabel_handle *rec, int translating,
167 const char *key, int type)
168 {
169 struct selabel_lookup_rec *lr;
170
171 if (key == NULL) {
172 errno = EINVAL;
173 return NULL;
174 }
175
176 lr = rec->func_lookup(rec, key, type);
177 if (!lr)
178 return NULL;
179
180 if (selabel_fini(rec, lr, translating))
181 return NULL;
182
183 return lr;
184 }
185
186 static struct selabel_lookup_rec *
selabel_lookup_bm_common(struct selabel_handle * rec,int translating,const char * key,int type,const char ** aliases)187 selabel_lookup_bm_common(struct selabel_handle *rec, int translating,
188 const char *key, int type, const char **aliases)
189 {
190 struct selabel_lookup_rec *lr;
191
192 if (key == NULL) {
193 errno = EINVAL;
194 return NULL;
195 }
196
197 lr = rec->func_lookup_best_match(rec, key, aliases, type);
198 if (!lr)
199 return NULL;
200
201 if (selabel_fini(rec, lr, translating))
202 return NULL;
203
204 return lr;
205 }
206
207 #ifdef OHOS_FC_INIT
free_spec_files(struct selabel_handle * rec)208 static void free_spec_files(struct selabel_handle *rec)
209 {
210 if (rec->spec_file != NULL) {
211 for (int path_index = 0; path_index < rec->spec_file_nums; path_index++) {
212 if (rec->spec_file[path_index] != NULL) {
213 free(rec->spec_file[path_index]);
214 }
215 }
216 free(rec->spec_file);
217 }
218 }
219 #endif
220
221 /*
222 * Public API
223 */
224
selabel_open(unsigned int backend,const struct selinux_opt * opts,unsigned nopts)225 struct selabel_handle *selabel_open(unsigned int backend,
226 const struct selinux_opt *opts,
227 unsigned nopts)
228 {
229 struct selabel_handle *rec = NULL;
230
231 if (backend >= ARRAY_SIZE(initfuncs)) {
232 errno = EINVAL;
233 goto out;
234 }
235
236 if (!initfuncs[backend]) {
237 errno = ENOTSUP;
238 goto out;
239 }
240
241 rec = (struct selabel_handle *)malloc(sizeof(*rec));
242 if (!rec)
243 goto out;
244
245 memset(rec, 0, sizeof(*rec));
246 rec->backend = backend;
247 rec->validating = selabel_is_validate_set(opts, nopts);
248
249 rec->digest = selabel_is_digest_set(opts, nopts, rec->digest);
250
251 if ((*initfuncs[backend])(rec, opts, nopts)) {
252 if (rec->digest)
253 selabel_digest_fini(rec->digest);
254 #ifdef OHOS_FC_INIT
255 free_spec_files(rec);
256 #else
257 free(rec->spec_file);
258 #endif
259 free(rec);
260 rec = NULL;
261 }
262
263 out:
264 return rec;
265 }
266
selabel_lookup(struct selabel_handle * rec,char ** con,const char * key,int type)267 int selabel_lookup(struct selabel_handle *rec, char **con,
268 const char *key, int type)
269 {
270 struct selabel_lookup_rec *lr;
271
272 lr = selabel_lookup_common(rec, 1, key, type);
273 if (!lr)
274 return -1;
275
276 *con = strdup(lr->ctx_trans);
277 return *con ? 0 : -1;
278 }
279
selabel_lookup_raw(struct selabel_handle * rec,char ** con,const char * key,int type)280 int selabel_lookup_raw(struct selabel_handle *rec, char **con,
281 const char *key, int type)
282 {
283 struct selabel_lookup_rec *lr;
284
285 lr = selabel_lookup_common(rec, 0, key, type);
286 if (!lr)
287 return -1;
288
289 *con = strdup(lr->ctx_raw);
290 return *con ? 0 : -1;
291 }
292
selabel_partial_match(struct selabel_handle * rec,const char * key)293 bool selabel_partial_match(struct selabel_handle *rec, const char *key)
294 {
295 if (!rec->func_partial_match) {
296 /*
297 * If the label backend does not support partial matching,
298 * then assume a match is possible.
299 */
300 return true;
301 }
302
303 return rec->func_partial_match(rec, key);
304 }
305
selabel_get_digests_all_partial_matches(struct selabel_handle * rec,const char * key,uint8_t ** calculated_digest,uint8_t ** xattr_digest,size_t * digest_len)306 bool selabel_get_digests_all_partial_matches(struct selabel_handle *rec,
307 const char *key,
308 uint8_t **calculated_digest,
309 uint8_t **xattr_digest,
310 size_t *digest_len)
311 {
312 if (!rec->func_get_digests_all_partial_matches)
313 return false;
314
315 return rec->func_get_digests_all_partial_matches(rec, key,
316 calculated_digest,
317 xattr_digest,
318 digest_len);
319 }
320
selabel_hash_all_partial_matches(struct selabel_handle * rec,const char * key,uint8_t * digest)321 bool selabel_hash_all_partial_matches(struct selabel_handle *rec,
322 const char *key, uint8_t *digest) {
323 if (!rec->func_hash_all_partial_matches) {
324 return false;
325 }
326
327 return rec->func_hash_all_partial_matches(rec, key, digest);
328 }
329
selabel_lookup_best_match(struct selabel_handle * rec,char ** con,const char * key,const char ** aliases,int type)330 int selabel_lookup_best_match(struct selabel_handle *rec, char **con,
331 const char *key, const char **aliases, int type)
332 {
333 struct selabel_lookup_rec *lr;
334
335 if (!rec->func_lookup_best_match) {
336 errno = ENOTSUP;
337 return -1;
338 }
339
340 lr = selabel_lookup_bm_common(rec, 1, key, type, aliases);
341 if (!lr)
342 return -1;
343
344 *con = strdup(lr->ctx_trans);
345 return *con ? 0 : -1;
346 }
347
selabel_lookup_best_match_raw(struct selabel_handle * rec,char ** con,const char * key,const char ** aliases,int type)348 int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con,
349 const char *key, const char **aliases, int type)
350 {
351 struct selabel_lookup_rec *lr;
352
353 if (!rec->func_lookup_best_match) {
354 errno = ENOTSUP;
355 return -1;
356 }
357
358 lr = selabel_lookup_bm_common(rec, 0, key, type, aliases);
359 if (!lr)
360 return -1;
361
362 *con = strdup(lr->ctx_raw);
363 return *con ? 0 : -1;
364 }
365
selabel_cmp(struct selabel_handle * h1,struct selabel_handle * h2)366 enum selabel_cmp_result selabel_cmp(struct selabel_handle *h1,
367 struct selabel_handle *h2)
368 {
369 if (!h1->func_cmp || h1->func_cmp != h2->func_cmp)
370 return SELABEL_INCOMPARABLE;
371
372 return h1->func_cmp(h1, h2);
373 }
374
selabel_digest(struct selabel_handle * rec,unsigned char ** digest,size_t * digest_len,char *** specfiles,size_t * num_specfiles)375 int selabel_digest(struct selabel_handle *rec,
376 unsigned char **digest, size_t *digest_len,
377 char ***specfiles, size_t *num_specfiles)
378 {
379 if (!rec->digest) {
380 errno = EINVAL;
381 return -1;
382 }
383
384 *digest = rec->digest->digest;
385 *digest_len = DIGEST_SPECFILE_SIZE;
386 *specfiles = rec->digest->specfile_list;
387 *num_specfiles = rec->digest->specfile_cnt;
388 return 0;
389 }
390
selabel_close(struct selabel_handle * rec)391 void selabel_close(struct selabel_handle *rec)
392 {
393 if (rec->digest)
394 selabel_digest_fini(rec->digest);
395 rec->func_close(rec);
396 #ifdef OHOS_FC_INIT
397 free_spec_files(rec);
398 #else
399 free(rec->spec_file);
400 #endif
401 free(rec);
402 }
403
selabel_stats(struct selabel_handle * rec)404 void selabel_stats(struct selabel_handle *rec)
405 {
406 rec->func_stats(rec);
407 }
408