• 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 	if (compat_validate(rec, lr, rec->spec_file, lr->lineno))
147 		return -1;
148 
149 	if (translating && !lr->ctx_trans &&
150 	    selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans))
151 		return -1;
152 
153 	return 0;
154 }
155 
156 static struct selabel_lookup_rec *
selabel_lookup_common(struct selabel_handle * rec,int translating,const char * key,int type)157 selabel_lookup_common(struct selabel_handle *rec, int translating,
158 		      const char *key, int type)
159 {
160 	struct selabel_lookup_rec *lr;
161 
162 	if (key == NULL) {
163 		errno = EINVAL;
164 		return NULL;
165 	}
166 
167 	lr = rec->func_lookup(rec, key, type);
168 	if (!lr)
169 		return NULL;
170 
171 	if (selabel_fini(rec, lr, translating))
172 		return NULL;
173 
174 	return lr;
175 }
176 
177 static struct selabel_lookup_rec *
selabel_lookup_bm_common(struct selabel_handle * rec,int translating,const char * key,int type,const char ** aliases)178 selabel_lookup_bm_common(struct selabel_handle *rec, int translating,
179 		      const char *key, int type, const char **aliases)
180 {
181 	struct selabel_lookup_rec *lr;
182 
183 	if (key == NULL) {
184 		errno = EINVAL;
185 		return NULL;
186 	}
187 
188 	lr = rec->func_lookup_best_match(rec, key, aliases, type);
189 	if (!lr)
190 		return NULL;
191 
192 	if (selabel_fini(rec, lr, translating))
193 		return NULL;
194 
195 	return lr;
196 }
197 
198 /*
199  * Public API
200  */
201 
selabel_open(unsigned int backend,const struct selinux_opt * opts,unsigned nopts)202 struct selabel_handle *selabel_open(unsigned int backend,
203 				    const struct selinux_opt *opts,
204 				    unsigned nopts)
205 {
206 	struct selabel_handle *rec = NULL;
207 
208 	if (backend >= ARRAY_SIZE(initfuncs)) {
209 		errno = EINVAL;
210 		goto out;
211 	}
212 
213 	if (!initfuncs[backend]) {
214 		errno = ENOTSUP;
215 		goto out;
216 	}
217 
218 	rec = (struct selabel_handle *)malloc(sizeof(*rec));
219 	if (!rec)
220 		goto out;
221 
222 	memset(rec, 0, sizeof(*rec));
223 	rec->backend = backend;
224 	rec->validating = selabel_is_validate_set(opts, nopts);
225 
226 	rec->digest = selabel_is_digest_set(opts, nopts, rec->digest);
227 
228 	if ((*initfuncs[backend])(rec, opts, nopts)) {
229 		free(rec->spec_file);
230 		free(rec);
231 		rec = NULL;
232 	}
233 
234 out:
235 	return rec;
236 }
237 
selabel_lookup(struct selabel_handle * rec,char ** con,const char * key,int type)238 int selabel_lookup(struct selabel_handle *rec, char **con,
239 		   const char *key, int type)
240 {
241 	struct selabel_lookup_rec *lr;
242 
243 	lr = selabel_lookup_common(rec, 1, key, type);
244 	if (!lr)
245 		return -1;
246 
247 	*con = strdup(lr->ctx_trans);
248 	return *con ? 0 : -1;
249 }
250 
selabel_lookup_raw(struct selabel_handle * rec,char ** con,const char * key,int type)251 int selabel_lookup_raw(struct selabel_handle *rec, char **con,
252 		       const char *key, int type)
253 {
254 	struct selabel_lookup_rec *lr;
255 
256 	lr = selabel_lookup_common(rec, 0, key, type);
257 	if (!lr)
258 		return -1;
259 
260 	*con = strdup(lr->ctx_raw);
261 	return *con ? 0 : -1;
262 }
263 
selabel_partial_match(struct selabel_handle * rec,const char * key)264 bool selabel_partial_match(struct selabel_handle *rec, const char *key)
265 {
266 	if (!rec->func_partial_match) {
267 		/*
268 		 * If the label backend does not support partial matching,
269 		 * then assume a match is possible.
270 		 */
271 		return true;
272 	}
273 
274 	return rec->func_partial_match(rec, key);
275 }
276 
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)277 bool selabel_get_digests_all_partial_matches(struct selabel_handle *rec,
278 					     const char *key,
279 					     uint8_t **calculated_digest,
280 					     uint8_t **xattr_digest,
281 					     size_t *digest_len)
282 {
283 	if (!rec->func_get_digests_all_partial_matches)
284 		return false;
285 
286 	return rec->func_get_digests_all_partial_matches(rec, key,
287 							 calculated_digest,
288 							 xattr_digest,
289 							 digest_len);
290 }
291 
selabel_hash_all_partial_matches(struct selabel_handle * rec,const char * key,uint8_t * digest)292 bool selabel_hash_all_partial_matches(struct selabel_handle *rec,
293                                       const char *key, uint8_t *digest) {
294 	if (!rec->func_hash_all_partial_matches) {
295 		return false;
296 	}
297 
298 	return rec->func_hash_all_partial_matches(rec, key, digest);
299 }
300 
selabel_lookup_best_match(struct selabel_handle * rec,char ** con,const char * key,const char ** aliases,int type)301 int selabel_lookup_best_match(struct selabel_handle *rec, char **con,
302 			      const char *key, const char **aliases, int type)
303 {
304 	struct selabel_lookup_rec *lr;
305 
306 	if (!rec->func_lookup_best_match) {
307 		errno = ENOTSUP;
308 		return -1;
309 	}
310 
311 	lr = selabel_lookup_bm_common(rec, 1, key, type, aliases);
312 	if (!lr)
313 		return -1;
314 
315 	*con = strdup(lr->ctx_trans);
316 	return *con ? 0 : -1;
317 }
318 
selabel_lookup_best_match_raw(struct selabel_handle * rec,char ** con,const char * key,const char ** aliases,int type)319 int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con,
320 			      const char *key, const char **aliases, int type)
321 {
322 	struct selabel_lookup_rec *lr;
323 
324 	if (!rec->func_lookup_best_match) {
325 		errno = ENOTSUP;
326 		return -1;
327 	}
328 
329 	lr = selabel_lookup_bm_common(rec, 0, key, type, aliases);
330 	if (!lr)
331 		return -1;
332 
333 	*con = strdup(lr->ctx_raw);
334 	return *con ? 0 : -1;
335 }
336 
selabel_cmp(struct selabel_handle * h1,struct selabel_handle * h2)337 enum selabel_cmp_result selabel_cmp(struct selabel_handle *h1,
338 				    struct selabel_handle *h2)
339 {
340 	if (!h1->func_cmp || h1->func_cmp != h2->func_cmp)
341 		return SELABEL_INCOMPARABLE;
342 
343 	return h1->func_cmp(h1, h2);
344 }
345 
selabel_digest(struct selabel_handle * rec,unsigned char ** digest,size_t * digest_len,char *** specfiles,size_t * num_specfiles)346 int selabel_digest(struct selabel_handle *rec,
347 				    unsigned char **digest, size_t *digest_len,
348 				    char ***specfiles, size_t *num_specfiles)
349 {
350 	if (!rec->digest) {
351 		errno = EINVAL;
352 		return -1;
353 	}
354 
355 	*digest = rec->digest->digest;
356 	*digest_len = DIGEST_SPECFILE_SIZE;
357 	*specfiles = rec->digest->specfile_list;
358 	*num_specfiles = rec->digest->specfile_cnt;
359 	return 0;
360 }
361 
selabel_close(struct selabel_handle * rec)362 void selabel_close(struct selabel_handle *rec)
363 {
364 	if (rec->digest)
365 		selabel_digest_fini(rec->digest);
366 	rec->func_close(rec);
367 	free(rec->spec_file);
368 	free(rec);
369 }
370 
selabel_stats(struct selabel_handle * rec)371 void selabel_stats(struct selabel_handle *rec)
372 {
373 	rec->func_stats(rec);
374 }
375