xref: /third_party/selinux/libselinux/src/label.c (revision 6cd6a6ac)
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
44typedef int (*selabel_initfunc)(struct selabel_handle *rec,
45				const struct selinux_opt *opts,
46				unsigned nopts);
47
48static 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
57static 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
86err:
87	if (digest) {
88		free(digest->digest);
89		free(digest->specfile_list);
90		free(digest);
91	}
92	return NULL;
93}
94
95static 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
114static 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
124int 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;
137out:
138	return rc;
139}
140
141/* Public API helpers */
142static 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
165static struct selabel_lookup_rec *
166selabel_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
186static struct selabel_lookup_rec *
187selabel_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
208static 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
225struct 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
263out:
264	return rec;
265}
266
267int 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
280int 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
293bool 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
306bool 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
321bool 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
330int 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
348int 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
366enum 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
375int 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
391void 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
404void selabel_stats(struct selabel_handle *rec)
405{
406	rec->func_stats(rec);
407}
408