xref: /aosp_15_r20/external/selinux/libselinux/src/label_file.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1*2d543d20SAndroid Build Coastguard Worker /*
2*2d543d20SAndroid Build Coastguard Worker  * File contexts backend for labeling system
3*2d543d20SAndroid Build Coastguard Worker  *
4*2d543d20SAndroid Build Coastguard Worker  * Author : Eamon Walsh <[email protected]>
5*2d543d20SAndroid Build Coastguard Worker  * Author : Stephen Smalley <[email protected]>
6*2d543d20SAndroid Build Coastguard Worker  */
7*2d543d20SAndroid Build Coastguard Worker 
8*2d543d20SAndroid Build Coastguard Worker #include <assert.h>
9*2d543d20SAndroid Build Coastguard Worker #include <fcntl.h>
10*2d543d20SAndroid Build Coastguard Worker #include <stdarg.h>
11*2d543d20SAndroid Build Coastguard Worker #include <string.h>
12*2d543d20SAndroid Build Coastguard Worker #include <stdio.h>
13*2d543d20SAndroid Build Coastguard Worker #include <ctype.h>
14*2d543d20SAndroid Build Coastguard Worker #include <errno.h>
15*2d543d20SAndroid Build Coastguard Worker #include <limits.h>
16*2d543d20SAndroid Build Coastguard Worker #include <stdint.h>
17*2d543d20SAndroid Build Coastguard Worker #include <unistd.h>
18*2d543d20SAndroid Build Coastguard Worker #include <sys/mman.h>
19*2d543d20SAndroid Build Coastguard Worker #include <sys/types.h>
20*2d543d20SAndroid Build Coastguard Worker #include <sys/stat.h>
21*2d543d20SAndroid Build Coastguard Worker 
22*2d543d20SAndroid Build Coastguard Worker #include "hashtab.h"
23*2d543d20SAndroid Build Coastguard Worker #include "callbacks.h"
24*2d543d20SAndroid Build Coastguard Worker #include "label_internal.h"
25*2d543d20SAndroid Build Coastguard Worker #include "label_file.h"
26*2d543d20SAndroid Build Coastguard Worker 
27*2d543d20SAndroid Build Coastguard Worker /* controls the shrink multiple of the hashtab length */
28*2d543d20SAndroid Build Coastguard Worker #define SHRINK_MULTIS 1
29*2d543d20SAndroid Build Coastguard Worker 
30*2d543d20SAndroid Build Coastguard Worker struct chkdups_key {
31*2d543d20SAndroid Build Coastguard Worker 	char *regex;
32*2d543d20SAndroid Build Coastguard Worker 	unsigned int mode;
33*2d543d20SAndroid Build Coastguard Worker };
34*2d543d20SAndroid Build Coastguard Worker 
35*2d543d20SAndroid Build Coastguard Worker /*
36*2d543d20SAndroid Build Coastguard Worker  * Internals, mostly moved over from matchpathcon.c
37*2d543d20SAndroid Build Coastguard Worker  */
38*2d543d20SAndroid Build Coastguard Worker 
39*2d543d20SAndroid Build Coastguard Worker /* return the length of the text that is the stem of a file name */
get_stem_from_file_name(const char * const buf)40*2d543d20SAndroid Build Coastguard Worker static int get_stem_from_file_name(const char *const buf)
41*2d543d20SAndroid Build Coastguard Worker {
42*2d543d20SAndroid Build Coastguard Worker 	const char *tmp = strchr(buf + 1, '/');
43*2d543d20SAndroid Build Coastguard Worker 
44*2d543d20SAndroid Build Coastguard Worker 	if (!tmp)
45*2d543d20SAndroid Build Coastguard Worker 		return 0;
46*2d543d20SAndroid Build Coastguard Worker 	return tmp - buf;
47*2d543d20SAndroid Build Coastguard Worker }
48*2d543d20SAndroid Build Coastguard Worker 
49*2d543d20SAndroid Build Coastguard Worker /* find the stem of a file name, returns the index into stem_arr (or -1 if
50*2d543d20SAndroid Build Coastguard Worker  * there is no match - IE for a file in the root directory or a regex that is
51*2d543d20SAndroid Build Coastguard Worker  * too complex for us). */
find_stem_from_file(struct saved_data * data,const char * key)52*2d543d20SAndroid Build Coastguard Worker static int find_stem_from_file(struct saved_data *data, const char *key)
53*2d543d20SAndroid Build Coastguard Worker {
54*2d543d20SAndroid Build Coastguard Worker 	int i;
55*2d543d20SAndroid Build Coastguard Worker 	int stem_len = get_stem_from_file_name(key);
56*2d543d20SAndroid Build Coastguard Worker 
57*2d543d20SAndroid Build Coastguard Worker 	if (!stem_len)
58*2d543d20SAndroid Build Coastguard Worker 		return -1;
59*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < data->num_stems; i++) {
60*2d543d20SAndroid Build Coastguard Worker 		if (stem_len == data->stem_arr[i].len
61*2d543d20SAndroid Build Coastguard Worker 		    && !strncmp(key, data->stem_arr[i].buf, stem_len)) {
62*2d543d20SAndroid Build Coastguard Worker 			return i;
63*2d543d20SAndroid Build Coastguard Worker 		}
64*2d543d20SAndroid Build Coastguard Worker 	}
65*2d543d20SAndroid Build Coastguard Worker 	return -1;
66*2d543d20SAndroid Build Coastguard Worker }
67*2d543d20SAndroid Build Coastguard Worker 
68*2d543d20SAndroid Build Coastguard Worker /*
69*2d543d20SAndroid Build Coastguard Worker  * hash calculation and key comparison of hash table
70*2d543d20SAndroid Build Coastguard Worker  */
71*2d543d20SAndroid Build Coastguard Worker ignore_unsigned_overflow_
symhash(hashtab_t h,const_hashtab_key_t key)72*2d543d20SAndroid Build Coastguard Worker static unsigned int symhash(hashtab_t h, const_hashtab_key_t key)
73*2d543d20SAndroid Build Coastguard Worker {
74*2d543d20SAndroid Build Coastguard Worker 	const struct chkdups_key *k = (const struct chkdups_key *)key;
75*2d543d20SAndroid Build Coastguard Worker 	const char *p = NULL;
76*2d543d20SAndroid Build Coastguard Worker 	size_t size;
77*2d543d20SAndroid Build Coastguard Worker 	unsigned int val = 0;
78*2d543d20SAndroid Build Coastguard Worker 
79*2d543d20SAndroid Build Coastguard Worker 	size = strlen(k->regex);
80*2d543d20SAndroid Build Coastguard Worker 	for (p = k->regex; ((size_t) (p - k->regex)) < size; p++)
81*2d543d20SAndroid Build Coastguard Worker 		val =
82*2d543d20SAndroid Build Coastguard Worker 			((val << 4) | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p);
83*2d543d20SAndroid Build Coastguard Worker 	return val % h->size;
84*2d543d20SAndroid Build Coastguard Worker }
85*2d543d20SAndroid Build Coastguard Worker 
symcmp(hashtab_t h,const_hashtab_key_t key1,const_hashtab_key_t key2)86*2d543d20SAndroid Build Coastguard Worker static int symcmp(hashtab_t h
87*2d543d20SAndroid Build Coastguard Worker 		  __attribute__ ((unused)), const_hashtab_key_t key1,
88*2d543d20SAndroid Build Coastguard Worker 		  const_hashtab_key_t key2)
89*2d543d20SAndroid Build Coastguard Worker {
90*2d543d20SAndroid Build Coastguard Worker 	const struct chkdups_key *a = (const struct chkdups_key *)key1;
91*2d543d20SAndroid Build Coastguard Worker 	const struct chkdups_key *b = (const struct chkdups_key *)key2;
92*2d543d20SAndroid Build Coastguard Worker 
93*2d543d20SAndroid Build Coastguard Worker 	return strcmp(a->regex, b->regex) || (a->mode && b->mode && a->mode != b->mode);
94*2d543d20SAndroid Build Coastguard Worker }
95*2d543d20SAndroid Build Coastguard Worker 
destroy_chkdups_key(hashtab_key_t key)96*2d543d20SAndroid Build Coastguard Worker static int destroy_chkdups_key(hashtab_key_t key)
97*2d543d20SAndroid Build Coastguard Worker {
98*2d543d20SAndroid Build Coastguard Worker 	free(key);
99*2d543d20SAndroid Build Coastguard Worker 
100*2d543d20SAndroid Build Coastguard Worker 	return 0;
101*2d543d20SAndroid Build Coastguard Worker }
102*2d543d20SAndroid Build Coastguard Worker 
103*2d543d20SAndroid Build Coastguard Worker /*
104*2d543d20SAndroid Build Coastguard Worker  * Warn about duplicate specifications.
105*2d543d20SAndroid Build Coastguard Worker  */
nodups_specs(struct saved_data * data,const char * path)106*2d543d20SAndroid Build Coastguard Worker static int nodups_specs(struct saved_data *data, const char *path)
107*2d543d20SAndroid Build Coastguard Worker {
108*2d543d20SAndroid Build Coastguard Worker 	int rc = 0, ret = 0;
109*2d543d20SAndroid Build Coastguard Worker 	unsigned int ii;
110*2d543d20SAndroid Build Coastguard Worker 	struct spec *curr_spec, *spec_arr = data->spec_arr;
111*2d543d20SAndroid Build Coastguard Worker 	struct chkdups_key *new = NULL;
112*2d543d20SAndroid Build Coastguard Worker 	unsigned int hashtab_len = (data->nspec / SHRINK_MULTIS) ? data->nspec / SHRINK_MULTIS : 1;
113*2d543d20SAndroid Build Coastguard Worker 
114*2d543d20SAndroid Build Coastguard Worker 	hashtab_t hash_table = selinux_hashtab_create(symhash, symcmp, hashtab_len);
115*2d543d20SAndroid Build Coastguard Worker 	if (!hash_table) {
116*2d543d20SAndroid Build Coastguard Worker 		rc = -1;
117*2d543d20SAndroid Build Coastguard Worker 		COMPAT_LOG(SELINUX_ERROR, "%s: hashtab create failed.\n", path);
118*2d543d20SAndroid Build Coastguard Worker 		return rc;
119*2d543d20SAndroid Build Coastguard Worker 	}
120*2d543d20SAndroid Build Coastguard Worker 	for (ii = 0; ii < data->nspec; ii++) {
121*2d543d20SAndroid Build Coastguard Worker 		new = (struct chkdups_key *)malloc(sizeof(struct chkdups_key));
122*2d543d20SAndroid Build Coastguard Worker 		if (!new) {
123*2d543d20SAndroid Build Coastguard Worker 			rc = -1;
124*2d543d20SAndroid Build Coastguard Worker 			selinux_hashtab_destroy_key(hash_table, destroy_chkdups_key);
125*2d543d20SAndroid Build Coastguard Worker 			COMPAT_LOG(SELINUX_ERROR, "%s: hashtab key create failed.\n", path);
126*2d543d20SAndroid Build Coastguard Worker 			return rc;
127*2d543d20SAndroid Build Coastguard Worker 		}
128*2d543d20SAndroid Build Coastguard Worker 		new->regex = spec_arr[ii].regex_str;
129*2d543d20SAndroid Build Coastguard Worker 		new->mode = spec_arr[ii].mode;
130*2d543d20SAndroid Build Coastguard Worker 		ret = selinux_hashtab_insert(hash_table, (hashtab_key_t)new, &spec_arr[ii]);
131*2d543d20SAndroid Build Coastguard Worker 		if (ret == HASHTAB_SUCCESS)
132*2d543d20SAndroid Build Coastguard Worker 			continue;
133*2d543d20SAndroid Build Coastguard Worker 		if (ret == HASHTAB_PRESENT) {
134*2d543d20SAndroid Build Coastguard Worker 			curr_spec =
135*2d543d20SAndroid Build Coastguard Worker 				(struct spec *)selinux_hashtab_search(hash_table, (hashtab_key_t)new);
136*2d543d20SAndroid Build Coastguard Worker 			rc = -1;
137*2d543d20SAndroid Build Coastguard Worker 			errno = EINVAL;
138*2d543d20SAndroid Build Coastguard Worker 			free(new);
139*2d543d20SAndroid Build Coastguard Worker 			if (strcmp(spec_arr[ii].lr.ctx_raw, curr_spec->lr.ctx_raw)) {
140*2d543d20SAndroid Build Coastguard Worker 				COMPAT_LOG
141*2d543d20SAndroid Build Coastguard Worker 					(SELINUX_ERROR,
142*2d543d20SAndroid Build Coastguard Worker 					 "%s: Multiple different specifications for %s  (%s and %s).\n",
143*2d543d20SAndroid Build Coastguard Worker 					 path, curr_spec->regex_str,
144*2d543d20SAndroid Build Coastguard Worker 					 spec_arr[ii].lr.ctx_raw,
145*2d543d20SAndroid Build Coastguard Worker 					 curr_spec->lr.ctx_raw);
146*2d543d20SAndroid Build Coastguard Worker 			} else {
147*2d543d20SAndroid Build Coastguard Worker 				COMPAT_LOG
148*2d543d20SAndroid Build Coastguard Worker 					(SELINUX_ERROR,
149*2d543d20SAndroid Build Coastguard Worker 					 "%s: Multiple same specifications for %s.\n",
150*2d543d20SAndroid Build Coastguard Worker 					 path, curr_spec->regex_str);
151*2d543d20SAndroid Build Coastguard Worker 			}
152*2d543d20SAndroid Build Coastguard Worker 		}
153*2d543d20SAndroid Build Coastguard Worker 		if (ret == HASHTAB_OVERFLOW) {
154*2d543d20SAndroid Build Coastguard Worker 			rc = -1;
155*2d543d20SAndroid Build Coastguard Worker 			free(new);
156*2d543d20SAndroid Build Coastguard Worker 			COMPAT_LOG
157*2d543d20SAndroid Build Coastguard Worker 				(SELINUX_ERROR,
158*2d543d20SAndroid Build Coastguard Worker 				"%s: hashtab happen memory error.\n",
159*2d543d20SAndroid Build Coastguard Worker 				path);
160*2d543d20SAndroid Build Coastguard Worker 			break;
161*2d543d20SAndroid Build Coastguard Worker 		}
162*2d543d20SAndroid Build Coastguard Worker 	}
163*2d543d20SAndroid Build Coastguard Worker 
164*2d543d20SAndroid Build Coastguard Worker 	selinux_hashtab_destroy_key(hash_table, destroy_chkdups_key);
165*2d543d20SAndroid Build Coastguard Worker 
166*2d543d20SAndroid Build Coastguard Worker 	return rc;
167*2d543d20SAndroid Build Coastguard Worker }
168*2d543d20SAndroid Build Coastguard Worker 
process_text_file(FILE * fp,const char * prefix,struct selabel_handle * rec,const char * path)169*2d543d20SAndroid Build Coastguard Worker static int process_text_file(FILE *fp, const char *prefix,
170*2d543d20SAndroid Build Coastguard Worker 			     struct selabel_handle *rec, const char *path)
171*2d543d20SAndroid Build Coastguard Worker {
172*2d543d20SAndroid Build Coastguard Worker 	int rc;
173*2d543d20SAndroid Build Coastguard Worker 	size_t line_len;
174*2d543d20SAndroid Build Coastguard Worker 	unsigned int lineno = 0;
175*2d543d20SAndroid Build Coastguard Worker 	char *line_buf = NULL;
176*2d543d20SAndroid Build Coastguard Worker 
177*2d543d20SAndroid Build Coastguard Worker 	while (getline(&line_buf, &line_len, fp) > 0) {
178*2d543d20SAndroid Build Coastguard Worker 		rc = process_line(rec, path, prefix, line_buf, ++lineno);
179*2d543d20SAndroid Build Coastguard Worker 		if (rc)
180*2d543d20SAndroid Build Coastguard Worker 			goto out;
181*2d543d20SAndroid Build Coastguard Worker 	}
182*2d543d20SAndroid Build Coastguard Worker 	rc = 0;
183*2d543d20SAndroid Build Coastguard Worker out:
184*2d543d20SAndroid Build Coastguard Worker 	free(line_buf);
185*2d543d20SAndroid Build Coastguard Worker 	return rc;
186*2d543d20SAndroid Build Coastguard Worker }
187*2d543d20SAndroid Build Coastguard Worker 
load_mmap(FILE * fp,size_t len,struct selabel_handle * rec,const char * path)188*2d543d20SAndroid Build Coastguard Worker static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec,
189*2d543d20SAndroid Build Coastguard Worker 		     const char *path)
190*2d543d20SAndroid Build Coastguard Worker {
191*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data = (struct saved_data *)rec->data;
192*2d543d20SAndroid Build Coastguard Worker 	int rc;
193*2d543d20SAndroid Build Coastguard Worker 	char *addr, *str_buf;
194*2d543d20SAndroid Build Coastguard Worker 	int *stem_map;
195*2d543d20SAndroid Build Coastguard Worker 	struct mmap_area *mmap_area;
196*2d543d20SAndroid Build Coastguard Worker 	uint32_t i, magic, version;
197*2d543d20SAndroid Build Coastguard Worker 	uint32_t entry_len, stem_map_len, regex_array_len;
198*2d543d20SAndroid Build Coastguard Worker 	const char *reg_version;
199*2d543d20SAndroid Build Coastguard Worker 	const char *reg_arch;
200*2d543d20SAndroid Build Coastguard Worker 	char reg_arch_matches = 0;
201*2d543d20SAndroid Build Coastguard Worker 
202*2d543d20SAndroid Build Coastguard Worker 	mmap_area = malloc(sizeof(*mmap_area));
203*2d543d20SAndroid Build Coastguard Worker 	if (!mmap_area) {
204*2d543d20SAndroid Build Coastguard Worker 		return -1;
205*2d543d20SAndroid Build Coastguard Worker 	}
206*2d543d20SAndroid Build Coastguard Worker 
207*2d543d20SAndroid Build Coastguard Worker 	addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fileno(fp), 0);
208*2d543d20SAndroid Build Coastguard Worker 	if (addr == MAP_FAILED) {
209*2d543d20SAndroid Build Coastguard Worker 		free(mmap_area);
210*2d543d20SAndroid Build Coastguard Worker 		perror("mmap");
211*2d543d20SAndroid Build Coastguard Worker 		return -1;
212*2d543d20SAndroid Build Coastguard Worker 	}
213*2d543d20SAndroid Build Coastguard Worker 
214*2d543d20SAndroid Build Coastguard Worker 	/* save where we mmap'd the file to cleanup on close() */
215*2d543d20SAndroid Build Coastguard Worker 	mmap_area->addr = mmap_area->next_addr = addr;
216*2d543d20SAndroid Build Coastguard Worker 	mmap_area->len = mmap_area->next_len = len;
217*2d543d20SAndroid Build Coastguard Worker 	mmap_area->next = data->mmap_areas;
218*2d543d20SAndroid Build Coastguard Worker 	data->mmap_areas = mmap_area;
219*2d543d20SAndroid Build Coastguard Worker 
220*2d543d20SAndroid Build Coastguard Worker 	/* check if this looks like an fcontext file */
221*2d543d20SAndroid Build Coastguard Worker 	rc = next_entry(&magic, mmap_area, sizeof(uint32_t));
222*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0 || magic != SELINUX_MAGIC_COMPILED_FCONTEXT)
223*2d543d20SAndroid Build Coastguard Worker 		return -1;
224*2d543d20SAndroid Build Coastguard Worker 
225*2d543d20SAndroid Build Coastguard Worker 	/* check if this version is higher than we understand */
226*2d543d20SAndroid Build Coastguard Worker 	rc = next_entry(&version, mmap_area, sizeof(uint32_t));
227*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0 || version > SELINUX_COMPILED_FCONTEXT_MAX_VERS)
228*2d543d20SAndroid Build Coastguard Worker 		return -1;
229*2d543d20SAndroid Build Coastguard Worker 
230*2d543d20SAndroid Build Coastguard Worker 	reg_version = regex_version();
231*2d543d20SAndroid Build Coastguard Worker 	if (!reg_version)
232*2d543d20SAndroid Build Coastguard Worker 		return -1;
233*2d543d20SAndroid Build Coastguard Worker 
234*2d543d20SAndroid Build Coastguard Worker 	reg_arch = regex_arch_string();
235*2d543d20SAndroid Build Coastguard Worker 	if (!reg_arch)
236*2d543d20SAndroid Build Coastguard Worker 		return -1;
237*2d543d20SAndroid Build Coastguard Worker 
238*2d543d20SAndroid Build Coastguard Worker 	if (version >= SELINUX_COMPILED_FCONTEXT_PCRE_VERS) {
239*2d543d20SAndroid Build Coastguard Worker 
240*2d543d20SAndroid Build Coastguard Worker 		len = strlen(reg_version);
241*2d543d20SAndroid Build Coastguard Worker 
242*2d543d20SAndroid Build Coastguard Worker 		rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
243*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0)
244*2d543d20SAndroid Build Coastguard Worker 			return -1;
245*2d543d20SAndroid Build Coastguard Worker 
246*2d543d20SAndroid Build Coastguard Worker 		/* Check version lengths */
247*2d543d20SAndroid Build Coastguard Worker 		if (len != entry_len)
248*2d543d20SAndroid Build Coastguard Worker 			return -1;
249*2d543d20SAndroid Build Coastguard Worker 
250*2d543d20SAndroid Build Coastguard Worker 		/* Check if regex version mismatch */
251*2d543d20SAndroid Build Coastguard Worker 		str_buf = malloc(entry_len + 1);
252*2d543d20SAndroid Build Coastguard Worker 		if (!str_buf)
253*2d543d20SAndroid Build Coastguard Worker 			return -1;
254*2d543d20SAndroid Build Coastguard Worker 
255*2d543d20SAndroid Build Coastguard Worker 		rc = next_entry(str_buf, mmap_area, entry_len);
256*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0) {
257*2d543d20SAndroid Build Coastguard Worker 			free(str_buf);
258*2d543d20SAndroid Build Coastguard Worker 			return -1;
259*2d543d20SAndroid Build Coastguard Worker 		}
260*2d543d20SAndroid Build Coastguard Worker 
261*2d543d20SAndroid Build Coastguard Worker 		str_buf[entry_len] = '\0';
262*2d543d20SAndroid Build Coastguard Worker 		if ((strcmp(str_buf, reg_version) != 0)) {
263*2d543d20SAndroid Build Coastguard Worker 			COMPAT_LOG(SELINUX_ERROR,
264*2d543d20SAndroid Build Coastguard Worker 				"Regex version mismatch, expected: %s actual: %s\n",
265*2d543d20SAndroid Build Coastguard Worker 				reg_version, str_buf);
266*2d543d20SAndroid Build Coastguard Worker 			free(str_buf);
267*2d543d20SAndroid Build Coastguard Worker 			return -1;
268*2d543d20SAndroid Build Coastguard Worker 		}
269*2d543d20SAndroid Build Coastguard Worker 		free(str_buf);
270*2d543d20SAndroid Build Coastguard Worker 
271*2d543d20SAndroid Build Coastguard Worker 		if (version >= SELINUX_COMPILED_FCONTEXT_REGEX_ARCH) {
272*2d543d20SAndroid Build Coastguard Worker 			len = strlen(reg_arch);
273*2d543d20SAndroid Build Coastguard Worker 
274*2d543d20SAndroid Build Coastguard Worker 			rc = next_entry(&entry_len, mmap_area,
275*2d543d20SAndroid Build Coastguard Worker 					sizeof(uint32_t));
276*2d543d20SAndroid Build Coastguard Worker 			if (rc < 0)
277*2d543d20SAndroid Build Coastguard Worker 				return -1;
278*2d543d20SAndroid Build Coastguard Worker 
279*2d543d20SAndroid Build Coastguard Worker 			/* Check arch string lengths */
280*2d543d20SAndroid Build Coastguard Worker 			if (len != entry_len) {
281*2d543d20SAndroid Build Coastguard Worker 				/*
282*2d543d20SAndroid Build Coastguard Worker 				 * Skip the entry and conclude that we have
283*2d543d20SAndroid Build Coastguard Worker 				 * a mismatch, which is not fatal.
284*2d543d20SAndroid Build Coastguard Worker 				 */
285*2d543d20SAndroid Build Coastguard Worker 				next_entry(NULL, mmap_area, entry_len);
286*2d543d20SAndroid Build Coastguard Worker 				goto end_arch_check;
287*2d543d20SAndroid Build Coastguard Worker 			}
288*2d543d20SAndroid Build Coastguard Worker 
289*2d543d20SAndroid Build Coastguard Worker 			/* Check if arch string mismatch */
290*2d543d20SAndroid Build Coastguard Worker 			str_buf = malloc(entry_len + 1);
291*2d543d20SAndroid Build Coastguard Worker 			if (!str_buf)
292*2d543d20SAndroid Build Coastguard Worker 				return -1;
293*2d543d20SAndroid Build Coastguard Worker 
294*2d543d20SAndroid Build Coastguard Worker 			rc = next_entry(str_buf, mmap_area, entry_len);
295*2d543d20SAndroid Build Coastguard Worker 			if (rc < 0) {
296*2d543d20SAndroid Build Coastguard Worker 				free(str_buf);
297*2d543d20SAndroid Build Coastguard Worker 				return -1;
298*2d543d20SAndroid Build Coastguard Worker 			}
299*2d543d20SAndroid Build Coastguard Worker 
300*2d543d20SAndroid Build Coastguard Worker 			str_buf[entry_len] = '\0';
301*2d543d20SAndroid Build Coastguard Worker 			reg_arch_matches = strcmp(str_buf, reg_arch) == 0;
302*2d543d20SAndroid Build Coastguard Worker 			free(str_buf);
303*2d543d20SAndroid Build Coastguard Worker 		}
304*2d543d20SAndroid Build Coastguard Worker 	}
305*2d543d20SAndroid Build Coastguard Worker end_arch_check:
306*2d543d20SAndroid Build Coastguard Worker 
307*2d543d20SAndroid Build Coastguard Worker 	/* allocate the stems_data array */
308*2d543d20SAndroid Build Coastguard Worker 	rc = next_entry(&stem_map_len, mmap_area, sizeof(uint32_t));
309*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0)
310*2d543d20SAndroid Build Coastguard Worker 		return -1;
311*2d543d20SAndroid Build Coastguard Worker 
312*2d543d20SAndroid Build Coastguard Worker 	/*
313*2d543d20SAndroid Build Coastguard Worker 	 * map indexed by the stem # in the mmap file and contains the stem
314*2d543d20SAndroid Build Coastguard Worker 	 * number in the data stem_arr
315*2d543d20SAndroid Build Coastguard Worker 	 */
316*2d543d20SAndroid Build Coastguard Worker 	stem_map = calloc(stem_map_len, sizeof(*stem_map));
317*2d543d20SAndroid Build Coastguard Worker 	if (!stem_map)
318*2d543d20SAndroid Build Coastguard Worker 		return -1;
319*2d543d20SAndroid Build Coastguard Worker 
320*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < stem_map_len; i++) {
321*2d543d20SAndroid Build Coastguard Worker 		char *buf;
322*2d543d20SAndroid Build Coastguard Worker 		uint32_t stem_len;
323*2d543d20SAndroid Build Coastguard Worker 		int newid;
324*2d543d20SAndroid Build Coastguard Worker 
325*2d543d20SAndroid Build Coastguard Worker 		/* the length does not include the nul */
326*2d543d20SAndroid Build Coastguard Worker 		rc = next_entry(&stem_len, mmap_area, sizeof(uint32_t));
327*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0 || !stem_len) {
328*2d543d20SAndroid Build Coastguard Worker 			rc = -1;
329*2d543d20SAndroid Build Coastguard Worker 			goto out;
330*2d543d20SAndroid Build Coastguard Worker 		}
331*2d543d20SAndroid Build Coastguard Worker 
332*2d543d20SAndroid Build Coastguard Worker 		/* Check for stem_len wrap around. */
333*2d543d20SAndroid Build Coastguard Worker 		if (stem_len < UINT32_MAX) {
334*2d543d20SAndroid Build Coastguard Worker 			buf = (char *)mmap_area->next_addr;
335*2d543d20SAndroid Build Coastguard Worker 			/* Check if over-run before null check. */
336*2d543d20SAndroid Build Coastguard Worker 			rc = next_entry(NULL, mmap_area, (stem_len + 1));
337*2d543d20SAndroid Build Coastguard Worker 			if (rc < 0)
338*2d543d20SAndroid Build Coastguard Worker 				goto out;
339*2d543d20SAndroid Build Coastguard Worker 
340*2d543d20SAndroid Build Coastguard Worker 			if (buf[stem_len] != '\0') {
341*2d543d20SAndroid Build Coastguard Worker 				rc = -1;
342*2d543d20SAndroid Build Coastguard Worker 				goto out;
343*2d543d20SAndroid Build Coastguard Worker 			}
344*2d543d20SAndroid Build Coastguard Worker 		} else {
345*2d543d20SAndroid Build Coastguard Worker 			rc = -1;
346*2d543d20SAndroid Build Coastguard Worker 			goto out;
347*2d543d20SAndroid Build Coastguard Worker 		}
348*2d543d20SAndroid Build Coastguard Worker 
349*2d543d20SAndroid Build Coastguard Worker 		/* store the mapping between old and new */
350*2d543d20SAndroid Build Coastguard Worker 		newid = find_stem(data, buf, stem_len);
351*2d543d20SAndroid Build Coastguard Worker 		if (newid < 0) {
352*2d543d20SAndroid Build Coastguard Worker 			newid = store_stem(data, buf, stem_len);
353*2d543d20SAndroid Build Coastguard Worker 			if (newid < 0) {
354*2d543d20SAndroid Build Coastguard Worker 				rc = newid;
355*2d543d20SAndroid Build Coastguard Worker 				goto out;
356*2d543d20SAndroid Build Coastguard Worker 			}
357*2d543d20SAndroid Build Coastguard Worker 			data->stem_arr[newid].from_mmap = 1;
358*2d543d20SAndroid Build Coastguard Worker 		}
359*2d543d20SAndroid Build Coastguard Worker 		stem_map[i] = newid;
360*2d543d20SAndroid Build Coastguard Worker 	}
361*2d543d20SAndroid Build Coastguard Worker 
362*2d543d20SAndroid Build Coastguard Worker 	/* allocate the regex array */
363*2d543d20SAndroid Build Coastguard Worker 	rc = next_entry(&regex_array_len, mmap_area, sizeof(uint32_t));
364*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0 || !regex_array_len) {
365*2d543d20SAndroid Build Coastguard Worker 		rc = -1;
366*2d543d20SAndroid Build Coastguard Worker 		goto out;
367*2d543d20SAndroid Build Coastguard Worker 	}
368*2d543d20SAndroid Build Coastguard Worker 
369*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < regex_array_len; i++) {
370*2d543d20SAndroid Build Coastguard Worker 		struct spec *spec;
371*2d543d20SAndroid Build Coastguard Worker 		int32_t stem_id, meta_chars;
372*2d543d20SAndroid Build Coastguard Worker 		uint32_t mode = 0, prefix_len = 0;
373*2d543d20SAndroid Build Coastguard Worker 
374*2d543d20SAndroid Build Coastguard Worker 		rc = grow_specs(data);
375*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0)
376*2d543d20SAndroid Build Coastguard Worker 			goto out;
377*2d543d20SAndroid Build Coastguard Worker 
378*2d543d20SAndroid Build Coastguard Worker 		spec = &data->spec_arr[data->nspec];
379*2d543d20SAndroid Build Coastguard Worker 		spec->from_mmap = 1;
380*2d543d20SAndroid Build Coastguard Worker 
381*2d543d20SAndroid Build Coastguard Worker 		/* Process context */
382*2d543d20SAndroid Build Coastguard Worker 		rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
383*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0 || !entry_len) {
384*2d543d20SAndroid Build Coastguard Worker 			rc = -1;
385*2d543d20SAndroid Build Coastguard Worker 			goto out;
386*2d543d20SAndroid Build Coastguard Worker 		}
387*2d543d20SAndroid Build Coastguard Worker 
388*2d543d20SAndroid Build Coastguard Worker 		str_buf = malloc(entry_len);
389*2d543d20SAndroid Build Coastguard Worker 		if (!str_buf) {
390*2d543d20SAndroid Build Coastguard Worker 			rc = -1;
391*2d543d20SAndroid Build Coastguard Worker 			goto out;
392*2d543d20SAndroid Build Coastguard Worker 		}
393*2d543d20SAndroid Build Coastguard Worker 		rc = next_entry(str_buf, mmap_area, entry_len);
394*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0) {
395*2d543d20SAndroid Build Coastguard Worker 			free(str_buf);
396*2d543d20SAndroid Build Coastguard Worker 			goto out;
397*2d543d20SAndroid Build Coastguard Worker 		}
398*2d543d20SAndroid Build Coastguard Worker 
399*2d543d20SAndroid Build Coastguard Worker 		if (str_buf[entry_len - 1] != '\0') {
400*2d543d20SAndroid Build Coastguard Worker 			free(str_buf);
401*2d543d20SAndroid Build Coastguard Worker 			rc = -1;
402*2d543d20SAndroid Build Coastguard Worker 			goto out;
403*2d543d20SAndroid Build Coastguard Worker 		}
404*2d543d20SAndroid Build Coastguard Worker 		spec->lr.ctx_raw = str_buf;
405*2d543d20SAndroid Build Coastguard Worker 
406*2d543d20SAndroid Build Coastguard Worker 		if (strcmp(spec->lr.ctx_raw, "<<none>>") && rec->validating) {
407*2d543d20SAndroid Build Coastguard Worker 			if (selabel_validate(&spec->lr) < 0) {
408*2d543d20SAndroid Build Coastguard Worker 				selinux_log(SELINUX_ERROR,
409*2d543d20SAndroid Build Coastguard Worker 					    "%s: context %s is invalid\n",
410*2d543d20SAndroid Build Coastguard Worker 					    path, spec->lr.ctx_raw);
411*2d543d20SAndroid Build Coastguard Worker 				goto out;
412*2d543d20SAndroid Build Coastguard Worker 			}
413*2d543d20SAndroid Build Coastguard Worker 		}
414*2d543d20SAndroid Build Coastguard Worker 
415*2d543d20SAndroid Build Coastguard Worker 		/* Process regex string */
416*2d543d20SAndroid Build Coastguard Worker 		rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
417*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0 || !entry_len) {
418*2d543d20SAndroid Build Coastguard Worker 			rc = -1;
419*2d543d20SAndroid Build Coastguard Worker 			goto out;
420*2d543d20SAndroid Build Coastguard Worker 		}
421*2d543d20SAndroid Build Coastguard Worker 
422*2d543d20SAndroid Build Coastguard Worker 		spec->regex_str = (char *)mmap_area->next_addr;
423*2d543d20SAndroid Build Coastguard Worker 		rc = next_entry(NULL, mmap_area, entry_len);
424*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0)
425*2d543d20SAndroid Build Coastguard Worker 			goto out;
426*2d543d20SAndroid Build Coastguard Worker 
427*2d543d20SAndroid Build Coastguard Worker 		if (spec->regex_str[entry_len - 1] != '\0') {
428*2d543d20SAndroid Build Coastguard Worker 			rc = -1;
429*2d543d20SAndroid Build Coastguard Worker 			goto out;
430*2d543d20SAndroid Build Coastguard Worker 		}
431*2d543d20SAndroid Build Coastguard Worker 
432*2d543d20SAndroid Build Coastguard Worker 		/* Process mode */
433*2d543d20SAndroid Build Coastguard Worker 		if (version >= SELINUX_COMPILED_FCONTEXT_MODE)
434*2d543d20SAndroid Build Coastguard Worker 			rc = next_entry(&mode, mmap_area, sizeof(uint32_t));
435*2d543d20SAndroid Build Coastguard Worker 		else
436*2d543d20SAndroid Build Coastguard Worker 			rc = next_entry(&mode, mmap_area, sizeof(mode_t));
437*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0)
438*2d543d20SAndroid Build Coastguard Worker 			goto out;
439*2d543d20SAndroid Build Coastguard Worker 
440*2d543d20SAndroid Build Coastguard Worker 		spec->mode = mode;
441*2d543d20SAndroid Build Coastguard Worker 
442*2d543d20SAndroid Build Coastguard Worker 		/* map the stem id from the mmap file to the data->stem_arr */
443*2d543d20SAndroid Build Coastguard Worker 		rc = next_entry(&stem_id, mmap_area, sizeof(int32_t));
444*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0)
445*2d543d20SAndroid Build Coastguard Worker 			goto out;
446*2d543d20SAndroid Build Coastguard Worker 
447*2d543d20SAndroid Build Coastguard Worker 		if (stem_id < 0 || stem_id >= (int32_t)stem_map_len)
448*2d543d20SAndroid Build Coastguard Worker 			spec->stem_id = -1;
449*2d543d20SAndroid Build Coastguard Worker 		else
450*2d543d20SAndroid Build Coastguard Worker 			spec->stem_id = stem_map[stem_id];
451*2d543d20SAndroid Build Coastguard Worker 
452*2d543d20SAndroid Build Coastguard Worker 		/* retrieve the hasMetaChars bit */
453*2d543d20SAndroid Build Coastguard Worker 		rc = next_entry(&meta_chars, mmap_area, sizeof(uint32_t));
454*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0)
455*2d543d20SAndroid Build Coastguard Worker 			goto out;
456*2d543d20SAndroid Build Coastguard Worker 
457*2d543d20SAndroid Build Coastguard Worker 		spec->hasMetaChars = meta_chars;
458*2d543d20SAndroid Build Coastguard Worker 		/* and prefix length for use by selabel_lookup_best_match */
459*2d543d20SAndroid Build Coastguard Worker 		if (version >= SELINUX_COMPILED_FCONTEXT_PREFIX_LEN) {
460*2d543d20SAndroid Build Coastguard Worker 			rc = next_entry(&prefix_len, mmap_area,
461*2d543d20SAndroid Build Coastguard Worker 					    sizeof(uint32_t));
462*2d543d20SAndroid Build Coastguard Worker 			if (rc < 0)
463*2d543d20SAndroid Build Coastguard Worker 				goto out;
464*2d543d20SAndroid Build Coastguard Worker 
465*2d543d20SAndroid Build Coastguard Worker 			spec->prefix_len = prefix_len;
466*2d543d20SAndroid Build Coastguard Worker 		}
467*2d543d20SAndroid Build Coastguard Worker 
468*2d543d20SAndroid Build Coastguard Worker 		rc = regex_load_mmap(mmap_area, &spec->regex, reg_arch_matches,
469*2d543d20SAndroid Build Coastguard Worker 				     &spec->regex_compiled);
470*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0)
471*2d543d20SAndroid Build Coastguard Worker 			goto out;
472*2d543d20SAndroid Build Coastguard Worker 
473*2d543d20SAndroid Build Coastguard Worker 		__pthread_mutex_init(&spec->regex_lock, NULL);
474*2d543d20SAndroid Build Coastguard Worker 		data->nspec++;
475*2d543d20SAndroid Build Coastguard Worker 	}
476*2d543d20SAndroid Build Coastguard Worker 
477*2d543d20SAndroid Build Coastguard Worker 	rc = 0;
478*2d543d20SAndroid Build Coastguard Worker out:
479*2d543d20SAndroid Build Coastguard Worker 	free(stem_map);
480*2d543d20SAndroid Build Coastguard Worker 
481*2d543d20SAndroid Build Coastguard Worker 	return rc;
482*2d543d20SAndroid Build Coastguard Worker }
483*2d543d20SAndroid Build Coastguard Worker 
484*2d543d20SAndroid Build Coastguard Worker struct file_details {
485*2d543d20SAndroid Build Coastguard Worker 	const char *suffix;
486*2d543d20SAndroid Build Coastguard Worker 	struct stat sb;
487*2d543d20SAndroid Build Coastguard Worker };
488*2d543d20SAndroid Build Coastguard Worker 
rolling_append(char * current,const char * suffix,size_t max)489*2d543d20SAndroid Build Coastguard Worker static char *rolling_append(char *current, const char *suffix, size_t max)
490*2d543d20SAndroid Build Coastguard Worker {
491*2d543d20SAndroid Build Coastguard Worker 	size_t size;
492*2d543d20SAndroid Build Coastguard Worker 	size_t suffix_size;
493*2d543d20SAndroid Build Coastguard Worker 	size_t current_size;
494*2d543d20SAndroid Build Coastguard Worker 
495*2d543d20SAndroid Build Coastguard Worker 	if (!suffix)
496*2d543d20SAndroid Build Coastguard Worker 		return current;
497*2d543d20SAndroid Build Coastguard Worker 
498*2d543d20SAndroid Build Coastguard Worker 	current_size = strlen(current);
499*2d543d20SAndroid Build Coastguard Worker 	suffix_size = strlen(suffix);
500*2d543d20SAndroid Build Coastguard Worker 
501*2d543d20SAndroid Build Coastguard Worker 	size = current_size + suffix_size;
502*2d543d20SAndroid Build Coastguard Worker 	if (size < current_size || size < suffix_size)
503*2d543d20SAndroid Build Coastguard Worker 		return NULL;
504*2d543d20SAndroid Build Coastguard Worker 
505*2d543d20SAndroid Build Coastguard Worker 	/* ensure space for the '.' and the '\0' characters. */
506*2d543d20SAndroid Build Coastguard Worker 	if (size >= (SIZE_MAX - 2))
507*2d543d20SAndroid Build Coastguard Worker 		return NULL;
508*2d543d20SAndroid Build Coastguard Worker 
509*2d543d20SAndroid Build Coastguard Worker 	size += 2;
510*2d543d20SAndroid Build Coastguard Worker 
511*2d543d20SAndroid Build Coastguard Worker 	if (size > max)
512*2d543d20SAndroid Build Coastguard Worker 		return NULL;
513*2d543d20SAndroid Build Coastguard Worker 
514*2d543d20SAndroid Build Coastguard Worker 	/* Append any given suffix */
515*2d543d20SAndroid Build Coastguard Worker 	char *to = current + current_size;
516*2d543d20SAndroid Build Coastguard Worker 	*to++ = '.';
517*2d543d20SAndroid Build Coastguard Worker 	strcpy(to, suffix);
518*2d543d20SAndroid Build Coastguard Worker 
519*2d543d20SAndroid Build Coastguard Worker 	return current;
520*2d543d20SAndroid Build Coastguard Worker }
521*2d543d20SAndroid Build Coastguard Worker 
fcontext_is_binary(FILE * fp)522*2d543d20SAndroid Build Coastguard Worker static int fcontext_is_binary(FILE *fp)
523*2d543d20SAndroid Build Coastguard Worker {
524*2d543d20SAndroid Build Coastguard Worker 	uint32_t magic;
525*2d543d20SAndroid Build Coastguard Worker 	int rc;
526*2d543d20SAndroid Build Coastguard Worker 
527*2d543d20SAndroid Build Coastguard Worker 	size_t len = fread(&magic, sizeof(magic), 1, fp);
528*2d543d20SAndroid Build Coastguard Worker 
529*2d543d20SAndroid Build Coastguard Worker 	rc = fseek(fp, 0L, SEEK_SET);
530*2d543d20SAndroid Build Coastguard Worker 	if (rc == -1)
531*2d543d20SAndroid Build Coastguard Worker 		return -1;
532*2d543d20SAndroid Build Coastguard Worker 
533*2d543d20SAndroid Build Coastguard Worker 	return (len && (magic == SELINUX_MAGIC_COMPILED_FCONTEXT));
534*2d543d20SAndroid Build Coastguard Worker }
535*2d543d20SAndroid Build Coastguard Worker 
536*2d543d20SAndroid Build Coastguard Worker #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
537*2d543d20SAndroid Build Coastguard Worker 
open_file(const char * path,const char * suffix,char * save_path,size_t len,struct stat * sb,bool open_oldest)538*2d543d20SAndroid Build Coastguard Worker static FILE *open_file(const char *path, const char *suffix,
539*2d543d20SAndroid Build Coastguard Worker 	       char *save_path, size_t len, struct stat *sb, bool open_oldest)
540*2d543d20SAndroid Build Coastguard Worker {
541*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
542*2d543d20SAndroid Build Coastguard Worker 	int rc;
543*2d543d20SAndroid Build Coastguard Worker 	char stack_path[len];
544*2d543d20SAndroid Build Coastguard Worker 	struct file_details *found = NULL;
545*2d543d20SAndroid Build Coastguard Worker 
546*2d543d20SAndroid Build Coastguard Worker 	/*
547*2d543d20SAndroid Build Coastguard Worker 	 * Rolling append of suffix. Try to open with path.suffix then the
548*2d543d20SAndroid Build Coastguard Worker 	 * next as path.suffix.suffix and so forth.
549*2d543d20SAndroid Build Coastguard Worker 	 */
550*2d543d20SAndroid Build Coastguard Worker 	struct file_details fdetails[2] = {
551*2d543d20SAndroid Build Coastguard Worker 			{ .suffix = suffix },
552*2d543d20SAndroid Build Coastguard Worker 			{ .suffix = "bin" }
553*2d543d20SAndroid Build Coastguard Worker 	};
554*2d543d20SAndroid Build Coastguard Worker 
555*2d543d20SAndroid Build Coastguard Worker 	rc = snprintf(stack_path, sizeof(stack_path), "%s", path);
556*2d543d20SAndroid Build Coastguard Worker 	if (rc >= (int) sizeof(stack_path)) {
557*2d543d20SAndroid Build Coastguard Worker 		errno = ENAMETOOLONG;
558*2d543d20SAndroid Build Coastguard Worker 		return NULL;
559*2d543d20SAndroid Build Coastguard Worker 	}
560*2d543d20SAndroid Build Coastguard Worker 
561*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < ARRAY_SIZE(fdetails); i++) {
562*2d543d20SAndroid Build Coastguard Worker 
563*2d543d20SAndroid Build Coastguard Worker 		/* This handles the case if suffix is null */
564*2d543d20SAndroid Build Coastguard Worker 		path = rolling_append(stack_path, fdetails[i].suffix,
565*2d543d20SAndroid Build Coastguard Worker 				      sizeof(stack_path));
566*2d543d20SAndroid Build Coastguard Worker 		if (!path) {
567*2d543d20SAndroid Build Coastguard Worker 			errno = ENOMEM;
568*2d543d20SAndroid Build Coastguard Worker 			return NULL;
569*2d543d20SAndroid Build Coastguard Worker 		}
570*2d543d20SAndroid Build Coastguard Worker 
571*2d543d20SAndroid Build Coastguard Worker 		rc = stat(path, &fdetails[i].sb);
572*2d543d20SAndroid Build Coastguard Worker 		if (rc)
573*2d543d20SAndroid Build Coastguard Worker 			continue;
574*2d543d20SAndroid Build Coastguard Worker 
575*2d543d20SAndroid Build Coastguard Worker 		/* first file thing found, just take it */
576*2d543d20SAndroid Build Coastguard Worker 		if (!found) {
577*2d543d20SAndroid Build Coastguard Worker 			strcpy(save_path, path);
578*2d543d20SAndroid Build Coastguard Worker 			found = &fdetails[i];
579*2d543d20SAndroid Build Coastguard Worker 			continue;
580*2d543d20SAndroid Build Coastguard Worker 		}
581*2d543d20SAndroid Build Coastguard Worker 
582*2d543d20SAndroid Build Coastguard Worker 		/*
583*2d543d20SAndroid Build Coastguard Worker 		 * Keep picking the newest file found. Where "newest"
584*2d543d20SAndroid Build Coastguard Worker 		 * includes equality. This provides a precedence on
585*2d543d20SAndroid Build Coastguard Worker 		 * secondary suffixes even when the timestamp is the
586*2d543d20SAndroid Build Coastguard Worker 		 * same. Ie choose file_contexts.bin over file_contexts
587*2d543d20SAndroid Build Coastguard Worker 		 * even if the time stamp is the same. Invert this logic
588*2d543d20SAndroid Build Coastguard Worker 		 * on open_oldest set to true. The idea is that if the
589*2d543d20SAndroid Build Coastguard Worker 		 * newest file failed to process, we can attempt to
590*2d543d20SAndroid Build Coastguard Worker 		 * process the oldest. The logic here is subtle and depends
591*2d543d20SAndroid Build Coastguard Worker 		 * on the array ordering in fdetails for the case when time
592*2d543d20SAndroid Build Coastguard Worker 		 * stamps are the same.
593*2d543d20SAndroid Build Coastguard Worker 		 */
594*2d543d20SAndroid Build Coastguard Worker 		if (open_oldest ^
595*2d543d20SAndroid Build Coastguard Worker 			(fdetails[i].sb.st_mtime >= found->sb.st_mtime)) {
596*2d543d20SAndroid Build Coastguard Worker 			found = &fdetails[i];
597*2d543d20SAndroid Build Coastguard Worker 			strcpy(save_path, path);
598*2d543d20SAndroid Build Coastguard Worker 		}
599*2d543d20SAndroid Build Coastguard Worker 	}
600*2d543d20SAndroid Build Coastguard Worker 
601*2d543d20SAndroid Build Coastguard Worker 	if (!found) {
602*2d543d20SAndroid Build Coastguard Worker 		errno = ENOENT;
603*2d543d20SAndroid Build Coastguard Worker 		return NULL;
604*2d543d20SAndroid Build Coastguard Worker 	}
605*2d543d20SAndroid Build Coastguard Worker 
606*2d543d20SAndroid Build Coastguard Worker 	memcpy(sb, &found->sb, sizeof(*sb));
607*2d543d20SAndroid Build Coastguard Worker 	return fopen(save_path, "re");
608*2d543d20SAndroid Build Coastguard Worker }
609*2d543d20SAndroid Build Coastguard Worker 
process_file(const char * path,const char * suffix,struct selabel_handle * rec,const char * prefix,struct selabel_digest * digest)610*2d543d20SAndroid Build Coastguard Worker static int process_file(const char *path, const char *suffix,
611*2d543d20SAndroid Build Coastguard Worker 			  struct selabel_handle *rec,
612*2d543d20SAndroid Build Coastguard Worker 			  const char *prefix, struct selabel_digest *digest)
613*2d543d20SAndroid Build Coastguard Worker {
614*2d543d20SAndroid Build Coastguard Worker 	int rc;
615*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
616*2d543d20SAndroid Build Coastguard Worker 	struct stat sb;
617*2d543d20SAndroid Build Coastguard Worker 	FILE *fp = NULL;
618*2d543d20SAndroid Build Coastguard Worker 	char found_path[PATH_MAX];
619*2d543d20SAndroid Build Coastguard Worker 
620*2d543d20SAndroid Build Coastguard Worker 	/*
621*2d543d20SAndroid Build Coastguard Worker 	 * On the first pass open the newest modified file. If it fails to
622*2d543d20SAndroid Build Coastguard Worker 	 * process, then the second pass shall open the oldest file. If both
623*2d543d20SAndroid Build Coastguard Worker 	 * passes fail, then it's a fatal error.
624*2d543d20SAndroid Build Coastguard Worker 	 */
625*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < 2; i++) {
626*2d543d20SAndroid Build Coastguard Worker 		fp = open_file(path, suffix, found_path, sizeof(found_path),
627*2d543d20SAndroid Build Coastguard Worker 			&sb, i > 0);
628*2d543d20SAndroid Build Coastguard Worker 		if (fp == NULL)
629*2d543d20SAndroid Build Coastguard Worker 			return -1;
630*2d543d20SAndroid Build Coastguard Worker 
631*2d543d20SAndroid Build Coastguard Worker 		rc = fcontext_is_binary(fp);
632*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0) {
633*2d543d20SAndroid Build Coastguard Worker 			fclose_errno_safe(fp);
634*2d543d20SAndroid Build Coastguard Worker 			return -1;
635*2d543d20SAndroid Build Coastguard Worker 		}
636*2d543d20SAndroid Build Coastguard Worker 
637*2d543d20SAndroid Build Coastguard Worker 		rc = rc ?
638*2d543d20SAndroid Build Coastguard Worker 				load_mmap(fp, sb.st_size, rec, found_path) :
639*2d543d20SAndroid Build Coastguard Worker 				process_text_file(fp, prefix, rec, found_path);
640*2d543d20SAndroid Build Coastguard Worker 		if (!rc)
641*2d543d20SAndroid Build Coastguard Worker 			rc = digest_add_specfile(digest, fp, NULL, sb.st_size,
642*2d543d20SAndroid Build Coastguard Worker 				found_path);
643*2d543d20SAndroid Build Coastguard Worker 
644*2d543d20SAndroid Build Coastguard Worker 		fclose_errno_safe(fp);
645*2d543d20SAndroid Build Coastguard Worker 
646*2d543d20SAndroid Build Coastguard Worker 		if (!rc)
647*2d543d20SAndroid Build Coastguard Worker 			return 0;
648*2d543d20SAndroid Build Coastguard Worker 	}
649*2d543d20SAndroid Build Coastguard Worker 	return -1;
650*2d543d20SAndroid Build Coastguard Worker }
651*2d543d20SAndroid Build Coastguard Worker 
selabel_subs_fini(struct selabel_sub * ptr)652*2d543d20SAndroid Build Coastguard Worker static void selabel_subs_fini(struct selabel_sub *ptr)
653*2d543d20SAndroid Build Coastguard Worker {
654*2d543d20SAndroid Build Coastguard Worker 	struct selabel_sub *next;
655*2d543d20SAndroid Build Coastguard Worker 
656*2d543d20SAndroid Build Coastguard Worker 	while (ptr) {
657*2d543d20SAndroid Build Coastguard Worker 		next = ptr->next;
658*2d543d20SAndroid Build Coastguard Worker 		free(ptr->src);
659*2d543d20SAndroid Build Coastguard Worker 		free(ptr->dst);
660*2d543d20SAndroid Build Coastguard Worker 		free(ptr);
661*2d543d20SAndroid Build Coastguard Worker 		ptr = next;
662*2d543d20SAndroid Build Coastguard Worker 	}
663*2d543d20SAndroid Build Coastguard Worker }
664*2d543d20SAndroid Build Coastguard Worker 
selabel_sub(struct selabel_sub * ptr,const char * src)665*2d543d20SAndroid Build Coastguard Worker static char *selabel_sub(struct selabel_sub *ptr, const char *src)
666*2d543d20SAndroid Build Coastguard Worker {
667*2d543d20SAndroid Build Coastguard Worker 	char *dst = NULL;
668*2d543d20SAndroid Build Coastguard Worker 	int len;
669*2d543d20SAndroid Build Coastguard Worker 
670*2d543d20SAndroid Build Coastguard Worker 	while (ptr) {
671*2d543d20SAndroid Build Coastguard Worker 		if (strncmp(src, ptr->src, ptr->slen) == 0 ) {
672*2d543d20SAndroid Build Coastguard Worker 			if (src[ptr->slen] == '/' ||
673*2d543d20SAndroid Build Coastguard Worker 			    src[ptr->slen] == 0) {
674*2d543d20SAndroid Build Coastguard Worker 				if ((src[ptr->slen] == '/') &&
675*2d543d20SAndroid Build Coastguard Worker 				    (strcmp(ptr->dst, "/") == 0))
676*2d543d20SAndroid Build Coastguard Worker 					len = ptr->slen + 1;
677*2d543d20SAndroid Build Coastguard Worker 				else
678*2d543d20SAndroid Build Coastguard Worker 					len = ptr->slen;
679*2d543d20SAndroid Build Coastguard Worker 				if (asprintf(&dst, "%s%s", ptr->dst, &src[len]) < 0)
680*2d543d20SAndroid Build Coastguard Worker 					return NULL;
681*2d543d20SAndroid Build Coastguard Worker 				return dst;
682*2d543d20SAndroid Build Coastguard Worker 			}
683*2d543d20SAndroid Build Coastguard Worker 		}
684*2d543d20SAndroid Build Coastguard Worker 		ptr = ptr->next;
685*2d543d20SAndroid Build Coastguard Worker 	}
686*2d543d20SAndroid Build Coastguard Worker 	return NULL;
687*2d543d20SAndroid Build Coastguard Worker }
688*2d543d20SAndroid Build Coastguard Worker 
689*2d543d20SAndroid Build Coastguard Worker #if !defined(BUILD_HOST) && !defined(ANDROID)
selabel_subs_init(const char * path,struct selabel_digest * digest,struct selabel_sub ** out_subs)690*2d543d20SAndroid Build Coastguard Worker static int selabel_subs_init(const char *path, struct selabel_digest *digest,
691*2d543d20SAndroid Build Coastguard Worker 		       struct selabel_sub **out_subs)
692*2d543d20SAndroid Build Coastguard Worker {
693*2d543d20SAndroid Build Coastguard Worker 	char buf[1024];
694*2d543d20SAndroid Build Coastguard Worker 	FILE *cfg = fopen(path, "re");
695*2d543d20SAndroid Build Coastguard Worker 	struct selabel_sub *list = NULL, *sub = NULL;
696*2d543d20SAndroid Build Coastguard Worker 	struct stat sb;
697*2d543d20SAndroid Build Coastguard Worker 	int status = -1;
698*2d543d20SAndroid Build Coastguard Worker 
699*2d543d20SAndroid Build Coastguard Worker 	*out_subs = NULL;
700*2d543d20SAndroid Build Coastguard Worker 	if (!cfg) {
701*2d543d20SAndroid Build Coastguard Worker 		/* If the file does not exist, it is not fatal */
702*2d543d20SAndroid Build Coastguard Worker 		return (errno == ENOENT) ? 0 : -1;
703*2d543d20SAndroid Build Coastguard Worker 	}
704*2d543d20SAndroid Build Coastguard Worker 
705*2d543d20SAndroid Build Coastguard Worker 	if (fstat(fileno(cfg), &sb) < 0)
706*2d543d20SAndroid Build Coastguard Worker 		goto out;
707*2d543d20SAndroid Build Coastguard Worker 
708*2d543d20SAndroid Build Coastguard Worker 	while (fgets_unlocked(buf, sizeof(buf) - 1, cfg)) {
709*2d543d20SAndroid Build Coastguard Worker 		char *ptr = NULL;
710*2d543d20SAndroid Build Coastguard Worker 		char *src = buf;
711*2d543d20SAndroid Build Coastguard Worker 		char *dst = NULL;
712*2d543d20SAndroid Build Coastguard Worker 
713*2d543d20SAndroid Build Coastguard Worker 		while (*src && isspace((unsigned char)*src))
714*2d543d20SAndroid Build Coastguard Worker 			src++;
715*2d543d20SAndroid Build Coastguard Worker 		if (src[0] == '#') continue;
716*2d543d20SAndroid Build Coastguard Worker 		ptr = src;
717*2d543d20SAndroid Build Coastguard Worker 		while (*ptr && ! isspace((unsigned char)*ptr))
718*2d543d20SAndroid Build Coastguard Worker 			ptr++;
719*2d543d20SAndroid Build Coastguard Worker 		*ptr++ = '\0';
720*2d543d20SAndroid Build Coastguard Worker 		if (! *src) continue;
721*2d543d20SAndroid Build Coastguard Worker 
722*2d543d20SAndroid Build Coastguard Worker 		dst = ptr;
723*2d543d20SAndroid Build Coastguard Worker 		while (*dst && isspace((unsigned char)*dst))
724*2d543d20SAndroid Build Coastguard Worker 			dst++;
725*2d543d20SAndroid Build Coastguard Worker 		ptr = dst;
726*2d543d20SAndroid Build Coastguard Worker 		while (*ptr && ! isspace((unsigned char)*ptr))
727*2d543d20SAndroid Build Coastguard Worker 			ptr++;
728*2d543d20SAndroid Build Coastguard Worker 		*ptr = '\0';
729*2d543d20SAndroid Build Coastguard Worker 		if (! *dst)
730*2d543d20SAndroid Build Coastguard Worker 			continue;
731*2d543d20SAndroid Build Coastguard Worker 
732*2d543d20SAndroid Build Coastguard Worker 		sub = calloc(1, sizeof(*sub));
733*2d543d20SAndroid Build Coastguard Worker 		if (! sub)
734*2d543d20SAndroid Build Coastguard Worker 			goto err;
735*2d543d20SAndroid Build Coastguard Worker 
736*2d543d20SAndroid Build Coastguard Worker 		sub->src = strdup(src);
737*2d543d20SAndroid Build Coastguard Worker 		if (! sub->src)
738*2d543d20SAndroid Build Coastguard Worker 			goto err;
739*2d543d20SAndroid Build Coastguard Worker 
740*2d543d20SAndroid Build Coastguard Worker 		sub->dst = strdup(dst);
741*2d543d20SAndroid Build Coastguard Worker 		if (! sub->dst)
742*2d543d20SAndroid Build Coastguard Worker 			goto err;
743*2d543d20SAndroid Build Coastguard Worker 
744*2d543d20SAndroid Build Coastguard Worker 		sub->slen = strlen(src);
745*2d543d20SAndroid Build Coastguard Worker 		sub->next = list;
746*2d543d20SAndroid Build Coastguard Worker 		list = sub;
747*2d543d20SAndroid Build Coastguard Worker 		sub = NULL;
748*2d543d20SAndroid Build Coastguard Worker 	}
749*2d543d20SAndroid Build Coastguard Worker 
750*2d543d20SAndroid Build Coastguard Worker 	if (digest_add_specfile(digest, cfg, NULL, sb.st_size, path) < 0)
751*2d543d20SAndroid Build Coastguard Worker 		goto err;
752*2d543d20SAndroid Build Coastguard Worker 
753*2d543d20SAndroid Build Coastguard Worker 	*out_subs = list;
754*2d543d20SAndroid Build Coastguard Worker 	status = 0;
755*2d543d20SAndroid Build Coastguard Worker 
756*2d543d20SAndroid Build Coastguard Worker out:
757*2d543d20SAndroid Build Coastguard Worker 	fclose(cfg);
758*2d543d20SAndroid Build Coastguard Worker 	return status;
759*2d543d20SAndroid Build Coastguard Worker err:
760*2d543d20SAndroid Build Coastguard Worker 	if (sub)
761*2d543d20SAndroid Build Coastguard Worker 		free(sub->src);
762*2d543d20SAndroid Build Coastguard Worker 	free(sub);
763*2d543d20SAndroid Build Coastguard Worker 	while (list) {
764*2d543d20SAndroid Build Coastguard Worker 		sub = list->next;
765*2d543d20SAndroid Build Coastguard Worker 		free(list->src);
766*2d543d20SAndroid Build Coastguard Worker 		free(list->dst);
767*2d543d20SAndroid Build Coastguard Worker 		free(list);
768*2d543d20SAndroid Build Coastguard Worker 		list = sub;
769*2d543d20SAndroid Build Coastguard Worker 	}
770*2d543d20SAndroid Build Coastguard Worker 	goto out;
771*2d543d20SAndroid Build Coastguard Worker }
772*2d543d20SAndroid Build Coastguard Worker #endif
773*2d543d20SAndroid Build Coastguard Worker 
selabel_sub_key(struct saved_data * data,const char * key)774*2d543d20SAndroid Build Coastguard Worker static char *selabel_sub_key(struct saved_data *data, const char *key)
775*2d543d20SAndroid Build Coastguard Worker {
776*2d543d20SAndroid Build Coastguard Worker 	char *ptr = NULL;
777*2d543d20SAndroid Build Coastguard Worker 	char *dptr = NULL;
778*2d543d20SAndroid Build Coastguard Worker 
779*2d543d20SAndroid Build Coastguard Worker 	ptr = selabel_sub(data->subs, key);
780*2d543d20SAndroid Build Coastguard Worker 	if (ptr) {
781*2d543d20SAndroid Build Coastguard Worker 		dptr = selabel_sub(data->dist_subs, ptr);
782*2d543d20SAndroid Build Coastguard Worker 		if (dptr) {
783*2d543d20SAndroid Build Coastguard Worker 			free(ptr);
784*2d543d20SAndroid Build Coastguard Worker 			ptr = dptr;
785*2d543d20SAndroid Build Coastguard Worker 		}
786*2d543d20SAndroid Build Coastguard Worker 	} else {
787*2d543d20SAndroid Build Coastguard Worker 		ptr = selabel_sub(data->dist_subs, key);
788*2d543d20SAndroid Build Coastguard Worker 	}
789*2d543d20SAndroid Build Coastguard Worker 	if (ptr)
790*2d543d20SAndroid Build Coastguard Worker 		return ptr;
791*2d543d20SAndroid Build Coastguard Worker 
792*2d543d20SAndroid Build Coastguard Worker 	return NULL;
793*2d543d20SAndroid Build Coastguard Worker }
794*2d543d20SAndroid Build Coastguard Worker 
795*2d543d20SAndroid Build Coastguard Worker static void closef(struct selabel_handle *rec);
796*2d543d20SAndroid Build Coastguard Worker 
init(struct selabel_handle * rec,const struct selinux_opt * opts,unsigned n)797*2d543d20SAndroid Build Coastguard Worker static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
798*2d543d20SAndroid Build Coastguard Worker 		unsigned n)
799*2d543d20SAndroid Build Coastguard Worker {
800*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data = (struct saved_data *)rec->data;
801*2d543d20SAndroid Build Coastguard Worker 	size_t num_paths = 0;
802*2d543d20SAndroid Build Coastguard Worker 	char **path = NULL;
803*2d543d20SAndroid Build Coastguard Worker 	const char *prefix = NULL;
804*2d543d20SAndroid Build Coastguard Worker 	int status = -1;
805*2d543d20SAndroid Build Coastguard Worker 	size_t i;
806*2d543d20SAndroid Build Coastguard Worker 	bool baseonly = false;
807*2d543d20SAndroid Build Coastguard Worker 	bool path_provided;
808*2d543d20SAndroid Build Coastguard Worker 
809*2d543d20SAndroid Build Coastguard Worker 	/* Process arguments */
810*2d543d20SAndroid Build Coastguard Worker 	i = n;
811*2d543d20SAndroid Build Coastguard Worker 	while (i--) {
812*2d543d20SAndroid Build Coastguard Worker 		switch(opts[i].type) {
813*2d543d20SAndroid Build Coastguard Worker 		case SELABEL_OPT_PATH:
814*2d543d20SAndroid Build Coastguard Worker 			num_paths++;
815*2d543d20SAndroid Build Coastguard Worker 			break;
816*2d543d20SAndroid Build Coastguard Worker 		case SELABEL_OPT_SUBSET:
817*2d543d20SAndroid Build Coastguard Worker 			prefix = opts[i].value;
818*2d543d20SAndroid Build Coastguard Worker 			break;
819*2d543d20SAndroid Build Coastguard Worker 		case SELABEL_OPT_BASEONLY:
820*2d543d20SAndroid Build Coastguard Worker 			baseonly = !!opts[i].value;
821*2d543d20SAndroid Build Coastguard Worker 			break;
822*2d543d20SAndroid Build Coastguard Worker 		case SELABEL_OPT_UNUSED:
823*2d543d20SAndroid Build Coastguard Worker 		case SELABEL_OPT_VALIDATE:
824*2d543d20SAndroid Build Coastguard Worker 		case SELABEL_OPT_DIGEST:
825*2d543d20SAndroid Build Coastguard Worker 			break;
826*2d543d20SAndroid Build Coastguard Worker 		default:
827*2d543d20SAndroid Build Coastguard Worker 			errno = EINVAL;
828*2d543d20SAndroid Build Coastguard Worker 			return -1;
829*2d543d20SAndroid Build Coastguard Worker 		}
830*2d543d20SAndroid Build Coastguard Worker 	}
831*2d543d20SAndroid Build Coastguard Worker 
832*2d543d20SAndroid Build Coastguard Worker 	if (!num_paths) {
833*2d543d20SAndroid Build Coastguard Worker 		num_paths = 1;
834*2d543d20SAndroid Build Coastguard Worker 		path_provided = false;
835*2d543d20SAndroid Build Coastguard Worker 	} else {
836*2d543d20SAndroid Build Coastguard Worker 		path_provided = true;
837*2d543d20SAndroid Build Coastguard Worker 	}
838*2d543d20SAndroid Build Coastguard Worker 
839*2d543d20SAndroid Build Coastguard Worker 	path = calloc(num_paths, sizeof(*path));
840*2d543d20SAndroid Build Coastguard Worker 	if (path == NULL) {
841*2d543d20SAndroid Build Coastguard Worker 		goto finish;
842*2d543d20SAndroid Build Coastguard Worker 	}
843*2d543d20SAndroid Build Coastguard Worker 	rec->spec_files = path;
844*2d543d20SAndroid Build Coastguard Worker 	rec->spec_files_len = num_paths;
845*2d543d20SAndroid Build Coastguard Worker 
846*2d543d20SAndroid Build Coastguard Worker 	if (path_provided) {
847*2d543d20SAndroid Build Coastguard Worker 		for (i = 0; i < n; i++) {
848*2d543d20SAndroid Build Coastguard Worker 			switch(opts[i].type) {
849*2d543d20SAndroid Build Coastguard Worker 			case SELABEL_OPT_PATH:
850*2d543d20SAndroid Build Coastguard Worker 				*path = strdup(opts[i].value);
851*2d543d20SAndroid Build Coastguard Worker 				if (*path == NULL)
852*2d543d20SAndroid Build Coastguard Worker 					goto finish;
853*2d543d20SAndroid Build Coastguard Worker 				path++;
854*2d543d20SAndroid Build Coastguard Worker 				break;
855*2d543d20SAndroid Build Coastguard Worker 			default:
856*2d543d20SAndroid Build Coastguard Worker 				break;
857*2d543d20SAndroid Build Coastguard Worker 			}
858*2d543d20SAndroid Build Coastguard Worker 		}
859*2d543d20SAndroid Build Coastguard Worker 	}
860*2d543d20SAndroid Build Coastguard Worker #if !defined(BUILD_HOST) && !defined(ANDROID)
861*2d543d20SAndroid Build Coastguard Worker 	char subs_file[PATH_MAX + 1];
862*2d543d20SAndroid Build Coastguard Worker 	/* Process local and distribution substitution files */
863*2d543d20SAndroid Build Coastguard Worker 	if (!path_provided) {
864*2d543d20SAndroid Build Coastguard Worker 		status = selabel_subs_init(
865*2d543d20SAndroid Build Coastguard Worker 			selinux_file_context_subs_dist_path(),
866*2d543d20SAndroid Build Coastguard Worker 			rec->digest, &data->dist_subs);
867*2d543d20SAndroid Build Coastguard Worker 		if (status)
868*2d543d20SAndroid Build Coastguard Worker 			goto finish;
869*2d543d20SAndroid Build Coastguard Worker 		status = selabel_subs_init(selinux_file_context_subs_path(),
870*2d543d20SAndroid Build Coastguard Worker 			rec->digest, &data->subs);
871*2d543d20SAndroid Build Coastguard Worker 		if (status)
872*2d543d20SAndroid Build Coastguard Worker 			goto finish;
873*2d543d20SAndroid Build Coastguard Worker 		rec->spec_files[0] = strdup(selinux_file_context_path());
874*2d543d20SAndroid Build Coastguard Worker 		if (rec->spec_files[0] == NULL)
875*2d543d20SAndroid Build Coastguard Worker 			goto finish;
876*2d543d20SAndroid Build Coastguard Worker 	} else {
877*2d543d20SAndroid Build Coastguard Worker 		for (i = 0; i < num_paths; i++) {
878*2d543d20SAndroid Build Coastguard Worker 			snprintf(subs_file, sizeof(subs_file), "%s.subs_dist", rec->spec_files[i]);
879*2d543d20SAndroid Build Coastguard Worker 			status = selabel_subs_init(subs_file, rec->digest,
880*2d543d20SAndroid Build Coastguard Worker 					   &data->dist_subs);
881*2d543d20SAndroid Build Coastguard Worker 			if (status)
882*2d543d20SAndroid Build Coastguard Worker 				goto finish;
883*2d543d20SAndroid Build Coastguard Worker 			snprintf(subs_file, sizeof(subs_file), "%s.subs", rec->spec_files[i]);
884*2d543d20SAndroid Build Coastguard Worker 			status = selabel_subs_init(subs_file, rec->digest,
885*2d543d20SAndroid Build Coastguard Worker 					   &data->subs);
886*2d543d20SAndroid Build Coastguard Worker 			if (status)
887*2d543d20SAndroid Build Coastguard Worker 				goto finish;
888*2d543d20SAndroid Build Coastguard Worker 		}
889*2d543d20SAndroid Build Coastguard Worker 	}
890*2d543d20SAndroid Build Coastguard Worker #else
891*2d543d20SAndroid Build Coastguard Worker 	if (!path_provided) {
892*2d543d20SAndroid Build Coastguard Worker 		selinux_log(SELINUX_ERROR, "No path given to file labeling backend\n");
893*2d543d20SAndroid Build Coastguard Worker 		goto finish;
894*2d543d20SAndroid Build Coastguard Worker 	}
895*2d543d20SAndroid Build Coastguard Worker #endif
896*2d543d20SAndroid Build Coastguard Worker 
897*2d543d20SAndroid Build Coastguard Worker 	/*
898*2d543d20SAndroid Build Coastguard Worker 	 * Do detailed validation of the input and fill the spec array
899*2d543d20SAndroid Build Coastguard Worker 	 */
900*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < num_paths; i++) {
901*2d543d20SAndroid Build Coastguard Worker 		status = process_file(rec->spec_files[i], NULL, rec, prefix, rec->digest);
902*2d543d20SAndroid Build Coastguard Worker 		if (status)
903*2d543d20SAndroid Build Coastguard Worker 			goto finish;
904*2d543d20SAndroid Build Coastguard Worker 
905*2d543d20SAndroid Build Coastguard Worker 		if (rec->validating) {
906*2d543d20SAndroid Build Coastguard Worker 			status = nodups_specs(data, rec->spec_files[i]);
907*2d543d20SAndroid Build Coastguard Worker 			if (status)
908*2d543d20SAndroid Build Coastguard Worker 				goto finish;
909*2d543d20SAndroid Build Coastguard Worker 		}
910*2d543d20SAndroid Build Coastguard Worker 	}
911*2d543d20SAndroid Build Coastguard Worker 
912*2d543d20SAndroid Build Coastguard Worker 	if (!baseonly) {
913*2d543d20SAndroid Build Coastguard Worker 		status = process_file(rec->spec_files[0], "homedirs", rec, prefix,
914*2d543d20SAndroid Build Coastguard Worker 							    rec->digest);
915*2d543d20SAndroid Build Coastguard Worker 		if (status && errno != ENOENT)
916*2d543d20SAndroid Build Coastguard Worker 			goto finish;
917*2d543d20SAndroid Build Coastguard Worker 
918*2d543d20SAndroid Build Coastguard Worker 		status = process_file(rec->spec_files[0], "local", rec, prefix,
919*2d543d20SAndroid Build Coastguard Worker 							    rec->digest);
920*2d543d20SAndroid Build Coastguard Worker 		if (status && errno != ENOENT)
921*2d543d20SAndroid Build Coastguard Worker 			goto finish;
922*2d543d20SAndroid Build Coastguard Worker 	}
923*2d543d20SAndroid Build Coastguard Worker 
924*2d543d20SAndroid Build Coastguard Worker 	digest_gen_hash(rec->digest);
925*2d543d20SAndroid Build Coastguard Worker 
926*2d543d20SAndroid Build Coastguard Worker 	status = sort_specs(data);
927*2d543d20SAndroid Build Coastguard Worker 
928*2d543d20SAndroid Build Coastguard Worker finish:
929*2d543d20SAndroid Build Coastguard Worker 	if (status)
930*2d543d20SAndroid Build Coastguard Worker 		closef(rec);
931*2d543d20SAndroid Build Coastguard Worker 
932*2d543d20SAndroid Build Coastguard Worker 	return status;
933*2d543d20SAndroid Build Coastguard Worker }
934*2d543d20SAndroid Build Coastguard Worker 
935*2d543d20SAndroid Build Coastguard Worker /*
936*2d543d20SAndroid Build Coastguard Worker  * Backend interface routines
937*2d543d20SAndroid Build Coastguard Worker  */
closef(struct selabel_handle * rec)938*2d543d20SAndroid Build Coastguard Worker static void closef(struct selabel_handle *rec)
939*2d543d20SAndroid Build Coastguard Worker {
940*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data = (struct saved_data *)rec->data;
941*2d543d20SAndroid Build Coastguard Worker 	struct mmap_area *area, *last_area;
942*2d543d20SAndroid Build Coastguard Worker 	struct spec *spec;
943*2d543d20SAndroid Build Coastguard Worker 	struct stem *stem;
944*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
945*2d543d20SAndroid Build Coastguard Worker 
946*2d543d20SAndroid Build Coastguard Worker 	if (!data)
947*2d543d20SAndroid Build Coastguard Worker 		return;
948*2d543d20SAndroid Build Coastguard Worker 
949*2d543d20SAndroid Build Coastguard Worker 	/* make sure successive ->func_close() calls are harmless */
950*2d543d20SAndroid Build Coastguard Worker 	rec->data = NULL;
951*2d543d20SAndroid Build Coastguard Worker 
952*2d543d20SAndroid Build Coastguard Worker 	selabel_subs_fini(data->subs);
953*2d543d20SAndroid Build Coastguard Worker 	selabel_subs_fini(data->dist_subs);
954*2d543d20SAndroid Build Coastguard Worker 
955*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < data->nspec; i++) {
956*2d543d20SAndroid Build Coastguard Worker 		spec = &data->spec_arr[i];
957*2d543d20SAndroid Build Coastguard Worker 		free(spec->lr.ctx_trans);
958*2d543d20SAndroid Build Coastguard Worker 		free(spec->lr.ctx_raw);
959*2d543d20SAndroid Build Coastguard Worker 		regex_data_free(spec->regex);
960*2d543d20SAndroid Build Coastguard Worker 		__pthread_mutex_destroy(&spec->regex_lock);
961*2d543d20SAndroid Build Coastguard Worker 		if (spec->from_mmap)
962*2d543d20SAndroid Build Coastguard Worker 			continue;
963*2d543d20SAndroid Build Coastguard Worker 		free(spec->regex_str);
964*2d543d20SAndroid Build Coastguard Worker 		free(spec->type_str);
965*2d543d20SAndroid Build Coastguard Worker 	}
966*2d543d20SAndroid Build Coastguard Worker 
967*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < (unsigned int)data->num_stems; i++) {
968*2d543d20SAndroid Build Coastguard Worker 		stem = &data->stem_arr[i];
969*2d543d20SAndroid Build Coastguard Worker 		if (stem->from_mmap)
970*2d543d20SAndroid Build Coastguard Worker 			continue;
971*2d543d20SAndroid Build Coastguard Worker 		free(stem->buf);
972*2d543d20SAndroid Build Coastguard Worker 	}
973*2d543d20SAndroid Build Coastguard Worker 
974*2d543d20SAndroid Build Coastguard Worker 	if (data->spec_arr)
975*2d543d20SAndroid Build Coastguard Worker 		free(data->spec_arr);
976*2d543d20SAndroid Build Coastguard Worker 	if (data->stem_arr)
977*2d543d20SAndroid Build Coastguard Worker 		free(data->stem_arr);
978*2d543d20SAndroid Build Coastguard Worker 
979*2d543d20SAndroid Build Coastguard Worker 	area = data->mmap_areas;
980*2d543d20SAndroid Build Coastguard Worker 	while (area) {
981*2d543d20SAndroid Build Coastguard Worker 		munmap(area->addr, area->len);
982*2d543d20SAndroid Build Coastguard Worker 		last_area = area;
983*2d543d20SAndroid Build Coastguard Worker 		area = area->next;
984*2d543d20SAndroid Build Coastguard Worker 		free(last_area);
985*2d543d20SAndroid Build Coastguard Worker 	}
986*2d543d20SAndroid Build Coastguard Worker 	free(data);
987*2d543d20SAndroid Build Coastguard Worker 	rec->data = NULL;
988*2d543d20SAndroid Build Coastguard Worker }
989*2d543d20SAndroid Build Coastguard Worker 
990*2d543d20SAndroid Build Coastguard Worker // Finds all the matches of |key| in the given context. Returns the result in
991*2d543d20SAndroid Build Coastguard Worker // the allocated array and updates the match count. If match_count is NULL,
992*2d543d20SAndroid Build Coastguard Worker // stops early once the 1st match is found.
lookup_all(struct selabel_handle * rec,const char * key,int type,bool partial,size_t * match_count)993*2d543d20SAndroid Build Coastguard Worker static struct spec **lookup_all(struct selabel_handle *rec,
994*2d543d20SAndroid Build Coastguard Worker                                       const char *key,
995*2d543d20SAndroid Build Coastguard Worker                                       int type,
996*2d543d20SAndroid Build Coastguard Worker                                       bool partial,
997*2d543d20SAndroid Build Coastguard Worker                                       size_t *match_count)
998*2d543d20SAndroid Build Coastguard Worker {
999*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data = (struct saved_data *)rec->data;
1000*2d543d20SAndroid Build Coastguard Worker 	struct spec *spec_arr = data->spec_arr;
1001*2d543d20SAndroid Build Coastguard Worker 	int i, rc, file_stem;
1002*2d543d20SAndroid Build Coastguard Worker 	size_t len;
1003*2d543d20SAndroid Build Coastguard Worker 	mode_t mode = (mode_t)type;
1004*2d543d20SAndroid Build Coastguard Worker 	char *clean_key = NULL;
1005*2d543d20SAndroid Build Coastguard Worker 	const char *prev_slash, *next_slash;
1006*2d543d20SAndroid Build Coastguard Worker 	unsigned int sofar = 0;
1007*2d543d20SAndroid Build Coastguard Worker 	char *sub = NULL;
1008*2d543d20SAndroid Build Coastguard Worker 
1009*2d543d20SAndroid Build Coastguard Worker 	struct spec **result = NULL;
1010*2d543d20SAndroid Build Coastguard Worker 	if (match_count) {
1011*2d543d20SAndroid Build Coastguard Worker 		*match_count = 0;
1012*2d543d20SAndroid Build Coastguard Worker 		result = calloc(data->nspec, sizeof(struct spec*));
1013*2d543d20SAndroid Build Coastguard Worker 	} else {
1014*2d543d20SAndroid Build Coastguard Worker 		result = calloc(1, sizeof(struct spec*));
1015*2d543d20SAndroid Build Coastguard Worker 	}
1016*2d543d20SAndroid Build Coastguard Worker 	if (!result) {
1017*2d543d20SAndroid Build Coastguard Worker 		selinux_log(SELINUX_ERROR, "Failed to allocate %zu bytes of data\n",
1018*2d543d20SAndroid Build Coastguard Worker 			    data->nspec * sizeof(struct spec*));
1019*2d543d20SAndroid Build Coastguard Worker 		goto finish;
1020*2d543d20SAndroid Build Coastguard Worker 	}
1021*2d543d20SAndroid Build Coastguard Worker 
1022*2d543d20SAndroid Build Coastguard Worker 	if (!data->nspec) {
1023*2d543d20SAndroid Build Coastguard Worker 		errno = ENOENT;
1024*2d543d20SAndroid Build Coastguard Worker 		goto finish;
1025*2d543d20SAndroid Build Coastguard Worker 	}
1026*2d543d20SAndroid Build Coastguard Worker 
1027*2d543d20SAndroid Build Coastguard Worker 	/* Remove duplicate slashes */
1028*2d543d20SAndroid Build Coastguard Worker 	if ((next_slash = strstr(key, "//"))) {
1029*2d543d20SAndroid Build Coastguard Worker 		clean_key = (char *) malloc(strlen(key) + 1);
1030*2d543d20SAndroid Build Coastguard Worker 		if (!clean_key)
1031*2d543d20SAndroid Build Coastguard Worker 			goto finish;
1032*2d543d20SAndroid Build Coastguard Worker 		prev_slash = key;
1033*2d543d20SAndroid Build Coastguard Worker 		while (next_slash) {
1034*2d543d20SAndroid Build Coastguard Worker 			memcpy(clean_key + sofar, prev_slash, next_slash - prev_slash);
1035*2d543d20SAndroid Build Coastguard Worker 			sofar += next_slash - prev_slash;
1036*2d543d20SAndroid Build Coastguard Worker 			prev_slash = next_slash + 1;
1037*2d543d20SAndroid Build Coastguard Worker 			next_slash = strstr(prev_slash, "//");
1038*2d543d20SAndroid Build Coastguard Worker 		}
1039*2d543d20SAndroid Build Coastguard Worker 		strcpy(clean_key + sofar, prev_slash);
1040*2d543d20SAndroid Build Coastguard Worker 		key = clean_key;
1041*2d543d20SAndroid Build Coastguard Worker 	}
1042*2d543d20SAndroid Build Coastguard Worker 
1043*2d543d20SAndroid Build Coastguard Worker 	/* remove trailing slash */
1044*2d543d20SAndroid Build Coastguard Worker 	len = strlen(key);
1045*2d543d20SAndroid Build Coastguard Worker 	if (len == 0) {
1046*2d543d20SAndroid Build Coastguard Worker 		errno = EINVAL;
1047*2d543d20SAndroid Build Coastguard Worker 		goto finish;
1048*2d543d20SAndroid Build Coastguard Worker 	}
1049*2d543d20SAndroid Build Coastguard Worker 
1050*2d543d20SAndroid Build Coastguard Worker 	if (len > 1 && key[len - 1] == '/') {
1051*2d543d20SAndroid Build Coastguard Worker 		/* reuse clean_key from above if available */
1052*2d543d20SAndroid Build Coastguard Worker 		if (!clean_key) {
1053*2d543d20SAndroid Build Coastguard Worker 			clean_key = (char *) malloc(len);
1054*2d543d20SAndroid Build Coastguard Worker 			if (!clean_key)
1055*2d543d20SAndroid Build Coastguard Worker 				goto finish;
1056*2d543d20SAndroid Build Coastguard Worker 
1057*2d543d20SAndroid Build Coastguard Worker 			memcpy(clean_key, key, len - 1);
1058*2d543d20SAndroid Build Coastguard Worker 		}
1059*2d543d20SAndroid Build Coastguard Worker 
1060*2d543d20SAndroid Build Coastguard Worker 		clean_key[len - 1] = '\0';
1061*2d543d20SAndroid Build Coastguard Worker 		key = clean_key;
1062*2d543d20SAndroid Build Coastguard Worker 	}
1063*2d543d20SAndroid Build Coastguard Worker 
1064*2d543d20SAndroid Build Coastguard Worker 	sub = selabel_sub_key(data, key);
1065*2d543d20SAndroid Build Coastguard Worker 	if (sub)
1066*2d543d20SAndroid Build Coastguard Worker 		key = sub;
1067*2d543d20SAndroid Build Coastguard Worker 
1068*2d543d20SAndroid Build Coastguard Worker 	file_stem = find_stem_from_file(data, key);
1069*2d543d20SAndroid Build Coastguard Worker 	mode &= S_IFMT;
1070*2d543d20SAndroid Build Coastguard Worker 
1071*2d543d20SAndroid Build Coastguard Worker 	/*
1072*2d543d20SAndroid Build Coastguard Worker 	 * Check for matching specifications in reverse order, so that
1073*2d543d20SAndroid Build Coastguard Worker 	 * the last matching specification is used.
1074*2d543d20SAndroid Build Coastguard Worker 	 */
1075*2d543d20SAndroid Build Coastguard Worker 	for (i = data->nspec - 1; i >= 0; i--) {
1076*2d543d20SAndroid Build Coastguard Worker 		struct spec *spec = &spec_arr[i];
1077*2d543d20SAndroid Build Coastguard Worker 		/* if the spec in question matches no stem or has the same
1078*2d543d20SAndroid Build Coastguard Worker 		 * stem as the file AND if the spec in question has no mode
1079*2d543d20SAndroid Build Coastguard Worker 		 * specified or if the mode matches the file mode then we do
1080*2d543d20SAndroid Build Coastguard Worker 		 * a regex check        */
1081*2d543d20SAndroid Build Coastguard Worker 		bool stem_matches = spec->stem_id == -1 || spec->stem_id == file_stem;
1082*2d543d20SAndroid Build Coastguard Worker 		// Don't check the stem if we want to find partial matches.
1083*2d543d20SAndroid Build Coastguard Worker                 // Otherwise the case "/abc/efg/(/.*)?" will be considered
1084*2d543d20SAndroid Build Coastguard Worker                 //a miss for "/abc".
1085*2d543d20SAndroid Build Coastguard Worker 		if ((partial || stem_matches) &&
1086*2d543d20SAndroid Build Coastguard Worker 				(!mode || !spec->mode || mode == spec->mode)) {
1087*2d543d20SAndroid Build Coastguard Worker 			if (compile_regex(spec, NULL) < 0)
1088*2d543d20SAndroid Build Coastguard Worker 				goto finish;
1089*2d543d20SAndroid Build Coastguard Worker 			rc = regex_match(spec->regex, key, partial);
1090*2d543d20SAndroid Build Coastguard Worker 			if (rc == REGEX_MATCH || (partial && rc == REGEX_MATCH_PARTIAL)) {
1091*2d543d20SAndroid Build Coastguard Worker 				if (rc == REGEX_MATCH) {
1092*2d543d20SAndroid Build Coastguard Worker #ifdef __ATOMIC_RELAXED
1093*2d543d20SAndroid Build Coastguard Worker 					__atomic_store_n(&spec->any_matches,
1094*2d543d20SAndroid Build Coastguard Worker 							 true, __ATOMIC_RELAXED);
1095*2d543d20SAndroid Build Coastguard Worker #else
1096*2d543d20SAndroid Build Coastguard Worker #error "Please use a compiler that supports __atomic builtins"
1097*2d543d20SAndroid Build Coastguard Worker #endif
1098*2d543d20SAndroid Build Coastguard Worker 				}
1099*2d543d20SAndroid Build Coastguard Worker 
1100*2d543d20SAndroid Build Coastguard Worker 				if (strcmp(spec_arr[i].lr.ctx_raw, "<<none>>") == 0) {
1101*2d543d20SAndroid Build Coastguard Worker 					errno = ENOENT;
1102*2d543d20SAndroid Build Coastguard Worker 					goto finish;
1103*2d543d20SAndroid Build Coastguard Worker 				}
1104*2d543d20SAndroid Build Coastguard Worker 
1105*2d543d20SAndroid Build Coastguard Worker 				if (match_count) {
1106*2d543d20SAndroid Build Coastguard Worker 					result[*match_count] = spec;
1107*2d543d20SAndroid Build Coastguard Worker 					*match_count += 1;
1108*2d543d20SAndroid Build Coastguard Worker 					// Continue to find all the matches.
1109*2d543d20SAndroid Build Coastguard Worker 					continue;
1110*2d543d20SAndroid Build Coastguard Worker 				}
1111*2d543d20SAndroid Build Coastguard Worker 				result[0] = spec;
1112*2d543d20SAndroid Build Coastguard Worker 				break;
1113*2d543d20SAndroid Build Coastguard Worker 			}
1114*2d543d20SAndroid Build Coastguard Worker 
1115*2d543d20SAndroid Build Coastguard Worker 			if (rc == REGEX_NO_MATCH)
1116*2d543d20SAndroid Build Coastguard Worker 				continue;
1117*2d543d20SAndroid Build Coastguard Worker 
1118*2d543d20SAndroid Build Coastguard Worker 			errno = ENOENT;
1119*2d543d20SAndroid Build Coastguard Worker 			/* else it's an error */
1120*2d543d20SAndroid Build Coastguard Worker 			goto finish;
1121*2d543d20SAndroid Build Coastguard Worker 		}
1122*2d543d20SAndroid Build Coastguard Worker 	}
1123*2d543d20SAndroid Build Coastguard Worker 	if (!result[0])
1124*2d543d20SAndroid Build Coastguard Worker 		errno = ENOENT;
1125*2d543d20SAndroid Build Coastguard Worker 
1126*2d543d20SAndroid Build Coastguard Worker finish:
1127*2d543d20SAndroid Build Coastguard Worker 	free(clean_key);
1128*2d543d20SAndroid Build Coastguard Worker 	free(sub);
1129*2d543d20SAndroid Build Coastguard Worker 	if (result && !result[0]) {
1130*2d543d20SAndroid Build Coastguard Worker 		free(result);
1131*2d543d20SAndroid Build Coastguard Worker 		result = NULL;
1132*2d543d20SAndroid Build Coastguard Worker 	}
1133*2d543d20SAndroid Build Coastguard Worker 	return result;
1134*2d543d20SAndroid Build Coastguard Worker }
1135*2d543d20SAndroid Build Coastguard Worker 
lookup_common(struct selabel_handle * rec,const char * key,int type,bool partial)1136*2d543d20SAndroid Build Coastguard Worker static struct spec *lookup_common(struct selabel_handle *rec,
1137*2d543d20SAndroid Build Coastguard Worker                                   const char *key,
1138*2d543d20SAndroid Build Coastguard Worker                                   int type,
1139*2d543d20SAndroid Build Coastguard Worker                                   bool partial) {
1140*2d543d20SAndroid Build Coastguard Worker 	struct spec **matches = lookup_all(rec, key, type, partial, NULL);
1141*2d543d20SAndroid Build Coastguard Worker 	if (!matches) {
1142*2d543d20SAndroid Build Coastguard Worker 		return NULL;
1143*2d543d20SAndroid Build Coastguard Worker 	}
1144*2d543d20SAndroid Build Coastguard Worker 	struct spec *result = matches[0];
1145*2d543d20SAndroid Build Coastguard Worker 	free(matches);
1146*2d543d20SAndroid Build Coastguard Worker 	return result;
1147*2d543d20SAndroid Build Coastguard Worker }
1148*2d543d20SAndroid Build Coastguard Worker 
1149*2d543d20SAndroid Build Coastguard Worker /*
1150*2d543d20SAndroid Build Coastguard Worker  * Returns true if the digest of all partial matched contexts is the same as
1151*2d543d20SAndroid Build Coastguard Worker  * the one saved by setxattr, otherwise returns false. The length of the SHA1
1152*2d543d20SAndroid Build Coastguard Worker  * digest will always be returned. The caller must free any returned digests.
1153*2d543d20SAndroid Build Coastguard Worker  */
get_digests_all_partial_matches(struct selabel_handle * rec,const char * pathname,uint8_t ** calculated_digest,uint8_t ** xattr_digest,size_t * digest_len)1154*2d543d20SAndroid Build Coastguard Worker static bool get_digests_all_partial_matches(struct selabel_handle *rec,
1155*2d543d20SAndroid Build Coastguard Worker 					    const char *pathname,
1156*2d543d20SAndroid Build Coastguard Worker 					    uint8_t **calculated_digest,
1157*2d543d20SAndroid Build Coastguard Worker 					    uint8_t **xattr_digest,
1158*2d543d20SAndroid Build Coastguard Worker 					    size_t *digest_len)
1159*2d543d20SAndroid Build Coastguard Worker {
1160*2d543d20SAndroid Build Coastguard Worker 	uint8_t read_digest[SHA1_HASH_SIZE];
1161*2d543d20SAndroid Build Coastguard Worker 	ssize_t read_size = getxattr(pathname, RESTORECON_PARTIAL_MATCH_DIGEST,
1162*2d543d20SAndroid Build Coastguard Worker 				     read_digest, SHA1_HASH_SIZE
1163*2d543d20SAndroid Build Coastguard Worker #ifdef __APPLE__
1164*2d543d20SAndroid Build Coastguard Worker 				     , 0, 0
1165*2d543d20SAndroid Build Coastguard Worker #endif /* __APPLE __ */
1166*2d543d20SAndroid Build Coastguard Worker 				    );
1167*2d543d20SAndroid Build Coastguard Worker 	uint8_t hash_digest[SHA1_HASH_SIZE];
1168*2d543d20SAndroid Build Coastguard Worker 	bool status = selabel_hash_all_partial_matches(rec, pathname,
1169*2d543d20SAndroid Build Coastguard Worker 						       hash_digest);
1170*2d543d20SAndroid Build Coastguard Worker 
1171*2d543d20SAndroid Build Coastguard Worker 	*xattr_digest = NULL;
1172*2d543d20SAndroid Build Coastguard Worker 	*calculated_digest = NULL;
1173*2d543d20SAndroid Build Coastguard Worker 	*digest_len = SHA1_HASH_SIZE;
1174*2d543d20SAndroid Build Coastguard Worker 
1175*2d543d20SAndroid Build Coastguard Worker 	if (read_size == SHA1_HASH_SIZE) {
1176*2d543d20SAndroid Build Coastguard Worker 		*xattr_digest = calloc(1, SHA1_HASH_SIZE + 1);
1177*2d543d20SAndroid Build Coastguard Worker 		if (!*xattr_digest)
1178*2d543d20SAndroid Build Coastguard Worker 			goto oom;
1179*2d543d20SAndroid Build Coastguard Worker 
1180*2d543d20SAndroid Build Coastguard Worker 		memcpy(*xattr_digest, read_digest, SHA1_HASH_SIZE);
1181*2d543d20SAndroid Build Coastguard Worker 	}
1182*2d543d20SAndroid Build Coastguard Worker 
1183*2d543d20SAndroid Build Coastguard Worker 	if (status) {
1184*2d543d20SAndroid Build Coastguard Worker 		*calculated_digest = calloc(1, SHA1_HASH_SIZE + 1);
1185*2d543d20SAndroid Build Coastguard Worker 		if (!*calculated_digest)
1186*2d543d20SAndroid Build Coastguard Worker 			goto oom;
1187*2d543d20SAndroid Build Coastguard Worker 
1188*2d543d20SAndroid Build Coastguard Worker 		memcpy(*calculated_digest, hash_digest, SHA1_HASH_SIZE);
1189*2d543d20SAndroid Build Coastguard Worker 	}
1190*2d543d20SAndroid Build Coastguard Worker 
1191*2d543d20SAndroid Build Coastguard Worker 	if (status && read_size == SHA1_HASH_SIZE &&
1192*2d543d20SAndroid Build Coastguard Worker 	    memcmp(read_digest, hash_digest, SHA1_HASH_SIZE) == 0)
1193*2d543d20SAndroid Build Coastguard Worker 		return true;
1194*2d543d20SAndroid Build Coastguard Worker 
1195*2d543d20SAndroid Build Coastguard Worker 	return false;
1196*2d543d20SAndroid Build Coastguard Worker 
1197*2d543d20SAndroid Build Coastguard Worker oom:
1198*2d543d20SAndroid Build Coastguard Worker 	selinux_log(SELINUX_ERROR, "SELinux: %s: Out of memory\n", __func__);
1199*2d543d20SAndroid Build Coastguard Worker 	return false;
1200*2d543d20SAndroid Build Coastguard Worker }
1201*2d543d20SAndroid Build Coastguard Worker 
hash_all_partial_matches(struct selabel_handle * rec,const char * key,uint8_t * digest)1202*2d543d20SAndroid Build Coastguard Worker static bool hash_all_partial_matches(struct selabel_handle *rec, const char *key, uint8_t *digest)
1203*2d543d20SAndroid Build Coastguard Worker {
1204*2d543d20SAndroid Build Coastguard Worker 	assert(digest);
1205*2d543d20SAndroid Build Coastguard Worker 
1206*2d543d20SAndroid Build Coastguard Worker 	size_t total_matches;
1207*2d543d20SAndroid Build Coastguard Worker 	struct spec **matches = lookup_all(rec, key, 0, true, &total_matches);
1208*2d543d20SAndroid Build Coastguard Worker 	if (!matches) {
1209*2d543d20SAndroid Build Coastguard Worker 		return false;
1210*2d543d20SAndroid Build Coastguard Worker 	}
1211*2d543d20SAndroid Build Coastguard Worker 
1212*2d543d20SAndroid Build Coastguard Worker 	Sha1Context context;
1213*2d543d20SAndroid Build Coastguard Worker 	Sha1Initialise(&context);
1214*2d543d20SAndroid Build Coastguard Worker 	size_t i;
1215*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < total_matches; i++) {
1216*2d543d20SAndroid Build Coastguard Worker 		char* regex_str = matches[i]->regex_str;
1217*2d543d20SAndroid Build Coastguard Worker 		mode_t mode = matches[i]->mode;
1218*2d543d20SAndroid Build Coastguard Worker 		char* ctx_raw = matches[i]->lr.ctx_raw;
1219*2d543d20SAndroid Build Coastguard Worker 
1220*2d543d20SAndroid Build Coastguard Worker 		Sha1Update(&context, regex_str, strlen(regex_str) + 1);
1221*2d543d20SAndroid Build Coastguard Worker 		Sha1Update(&context, &mode, sizeof(mode_t));
1222*2d543d20SAndroid Build Coastguard Worker 		Sha1Update(&context, ctx_raw, strlen(ctx_raw) + 1);
1223*2d543d20SAndroid Build Coastguard Worker 	}
1224*2d543d20SAndroid Build Coastguard Worker 
1225*2d543d20SAndroid Build Coastguard Worker 	SHA1_HASH sha1_hash;
1226*2d543d20SAndroid Build Coastguard Worker 	Sha1Finalise(&context, &sha1_hash);
1227*2d543d20SAndroid Build Coastguard Worker 	memcpy(digest, sha1_hash.bytes, SHA1_HASH_SIZE);
1228*2d543d20SAndroid Build Coastguard Worker 
1229*2d543d20SAndroid Build Coastguard Worker 	free(matches);
1230*2d543d20SAndroid Build Coastguard Worker 	return true;
1231*2d543d20SAndroid Build Coastguard Worker }
1232*2d543d20SAndroid Build Coastguard Worker 
lookup(struct selabel_handle * rec,const char * key,int type)1233*2d543d20SAndroid Build Coastguard Worker static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
1234*2d543d20SAndroid Build Coastguard Worker 					 const char *key, int type)
1235*2d543d20SAndroid Build Coastguard Worker {
1236*2d543d20SAndroid Build Coastguard Worker 	struct spec *spec;
1237*2d543d20SAndroid Build Coastguard Worker 
1238*2d543d20SAndroid Build Coastguard Worker 	spec = lookup_common(rec, key, type, false);
1239*2d543d20SAndroid Build Coastguard Worker 	if (spec)
1240*2d543d20SAndroid Build Coastguard Worker 		return &spec->lr;
1241*2d543d20SAndroid Build Coastguard Worker 	return NULL;
1242*2d543d20SAndroid Build Coastguard Worker }
1243*2d543d20SAndroid Build Coastguard Worker 
partial_match(struct selabel_handle * rec,const char * key)1244*2d543d20SAndroid Build Coastguard Worker static bool partial_match(struct selabel_handle *rec, const char *key)
1245*2d543d20SAndroid Build Coastguard Worker {
1246*2d543d20SAndroid Build Coastguard Worker 	return lookup_common(rec, key, 0, true) ? true : false;
1247*2d543d20SAndroid Build Coastguard Worker }
1248*2d543d20SAndroid Build Coastguard Worker 
lookup_best_match(struct selabel_handle * rec,const char * key,const char ** aliases,int type)1249*2d543d20SAndroid Build Coastguard Worker static struct selabel_lookup_rec *lookup_best_match(struct selabel_handle *rec,
1250*2d543d20SAndroid Build Coastguard Worker 						    const char *key,
1251*2d543d20SAndroid Build Coastguard Worker 						    const char **aliases,
1252*2d543d20SAndroid Build Coastguard Worker 						    int type)
1253*2d543d20SAndroid Build Coastguard Worker {
1254*2d543d20SAndroid Build Coastguard Worker 	size_t n, i;
1255*2d543d20SAndroid Build Coastguard Worker 	int best = -1;
1256*2d543d20SAndroid Build Coastguard Worker 	struct spec **specs;
1257*2d543d20SAndroid Build Coastguard Worker 	size_t prefix_len = 0;
1258*2d543d20SAndroid Build Coastguard Worker 	struct selabel_lookup_rec *lr = NULL;
1259*2d543d20SAndroid Build Coastguard Worker 
1260*2d543d20SAndroid Build Coastguard Worker 	if (!aliases || !aliases[0])
1261*2d543d20SAndroid Build Coastguard Worker 		return lookup(rec, key, type);
1262*2d543d20SAndroid Build Coastguard Worker 
1263*2d543d20SAndroid Build Coastguard Worker 	for (n = 0; aliases[n]; n++)
1264*2d543d20SAndroid Build Coastguard Worker 		;
1265*2d543d20SAndroid Build Coastguard Worker 
1266*2d543d20SAndroid Build Coastguard Worker 	specs = calloc(n+1, sizeof(struct spec *));
1267*2d543d20SAndroid Build Coastguard Worker 	if (!specs)
1268*2d543d20SAndroid Build Coastguard Worker 		return NULL;
1269*2d543d20SAndroid Build Coastguard Worker 	specs[0] = lookup_common(rec, key, type, false);
1270*2d543d20SAndroid Build Coastguard Worker 	if (specs[0]) {
1271*2d543d20SAndroid Build Coastguard Worker 		if (!specs[0]->hasMetaChars) {
1272*2d543d20SAndroid Build Coastguard Worker 			/* exact match on key */
1273*2d543d20SAndroid Build Coastguard Worker 			lr = &specs[0]->lr;
1274*2d543d20SAndroid Build Coastguard Worker 			goto out;
1275*2d543d20SAndroid Build Coastguard Worker 		}
1276*2d543d20SAndroid Build Coastguard Worker 		best = 0;
1277*2d543d20SAndroid Build Coastguard Worker 		prefix_len = specs[0]->prefix_len;
1278*2d543d20SAndroid Build Coastguard Worker 	}
1279*2d543d20SAndroid Build Coastguard Worker 	for (i = 1; i <= n; i++) {
1280*2d543d20SAndroid Build Coastguard Worker 		specs[i] = lookup_common(rec, aliases[i-1], type, false);
1281*2d543d20SAndroid Build Coastguard Worker 		if (specs[i]) {
1282*2d543d20SAndroid Build Coastguard Worker 			if (!specs[i]->hasMetaChars) {
1283*2d543d20SAndroid Build Coastguard Worker 				/* exact match on alias */
1284*2d543d20SAndroid Build Coastguard Worker 				lr = &specs[i]->lr;
1285*2d543d20SAndroid Build Coastguard Worker 				goto out;
1286*2d543d20SAndroid Build Coastguard Worker 			}
1287*2d543d20SAndroid Build Coastguard Worker 			if (specs[i]->prefix_len > prefix_len) {
1288*2d543d20SAndroid Build Coastguard Worker 				best = i;
1289*2d543d20SAndroid Build Coastguard Worker 				prefix_len = specs[i]->prefix_len;
1290*2d543d20SAndroid Build Coastguard Worker 			}
1291*2d543d20SAndroid Build Coastguard Worker 		}
1292*2d543d20SAndroid Build Coastguard Worker 	}
1293*2d543d20SAndroid Build Coastguard Worker 
1294*2d543d20SAndroid Build Coastguard Worker 	if (best >= 0) {
1295*2d543d20SAndroid Build Coastguard Worker 		/* longest fixed prefix match on key or alias */
1296*2d543d20SAndroid Build Coastguard Worker 		lr = &specs[best]->lr;
1297*2d543d20SAndroid Build Coastguard Worker 	} else {
1298*2d543d20SAndroid Build Coastguard Worker 		errno = ENOENT;
1299*2d543d20SAndroid Build Coastguard Worker 	}
1300*2d543d20SAndroid Build Coastguard Worker 
1301*2d543d20SAndroid Build Coastguard Worker out:
1302*2d543d20SAndroid Build Coastguard Worker 	free(specs);
1303*2d543d20SAndroid Build Coastguard Worker 	return lr;
1304*2d543d20SAndroid Build Coastguard Worker }
1305*2d543d20SAndroid Build Coastguard Worker 
incomp(const struct spec * spec1,const struct spec * spec2,const char * reason,int i,int j)1306*2d543d20SAndroid Build Coastguard Worker static enum selabel_cmp_result incomp(const struct spec *spec1, const struct spec *spec2, const char *reason, int i, int j)
1307*2d543d20SAndroid Build Coastguard Worker {
1308*2d543d20SAndroid Build Coastguard Worker 	selinux_log(SELINUX_INFO,
1309*2d543d20SAndroid Build Coastguard Worker 		    "selabel_cmp: mismatched %s on entry %d: (%s, %x, %s) vs entry %d: (%s, %x, %s)\n",
1310*2d543d20SAndroid Build Coastguard Worker 		    reason,
1311*2d543d20SAndroid Build Coastguard Worker 		    i, spec1->regex_str, spec1->mode, spec1->lr.ctx_raw,
1312*2d543d20SAndroid Build Coastguard Worker 		    j, spec2->regex_str, spec2->mode, spec2->lr.ctx_raw);
1313*2d543d20SAndroid Build Coastguard Worker 	return SELABEL_INCOMPARABLE;
1314*2d543d20SAndroid Build Coastguard Worker }
1315*2d543d20SAndroid Build Coastguard Worker 
cmp(const struct selabel_handle * h1,const struct selabel_handle * h2)1316*2d543d20SAndroid Build Coastguard Worker static enum selabel_cmp_result cmp(const struct selabel_handle *h1,
1317*2d543d20SAndroid Build Coastguard Worker 				   const struct selabel_handle *h2)
1318*2d543d20SAndroid Build Coastguard Worker {
1319*2d543d20SAndroid Build Coastguard Worker 	const struct saved_data *data1 = (const struct saved_data *)h1->data;
1320*2d543d20SAndroid Build Coastguard Worker 	const struct saved_data *data2 = (const struct saved_data *)h2->data;
1321*2d543d20SAndroid Build Coastguard Worker 	unsigned int i, nspec1 = data1->nspec, j, nspec2 = data2->nspec;
1322*2d543d20SAndroid Build Coastguard Worker 	const struct spec *spec_arr1 = data1->spec_arr, *spec_arr2 = data2->spec_arr;
1323*2d543d20SAndroid Build Coastguard Worker 	const struct stem *stem_arr1 = data1->stem_arr, *stem_arr2 = data2->stem_arr;
1324*2d543d20SAndroid Build Coastguard Worker 	bool skipped1 = false, skipped2 = false;
1325*2d543d20SAndroid Build Coastguard Worker 
1326*2d543d20SAndroid Build Coastguard Worker 	i = 0;
1327*2d543d20SAndroid Build Coastguard Worker 	j = 0;
1328*2d543d20SAndroid Build Coastguard Worker 	while (i < nspec1 && j < nspec2) {
1329*2d543d20SAndroid Build Coastguard Worker 		const struct spec *spec1 = &spec_arr1[i];
1330*2d543d20SAndroid Build Coastguard Worker 		const struct spec *spec2 = &spec_arr2[j];
1331*2d543d20SAndroid Build Coastguard Worker 
1332*2d543d20SAndroid Build Coastguard Worker 		/*
1333*2d543d20SAndroid Build Coastguard Worker 		 * Because sort_specs() moves exact pathnames to the
1334*2d543d20SAndroid Build Coastguard Worker 		 * end, we might need to skip over additional regex
1335*2d543d20SAndroid Build Coastguard Worker 		 * entries that only exist in one of the configurations.
1336*2d543d20SAndroid Build Coastguard Worker 		 */
1337*2d543d20SAndroid Build Coastguard Worker 		if (!spec1->hasMetaChars && spec2->hasMetaChars) {
1338*2d543d20SAndroid Build Coastguard Worker 			j++;
1339*2d543d20SAndroid Build Coastguard Worker 			skipped2 = true;
1340*2d543d20SAndroid Build Coastguard Worker 			continue;
1341*2d543d20SAndroid Build Coastguard Worker 		}
1342*2d543d20SAndroid Build Coastguard Worker 
1343*2d543d20SAndroid Build Coastguard Worker 		if (spec1->hasMetaChars && !spec2->hasMetaChars) {
1344*2d543d20SAndroid Build Coastguard Worker 			i++;
1345*2d543d20SAndroid Build Coastguard Worker 			skipped1 = true;
1346*2d543d20SAndroid Build Coastguard Worker 			continue;
1347*2d543d20SAndroid Build Coastguard Worker 		}
1348*2d543d20SAndroid Build Coastguard Worker 
1349*2d543d20SAndroid Build Coastguard Worker 		if (spec1->regex && spec2->regex) {
1350*2d543d20SAndroid Build Coastguard Worker 			if (regex_cmp(spec1->regex, spec2->regex) == SELABEL_INCOMPARABLE){
1351*2d543d20SAndroid Build Coastguard Worker 				return incomp(spec1, spec2, "regex", i, j);
1352*2d543d20SAndroid Build Coastguard Worker 			}
1353*2d543d20SAndroid Build Coastguard Worker 		} else {
1354*2d543d20SAndroid Build Coastguard Worker 			if (strcmp(spec1->regex_str, spec2->regex_str))
1355*2d543d20SAndroid Build Coastguard Worker 				return incomp(spec1, spec2, "regex_str", i, j);
1356*2d543d20SAndroid Build Coastguard Worker 		}
1357*2d543d20SAndroid Build Coastguard Worker 
1358*2d543d20SAndroid Build Coastguard Worker 		if (spec1->mode != spec2->mode)
1359*2d543d20SAndroid Build Coastguard Worker 			return incomp(spec1, spec2, "mode", i, j);
1360*2d543d20SAndroid Build Coastguard Worker 
1361*2d543d20SAndroid Build Coastguard Worker 		if (spec1->stem_id == -1 && spec2->stem_id != -1)
1362*2d543d20SAndroid Build Coastguard Worker 			return incomp(spec1, spec2, "stem_id", i, j);
1363*2d543d20SAndroid Build Coastguard Worker 		if (spec2->stem_id == -1 && spec1->stem_id != -1)
1364*2d543d20SAndroid Build Coastguard Worker 			return incomp(spec1, spec2, "stem_id", i, j);
1365*2d543d20SAndroid Build Coastguard Worker 		if (spec1->stem_id != -1 && spec2->stem_id != -1) {
1366*2d543d20SAndroid Build Coastguard Worker 			const struct stem *stem1 = &stem_arr1[spec1->stem_id];
1367*2d543d20SAndroid Build Coastguard Worker 			const struct stem *stem2 = &stem_arr2[spec2->stem_id];
1368*2d543d20SAndroid Build Coastguard Worker 			if (stem1->len != stem2->len ||
1369*2d543d20SAndroid Build Coastguard Worker 			    strncmp(stem1->buf, stem2->buf, stem1->len))
1370*2d543d20SAndroid Build Coastguard Worker 				return incomp(spec1, spec2, "stem", i, j);
1371*2d543d20SAndroid Build Coastguard Worker 		}
1372*2d543d20SAndroid Build Coastguard Worker 
1373*2d543d20SAndroid Build Coastguard Worker 		if (strcmp(spec1->lr.ctx_raw, spec2->lr.ctx_raw))
1374*2d543d20SAndroid Build Coastguard Worker 			return incomp(spec1, spec2, "ctx_raw", i, j);
1375*2d543d20SAndroid Build Coastguard Worker 
1376*2d543d20SAndroid Build Coastguard Worker 		i++;
1377*2d543d20SAndroid Build Coastguard Worker 		j++;
1378*2d543d20SAndroid Build Coastguard Worker 	}
1379*2d543d20SAndroid Build Coastguard Worker 
1380*2d543d20SAndroid Build Coastguard Worker 	if ((skipped1 || i < nspec1) && !skipped2)
1381*2d543d20SAndroid Build Coastguard Worker 		return SELABEL_SUPERSET;
1382*2d543d20SAndroid Build Coastguard Worker 	if ((skipped2 || j < nspec2) && !skipped1)
1383*2d543d20SAndroid Build Coastguard Worker 		return SELABEL_SUBSET;
1384*2d543d20SAndroid Build Coastguard Worker 	if (skipped1 && skipped2)
1385*2d543d20SAndroid Build Coastguard Worker 		return SELABEL_INCOMPARABLE;
1386*2d543d20SAndroid Build Coastguard Worker 	return SELABEL_EQUAL;
1387*2d543d20SAndroid Build Coastguard Worker }
1388*2d543d20SAndroid Build Coastguard Worker 
1389*2d543d20SAndroid Build Coastguard Worker 
stats(struct selabel_handle * rec)1390*2d543d20SAndroid Build Coastguard Worker static void stats(struct selabel_handle *rec)
1391*2d543d20SAndroid Build Coastguard Worker {
1392*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data = (struct saved_data *)rec->data;
1393*2d543d20SAndroid Build Coastguard Worker 	unsigned int i, nspec = data->nspec;
1394*2d543d20SAndroid Build Coastguard Worker 	struct spec *spec_arr = data->spec_arr;
1395*2d543d20SAndroid Build Coastguard Worker 	bool any_matches;
1396*2d543d20SAndroid Build Coastguard Worker 
1397*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < nspec; i++) {
1398*2d543d20SAndroid Build Coastguard Worker #ifdef __ATOMIC_RELAXED
1399*2d543d20SAndroid Build Coastguard Worker 		any_matches = __atomic_load_n(&spec_arr[i].any_matches, __ATOMIC_RELAXED);
1400*2d543d20SAndroid Build Coastguard Worker #else
1401*2d543d20SAndroid Build Coastguard Worker #error "Please use a compiler that supports __atomic builtins"
1402*2d543d20SAndroid Build Coastguard Worker #endif
1403*2d543d20SAndroid Build Coastguard Worker 		if (!any_matches) {
1404*2d543d20SAndroid Build Coastguard Worker 			if (spec_arr[i].type_str) {
1405*2d543d20SAndroid Build Coastguard Worker 				COMPAT_LOG(SELINUX_WARNING,
1406*2d543d20SAndroid Build Coastguard Worker 				    "Warning!  No matches for (%s, %s, %s)\n",
1407*2d543d20SAndroid Build Coastguard Worker 				    spec_arr[i].regex_str,
1408*2d543d20SAndroid Build Coastguard Worker 				    spec_arr[i].type_str,
1409*2d543d20SAndroid Build Coastguard Worker 				    spec_arr[i].lr.ctx_raw);
1410*2d543d20SAndroid Build Coastguard Worker 			} else {
1411*2d543d20SAndroid Build Coastguard Worker 				COMPAT_LOG(SELINUX_WARNING,
1412*2d543d20SAndroid Build Coastguard Worker 				    "Warning!  No matches for (%s, %s)\n",
1413*2d543d20SAndroid Build Coastguard Worker 				    spec_arr[i].regex_str,
1414*2d543d20SAndroid Build Coastguard Worker 				    spec_arr[i].lr.ctx_raw);
1415*2d543d20SAndroid Build Coastguard Worker 			}
1416*2d543d20SAndroid Build Coastguard Worker 		}
1417*2d543d20SAndroid Build Coastguard Worker 	}
1418*2d543d20SAndroid Build Coastguard Worker }
1419*2d543d20SAndroid Build Coastguard Worker 
selabel_file_init(struct selabel_handle * rec,const struct selinux_opt * opts,unsigned nopts)1420*2d543d20SAndroid Build Coastguard Worker int selabel_file_init(struct selabel_handle *rec,
1421*2d543d20SAndroid Build Coastguard Worker 				    const struct selinux_opt *opts,
1422*2d543d20SAndroid Build Coastguard Worker 				    unsigned nopts)
1423*2d543d20SAndroid Build Coastguard Worker {
1424*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data;
1425*2d543d20SAndroid Build Coastguard Worker 
1426*2d543d20SAndroid Build Coastguard Worker 	data = (struct saved_data *)calloc(1, sizeof(*data));
1427*2d543d20SAndroid Build Coastguard Worker 	if (!data)
1428*2d543d20SAndroid Build Coastguard Worker 		return -1;
1429*2d543d20SAndroid Build Coastguard Worker 
1430*2d543d20SAndroid Build Coastguard Worker 	rec->data = data;
1431*2d543d20SAndroid Build Coastguard Worker 	rec->func_close = &closef;
1432*2d543d20SAndroid Build Coastguard Worker 	rec->func_stats = &stats;
1433*2d543d20SAndroid Build Coastguard Worker 	rec->func_lookup = &lookup;
1434*2d543d20SAndroid Build Coastguard Worker 	rec->func_partial_match = &partial_match;
1435*2d543d20SAndroid Build Coastguard Worker 	rec->func_get_digests_all_partial_matches =
1436*2d543d20SAndroid Build Coastguard Worker 					&get_digests_all_partial_matches;
1437*2d543d20SAndroid Build Coastguard Worker 	rec->func_hash_all_partial_matches = &hash_all_partial_matches;
1438*2d543d20SAndroid Build Coastguard Worker 	rec->func_lookup_best_match = &lookup_best_match;
1439*2d543d20SAndroid Build Coastguard Worker 	rec->func_cmp = &cmp;
1440*2d543d20SAndroid Build Coastguard Worker 
1441*2d543d20SAndroid Build Coastguard Worker 	return init(rec, opts, nopts);
1442*2d543d20SAndroid Build Coastguard Worker }
1443