xref: /aosp_15_r20/external/selinux/libselinux/src/label.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1 /*
2  * Generalized labeling frontend for userspace object managers.
3  *
4  * Author : Eamon Walsh <[email protected]>
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_exact_match_init),//service init
55 	CONFIG_ANDROID_BACKEND(selabel_exact_match_init),//keyStore key init
56 };
57 
selabel_is_digest_set(const struct selinux_opt * opts,unsigned n)58 static inline struct selabel_digest *selabel_is_digest_set
59 				    (const struct selinux_opt *opts,
60 				    unsigned n)
61 {
62 	struct selabel_digest *digest = NULL;
63 
64 	while (n) {
65 		n--;
66 		if (opts[n].type == SELABEL_OPT_DIGEST &&
67 					    !!opts[n].value) {
68 			digest = calloc(1, sizeof(*digest));
69 			if (!digest)
70 				goto err;
71 
72 			digest->digest = calloc(1, DIGEST_SPECFILE_SIZE + 1);
73 			if (!digest->digest)
74 				goto err;
75 
76 			digest->specfile_list = calloc(DIGEST_FILES_MAX,
77 							    sizeof(char *));
78 			if (!digest->specfile_list)
79 				goto err;
80 
81 			return digest;
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 		n--;
119 		if (opts[n].type == SELABEL_OPT_VALIDATE)
120 			return !!opts[n].value;
121 	}
122 
123 	return 0;
124 }
125 
selabel_validate(struct selabel_lookup_rec * contexts)126 int selabel_validate(struct selabel_lookup_rec *contexts)
127 {
128 	int rc = 0;
129 
130 	if (contexts->validated)
131 		goto out;
132 
133 	rc = selinux_validate(&contexts->ctx_raw);
134 	if (rc < 0)
135 		goto out;
136 
137 	contexts->validated = true;
138 out:
139 	return rc;
140 }
141 
142 /* Public API helpers */
selabel_fini(const struct selabel_handle * rec,struct selabel_lookup_rec * lr,bool translating)143 static int selabel_fini(const struct selabel_handle *rec,
144 			    struct selabel_lookup_rec *lr,
145 			    bool translating)
146 {
147 	char *path = NULL;
148 
149 	if (rec->spec_files)
150 		path = rec->spec_files[0];
151 	if (compat_validate(rec, lr, path, lr->lineno))
152 		return -1;
153 
154 	if (translating && !lr->ctx_trans &&
155 	    selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans))
156 		return -1;
157 
158 	return 0;
159 }
160 
161 static struct selabel_lookup_rec *
selabel_lookup_common(struct selabel_handle * rec,bool translating,const char * key,int type)162 selabel_lookup_common(struct selabel_handle *rec, bool translating,
163 		      const char *key, int type)
164 {
165 	struct selabel_lookup_rec *lr;
166 
167 	if (key == NULL) {
168 		errno = EINVAL;
169 		return NULL;
170 	}
171 
172 	lr = rec->func_lookup(rec, key, type);
173 	if (!lr)
174 		return NULL;
175 
176 	if (selabel_fini(rec, lr, translating))
177 		return NULL;
178 
179 	return lr;
180 }
181 
182 static struct selabel_lookup_rec *
selabel_lookup_bm_common(struct selabel_handle * rec,bool translating,const char * key,int type,const char ** aliases)183 selabel_lookup_bm_common(struct selabel_handle *rec, bool translating,
184 		      const char *key, int type, const char **aliases)
185 {
186 	struct selabel_lookup_rec *lr;
187 
188 	if (key == NULL) {
189 		errno = EINVAL;
190 		return NULL;
191 	}
192 
193 	lr = rec->func_lookup_best_match(rec, key, aliases, type);
194 	if (!lr)
195 		return NULL;
196 
197 	if (selabel_fini(rec, lr, translating))
198 		return NULL;
199 
200 	return lr;
201 }
202 
203 /*
204  * Public API
205  */
206 
selabel_open(unsigned int backend,const struct selinux_opt * opts,unsigned nopts)207 struct selabel_handle *selabel_open(unsigned int backend,
208 				    const struct selinux_opt *opts,
209 				    unsigned nopts)
210 {
211 	struct selabel_handle *rec = NULL;
212 
213 	if (backend >= ARRAY_SIZE(initfuncs)) {
214 		errno = EINVAL;
215 		goto out;
216 	}
217 
218 	if (!initfuncs[backend]) {
219 		errno = ENOTSUP;
220 		goto out;
221 	}
222 
223 	rec = (struct selabel_handle *)calloc(1, sizeof(*rec));
224 	if (!rec)
225 		goto out;
226 
227 	rec->backend = backend;
228 	rec->validating = selabel_is_validate_set(opts, nopts);
229 
230 	rec->digest = selabel_is_digest_set(opts, nopts);
231 
232 	if ((*initfuncs[backend])(rec, opts, nopts)) {
233 		selabel_close(rec);
234 		rec = NULL;
235 	}
236 out:
237 	return rec;
238 }
239 
selabel_lookup(struct selabel_handle * rec,char ** con,const char * key,int type)240 int selabel_lookup(struct selabel_handle *rec, char **con,
241 		   const char *key, int type)
242 {
243 	struct selabel_lookup_rec *lr;
244 
245 	lr = selabel_lookup_common(rec, true, key, type);
246 	if (!lr)
247 		return -1;
248 
249 	*con = strdup(lr->ctx_trans);
250 	return *con ? 0 : -1;
251 }
252 
selabel_lookup_raw(struct selabel_handle * rec,char ** con,const char * key,int type)253 int selabel_lookup_raw(struct selabel_handle *rec, char **con,
254 		       const char *key, int type)
255 {
256 	struct selabel_lookup_rec *lr;
257 
258 	lr = selabel_lookup_common(rec, false, key, type);
259 	if (!lr)
260 		return -1;
261 
262 	*con = strdup(lr->ctx_raw);
263 	return *con ? 0 : -1;
264 }
265 
selabel_partial_match(struct selabel_handle * rec,const char * key)266 bool selabel_partial_match(struct selabel_handle *rec, const char *key)
267 {
268 	if (!rec->func_partial_match) {
269 		/*
270 		 * If the label backend does not support partial matching,
271 		 * then assume a match is possible.
272 		 */
273 		return true;
274 	}
275 
276 	return rec->func_partial_match(rec, key);
277 }
278 
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)279 bool selabel_get_digests_all_partial_matches(struct selabel_handle *rec,
280 					     const char *key,
281 					     uint8_t **calculated_digest,
282 					     uint8_t **xattr_digest,
283 					     size_t *digest_len)
284 {
285 	if (!rec->func_get_digests_all_partial_matches)
286 		return false;
287 
288 	return rec->func_get_digests_all_partial_matches(rec, key,
289 							 calculated_digest,
290 							 xattr_digest,
291 							 digest_len);
292 }
293 
selabel_hash_all_partial_matches(struct selabel_handle * rec,const char * key,uint8_t * digest)294 bool selabel_hash_all_partial_matches(struct selabel_handle *rec,
295                                       const char *key, uint8_t *digest) {
296 	if (!rec->func_hash_all_partial_matches) {
297 		return false;
298 	}
299 
300 	return rec->func_hash_all_partial_matches(rec, key, digest);
301 }
302 
selabel_lookup_best_match(struct selabel_handle * rec,char ** con,const char * key,const char ** aliases,int type)303 int selabel_lookup_best_match(struct selabel_handle *rec, char **con,
304 			      const char *key, const char **aliases, int type)
305 {
306 	struct selabel_lookup_rec *lr;
307 
308 	if (!rec->func_lookup_best_match) {
309 		errno = ENOTSUP;
310 		return -1;
311 	}
312 
313 	lr = selabel_lookup_bm_common(rec, true, key, type, aliases);
314 	if (!lr)
315 		return -1;
316 
317 	*con = strdup(lr->ctx_trans);
318 	return *con ? 0 : -1;
319 }
320 
selabel_lookup_best_match_raw(struct selabel_handle * rec,char ** con,const char * key,const char ** aliases,int type)321 int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con,
322 			      const char *key, const char **aliases, int type)
323 {
324 	struct selabel_lookup_rec *lr;
325 
326 	if (!rec->func_lookup_best_match) {
327 		errno = ENOTSUP;
328 		return -1;
329 	}
330 
331 	lr = selabel_lookup_bm_common(rec, false, key, type, aliases);
332 	if (!lr)
333 		return -1;
334 
335 	*con = strdup(lr->ctx_raw);
336 	return *con ? 0 : -1;
337 }
338 
selabel_cmp(const struct selabel_handle * h1,const struct selabel_handle * h2)339 enum selabel_cmp_result selabel_cmp(const struct selabel_handle *h1,
340 				    const struct selabel_handle *h2)
341 {
342 	if (!h1->func_cmp || h1->func_cmp != h2->func_cmp)
343 		return SELABEL_INCOMPARABLE;
344 
345 	return h1->func_cmp(h1, h2);
346 }
347 
selabel_digest(struct selabel_handle * rec,unsigned char ** digest,size_t * digest_len,char *** specfiles,size_t * num_specfiles)348 int selabel_digest(struct selabel_handle *rec,
349 				    unsigned char **digest, size_t *digest_len,
350 				    char ***specfiles, size_t *num_specfiles)
351 {
352 	if (!rec->digest) {
353 		errno = EINVAL;
354 		return -1;
355 	}
356 
357 	*digest = rec->digest->digest;
358 	*digest_len = DIGEST_SPECFILE_SIZE;
359 	*specfiles = rec->digest->specfile_list;
360 	*num_specfiles = rec->digest->specfile_cnt;
361 	return 0;
362 }
363 
selabel_close(struct selabel_handle * rec)364 void selabel_close(struct selabel_handle *rec)
365 {
366 	size_t i;
367 
368 	if (rec->spec_files) {
369 		for (i = 0; i < rec->spec_files_len; i++)
370 			free(rec->spec_files[i]);
371 		free(rec->spec_files);
372 	}
373 	if (rec->digest)
374 		selabel_digest_fini(rec->digest);
375 	if (rec->func_close)
376 		rec->func_close(rec);
377 	free(rec);
378 }
379 
selabel_stats(struct selabel_handle * rec)380 void selabel_stats(struct selabel_handle *rec)
381 {
382 	rec->func_stats(rec);
383 }
384