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 const 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)57 static inline struct selabel_digest *selabel_is_digest_set
58 (const struct selinux_opt *opts,
59 unsigned n)
60 {
61 struct selabel_digest *digest = NULL;
62
63 while (n) {
64 n--;
65 if (opts[n].type == SELABEL_OPT_DIGEST &&
66 !!opts[n].value) {
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 return digest;
81 }
82 }
83 return NULL;
84
85 err:
86 if (digest) {
87 free(digest->digest);
88 free(digest->specfile_list);
89 free(digest);
90 }
91 return NULL;
92 }
93
selabel_digest_fini(struct selabel_digest * ptr)94 static void selabel_digest_fini(struct selabel_digest *ptr)
95 {
96 int i;
97
98 free(ptr->digest);
99 free(ptr->hashbuf);
100
101 if (ptr->specfile_list) {
102 for (i = 0; ptr->specfile_list[i]; i++)
103 free(ptr->specfile_list[i]);
104 free(ptr->specfile_list);
105 }
106 free(ptr);
107 }
108
109 /*
110 * Validation functions
111 */
112
selabel_is_validate_set(const struct selinux_opt * opts,unsigned n)113 static inline int selabel_is_validate_set(const struct selinux_opt *opts,
114 unsigned n)
115 {
116 while (n) {
117 n--;
118 if (opts[n].type == SELABEL_OPT_VALIDATE)
119 return !!opts[n].value;
120 }
121
122 return 0;
123 }
124
selabel_validate(struct selabel_lookup_rec * contexts)125 int selabel_validate(struct selabel_lookup_rec *contexts)
126 {
127 int rc = 0;
128
129 if (contexts->validated)
130 goto out;
131
132 rc = selinux_validate(&contexts->ctx_raw);
133 if (rc < 0)
134 goto out;
135
136 contexts->validated = true;
137 out:
138 return rc;
139 }
140
141 /* Public API helpers */
selabel_fini(const struct selabel_handle * rec,struct selabel_lookup_rec * lr,bool translating)142 static int selabel_fini(const struct selabel_handle *rec,
143 struct selabel_lookup_rec *lr,
144 bool 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,bool translating,const char * key,int type)166 selabel_lookup_common(struct selabel_handle *rec, bool 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,bool translating,const char * key,int type,const char ** aliases)187 selabel_lookup_bm_common(struct selabel_handle *rec, bool 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 *)calloc(1, sizeof(*rec));
242 if (!rec)
243 goto out;
244
245 rec->backend = backend;
246 rec->validating = selabel_is_validate_set(opts, nopts);
247
248 rec->digest = selabel_is_digest_set(opts, nopts);
249
250 if ((*initfuncs[backend])(rec, opts, nopts)) {
251 selabel_close(rec);
252 rec = NULL;
253 }
254
255 out:
256 return rec;
257 }
258
selabel_lookup(struct selabel_handle * rec,char ** con,const char * key,int type)259 int selabel_lookup(struct selabel_handle *rec, char **con,
260 const char *key, int type)
261 {
262 struct selabel_lookup_rec *lr;
263
264 lr = selabel_lookup_common(rec, true, key, type);
265 if (!lr)
266 return -1;
267
268 *con = strdup(lr->ctx_trans);
269 return *con ? 0 : -1;
270 }
271
selabel_lookup_raw(struct selabel_handle * rec,char ** con,const char * key,int type)272 int selabel_lookup_raw(struct selabel_handle *rec, char **con,
273 const char *key, int type)
274 {
275 struct selabel_lookup_rec *lr;
276
277 lr = selabel_lookup_common(rec, false, key, type);
278 if (!lr)
279 return -1;
280
281 *con = strdup(lr->ctx_raw);
282 return *con ? 0 : -1;
283 }
284
selabel_partial_match(struct selabel_handle * rec,const char * key)285 bool selabel_partial_match(struct selabel_handle *rec, const char *key)
286 {
287 if (!rec->func_partial_match) {
288 /*
289 * If the label backend does not support partial matching,
290 * then assume a match is possible.
291 */
292 return true;
293 }
294
295 return rec->func_partial_match(rec, key);
296 }
297
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)298 bool selabel_get_digests_all_partial_matches(struct selabel_handle *rec,
299 const char *key,
300 uint8_t **calculated_digest,
301 uint8_t **xattr_digest,
302 size_t *digest_len)
303 {
304 if (!rec->func_get_digests_all_partial_matches)
305 return false;
306
307 return rec->func_get_digests_all_partial_matches(rec, key,
308 calculated_digest,
309 xattr_digest,
310 digest_len);
311 }
312
selabel_hash_all_partial_matches(struct selabel_handle * rec,const char * key,uint8_t * digest)313 bool selabel_hash_all_partial_matches(struct selabel_handle *rec,
314 const char *key, uint8_t *digest) {
315 if (!rec->func_hash_all_partial_matches) {
316 return false;
317 }
318
319 return rec->func_hash_all_partial_matches(rec, key, digest);
320 }
321
selabel_lookup_best_match(struct selabel_handle * rec,char ** con,const char * key,const char ** aliases,int type)322 int selabel_lookup_best_match(struct selabel_handle *rec, char **con,
323 const char *key, const char **aliases, int type)
324 {
325 struct selabel_lookup_rec *lr;
326
327 if (!rec->func_lookup_best_match) {
328 errno = ENOTSUP;
329 return -1;
330 }
331
332 lr = selabel_lookup_bm_common(rec, true, key, type, aliases);
333 if (!lr)
334 return -1;
335
336 *con = strdup(lr->ctx_trans);
337 return *con ? 0 : -1;
338 }
339
selabel_lookup_best_match_raw(struct selabel_handle * rec,char ** con,const char * key,const char ** aliases,int type)340 int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con,
341 const char *key, const char **aliases, int type)
342 {
343 struct selabel_lookup_rec *lr;
344
345 if (!rec->func_lookup_best_match) {
346 errno = ENOTSUP;
347 return -1;
348 }
349
350 lr = selabel_lookup_bm_common(rec, false, key, type, aliases);
351 if (!lr)
352 return -1;
353
354 *con = strdup(lr->ctx_raw);
355 return *con ? 0 : -1;
356 }
357
selabel_cmp(const struct selabel_handle * h1,const struct selabel_handle * h2)358 enum selabel_cmp_result selabel_cmp(const struct selabel_handle *h1,
359 const struct selabel_handle *h2)
360 {
361 if (!h1->func_cmp || h1->func_cmp != h2->func_cmp)
362 return SELABEL_INCOMPARABLE;
363
364 return h1->func_cmp(h1, h2);
365 }
366
selabel_digest(struct selabel_handle * rec,unsigned char ** digest,size_t * digest_len,char *** specfiles,size_t * num_specfiles)367 int selabel_digest(struct selabel_handle *rec,
368 unsigned char **digest, size_t *digest_len,
369 char ***specfiles, size_t *num_specfiles)
370 {
371 if (!rec->digest) {
372 errno = EINVAL;
373 return -1;
374 }
375
376 *digest = rec->digest->digest;
377 *digest_len = DIGEST_SPECFILE_SIZE;
378 *specfiles = rec->digest->specfile_list;
379 *num_specfiles = rec->digest->specfile_cnt;
380 return 0;
381 }
382
selabel_close(struct selabel_handle * rec)383 void selabel_close(struct selabel_handle *rec)
384 {
385 if (rec->digest)
386 selabel_digest_fini(rec->digest);
387 rec->func_close(rec);
388 #ifdef OHOS_FC_INIT
389 free_spec_files(rec);
390 #else
391 free(rec->spec_file);
392 #endif
393 free(rec);
394 }
395
selabel_stats(struct selabel_handle * rec)396 void selabel_stats(struct selabel_handle *rec)
397 {
398 rec->func_stats(rec);
399 }
400