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