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