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