• 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_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