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