1 /*
2 * Generalized labeling frontend for userspace object managers.
3 *
4 * Author : Eamon Walsh <[email protected]>
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_exact_match_init),//service init
55 CONFIG_ANDROID_BACKEND(selabel_exact_match_init),//keyStore key init
56 };
57
selabel_is_digest_set(const struct selinux_opt * opts,unsigned n)58 static inline struct selabel_digest *selabel_is_digest_set
59 (const struct selinux_opt *opts,
60 unsigned n)
61 {
62 struct selabel_digest *digest = NULL;
63
64 while (n) {
65 n--;
66 if (opts[n].type == SELABEL_OPT_DIGEST &&
67 !!opts[n].value) {
68 digest = calloc(1, sizeof(*digest));
69 if (!digest)
70 goto err;
71
72 digest->digest = calloc(1, DIGEST_SPECFILE_SIZE + 1);
73 if (!digest->digest)
74 goto err;
75
76 digest->specfile_list = calloc(DIGEST_FILES_MAX,
77 sizeof(char *));
78 if (!digest->specfile_list)
79 goto err;
80
81 return digest;
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 n--;
119 if (opts[n].type == SELABEL_OPT_VALIDATE)
120 return !!opts[n].value;
121 }
122
123 return 0;
124 }
125
selabel_validate(struct selabel_lookup_rec * contexts)126 int selabel_validate(struct selabel_lookup_rec *contexts)
127 {
128 int rc = 0;
129
130 if (contexts->validated)
131 goto out;
132
133 rc = selinux_validate(&contexts->ctx_raw);
134 if (rc < 0)
135 goto out;
136
137 contexts->validated = true;
138 out:
139 return rc;
140 }
141
142 /* Public API helpers */
selabel_fini(const struct selabel_handle * rec,struct selabel_lookup_rec * lr,bool translating)143 static int selabel_fini(const struct selabel_handle *rec,
144 struct selabel_lookup_rec *lr,
145 bool translating)
146 {
147 char *path = NULL;
148
149 if (rec->spec_files)
150 path = rec->spec_files[0];
151 if (compat_validate(rec, lr, path, lr->lineno))
152 return -1;
153
154 if (translating && !lr->ctx_trans &&
155 selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans))
156 return -1;
157
158 return 0;
159 }
160
161 static struct selabel_lookup_rec *
selabel_lookup_common(struct selabel_handle * rec,bool translating,const char * key,int type)162 selabel_lookup_common(struct selabel_handle *rec, bool translating,
163 const char *key, int type)
164 {
165 struct selabel_lookup_rec *lr;
166
167 if (key == NULL) {
168 errno = EINVAL;
169 return NULL;
170 }
171
172 lr = rec->func_lookup(rec, key, type);
173 if (!lr)
174 return NULL;
175
176 if (selabel_fini(rec, lr, translating))
177 return NULL;
178
179 return lr;
180 }
181
182 static struct selabel_lookup_rec *
selabel_lookup_bm_common(struct selabel_handle * rec,bool translating,const char * key,int type,const char ** aliases)183 selabel_lookup_bm_common(struct selabel_handle *rec, bool translating,
184 const char *key, int type, const char **aliases)
185 {
186 struct selabel_lookup_rec *lr;
187
188 if (key == NULL) {
189 errno = EINVAL;
190 return NULL;
191 }
192
193 lr = rec->func_lookup_best_match(rec, key, aliases, type);
194 if (!lr)
195 return NULL;
196
197 if (selabel_fini(rec, lr, translating))
198 return NULL;
199
200 return lr;
201 }
202
203 /*
204 * Public API
205 */
206
selabel_open(unsigned int backend,const struct selinux_opt * opts,unsigned nopts)207 struct selabel_handle *selabel_open(unsigned int backend,
208 const struct selinux_opt *opts,
209 unsigned nopts)
210 {
211 struct selabel_handle *rec = NULL;
212
213 if (backend >= ARRAY_SIZE(initfuncs)) {
214 errno = EINVAL;
215 goto out;
216 }
217
218 if (!initfuncs[backend]) {
219 errno = ENOTSUP;
220 goto out;
221 }
222
223 rec = (struct selabel_handle *)calloc(1, sizeof(*rec));
224 if (!rec)
225 goto out;
226
227 rec->backend = backend;
228 rec->validating = selabel_is_validate_set(opts, nopts);
229
230 rec->digest = selabel_is_digest_set(opts, nopts);
231
232 if ((*initfuncs[backend])(rec, opts, nopts)) {
233 selabel_close(rec);
234 rec = NULL;
235 }
236 out:
237 return rec;
238 }
239
selabel_lookup(struct selabel_handle * rec,char ** con,const char * key,int type)240 int selabel_lookup(struct selabel_handle *rec, char **con,
241 const char *key, int type)
242 {
243 struct selabel_lookup_rec *lr;
244
245 lr = selabel_lookup_common(rec, true, key, type);
246 if (!lr)
247 return -1;
248
249 *con = strdup(lr->ctx_trans);
250 return *con ? 0 : -1;
251 }
252
selabel_lookup_raw(struct selabel_handle * rec,char ** con,const char * key,int type)253 int selabel_lookup_raw(struct selabel_handle *rec, char **con,
254 const char *key, int type)
255 {
256 struct selabel_lookup_rec *lr;
257
258 lr = selabel_lookup_common(rec, false, key, type);
259 if (!lr)
260 return -1;
261
262 *con = strdup(lr->ctx_raw);
263 return *con ? 0 : -1;
264 }
265
selabel_partial_match(struct selabel_handle * rec,const char * key)266 bool selabel_partial_match(struct selabel_handle *rec, const char *key)
267 {
268 if (!rec->func_partial_match) {
269 /*
270 * If the label backend does not support partial matching,
271 * then assume a match is possible.
272 */
273 return true;
274 }
275
276 return rec->func_partial_match(rec, key);
277 }
278
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)279 bool selabel_get_digests_all_partial_matches(struct selabel_handle *rec,
280 const char *key,
281 uint8_t **calculated_digest,
282 uint8_t **xattr_digest,
283 size_t *digest_len)
284 {
285 if (!rec->func_get_digests_all_partial_matches)
286 return false;
287
288 return rec->func_get_digests_all_partial_matches(rec, key,
289 calculated_digest,
290 xattr_digest,
291 digest_len);
292 }
293
selabel_hash_all_partial_matches(struct selabel_handle * rec,const char * key,uint8_t * digest)294 bool selabel_hash_all_partial_matches(struct selabel_handle *rec,
295 const char *key, uint8_t *digest) {
296 if (!rec->func_hash_all_partial_matches) {
297 return false;
298 }
299
300 return rec->func_hash_all_partial_matches(rec, key, digest);
301 }
302
selabel_lookup_best_match(struct selabel_handle * rec,char ** con,const char * key,const char ** aliases,int type)303 int selabel_lookup_best_match(struct selabel_handle *rec, char **con,
304 const char *key, const char **aliases, int type)
305 {
306 struct selabel_lookup_rec *lr;
307
308 if (!rec->func_lookup_best_match) {
309 errno = ENOTSUP;
310 return -1;
311 }
312
313 lr = selabel_lookup_bm_common(rec, true, key, type, aliases);
314 if (!lr)
315 return -1;
316
317 *con = strdup(lr->ctx_trans);
318 return *con ? 0 : -1;
319 }
320
selabel_lookup_best_match_raw(struct selabel_handle * rec,char ** con,const char * key,const char ** aliases,int type)321 int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con,
322 const char *key, const char **aliases, int type)
323 {
324 struct selabel_lookup_rec *lr;
325
326 if (!rec->func_lookup_best_match) {
327 errno = ENOTSUP;
328 return -1;
329 }
330
331 lr = selabel_lookup_bm_common(rec, false, key, type, aliases);
332 if (!lr)
333 return -1;
334
335 *con = strdup(lr->ctx_raw);
336 return *con ? 0 : -1;
337 }
338
selabel_cmp(const struct selabel_handle * h1,const struct selabel_handle * h2)339 enum selabel_cmp_result selabel_cmp(const struct selabel_handle *h1,
340 const struct selabel_handle *h2)
341 {
342 if (!h1->func_cmp || h1->func_cmp != h2->func_cmp)
343 return SELABEL_INCOMPARABLE;
344
345 return h1->func_cmp(h1, h2);
346 }
347
selabel_digest(struct selabel_handle * rec,unsigned char ** digest,size_t * digest_len,char *** specfiles,size_t * num_specfiles)348 int selabel_digest(struct selabel_handle *rec,
349 unsigned char **digest, size_t *digest_len,
350 char ***specfiles, size_t *num_specfiles)
351 {
352 if (!rec->digest) {
353 errno = EINVAL;
354 return -1;
355 }
356
357 *digest = rec->digest->digest;
358 *digest_len = DIGEST_SPECFILE_SIZE;
359 *specfiles = rec->digest->specfile_list;
360 *num_specfiles = rec->digest->specfile_cnt;
361 return 0;
362 }
363
selabel_close(struct selabel_handle * rec)364 void selabel_close(struct selabel_handle *rec)
365 {
366 size_t i;
367
368 if (rec->spec_files) {
369 for (i = 0; i < rec->spec_files_len; i++)
370 free(rec->spec_files[i]);
371 free(rec->spec_files);
372 }
373 if (rec->digest)
374 selabel_digest_fini(rec->digest);
375 if (rec->func_close)
376 rec->func_close(rec);
377 free(rec);
378 }
379
selabel_stats(struct selabel_handle * rec)380 void selabel_stats(struct selabel_handle *rec)
381 {
382 rec->func_stats(rec);
383 }
384