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