xref: /aosp_15_r20/external/selinux/libselinux/src/label_file.h (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1*2d543d20SAndroid Build Coastguard Worker #ifndef _SELABEL_FILE_H_
2*2d543d20SAndroid Build Coastguard Worker #define _SELABEL_FILE_H_
3*2d543d20SAndroid Build Coastguard Worker 
4*2d543d20SAndroid Build Coastguard Worker #include <errno.h>
5*2d543d20SAndroid Build Coastguard Worker #include <pthread.h>
6*2d543d20SAndroid Build Coastguard Worker #include <string.h>
7*2d543d20SAndroid Build Coastguard Worker 
8*2d543d20SAndroid Build Coastguard Worker #include <sys/stat.h>
9*2d543d20SAndroid Build Coastguard Worker #include <sys/xattr.h>
10*2d543d20SAndroid Build Coastguard Worker 
11*2d543d20SAndroid Build Coastguard Worker /*
12*2d543d20SAndroid Build Coastguard Worker  * regex.h/c were introduced to hold all dependencies on the regular
13*2d543d20SAndroid Build Coastguard Worker  * expression back-end when we started supporting PCRE2. regex.h defines a
14*2d543d20SAndroid Build Coastguard Worker  * minimal interface required by libselinux, so that the remaining code
15*2d543d20SAndroid Build Coastguard Worker  * can be agnostic about the underlying implementation.
16*2d543d20SAndroid Build Coastguard Worker  */
17*2d543d20SAndroid Build Coastguard Worker #include "regex.h"
18*2d543d20SAndroid Build Coastguard Worker 
19*2d543d20SAndroid Build Coastguard Worker #include "callbacks.h"
20*2d543d20SAndroid Build Coastguard Worker #include "label_internal.h"
21*2d543d20SAndroid Build Coastguard Worker #include "selinux_internal.h"
22*2d543d20SAndroid Build Coastguard Worker 
23*2d543d20SAndroid Build Coastguard Worker #define SELINUX_MAGIC_COMPILED_FCONTEXT	0xf97cff8a
24*2d543d20SAndroid Build Coastguard Worker 
25*2d543d20SAndroid Build Coastguard Worker /* Version specific changes */
26*2d543d20SAndroid Build Coastguard Worker #define SELINUX_COMPILED_FCONTEXT_NOPCRE_VERS	1
27*2d543d20SAndroid Build Coastguard Worker #define SELINUX_COMPILED_FCONTEXT_PCRE_VERS	2
28*2d543d20SAndroid Build Coastguard Worker #define SELINUX_COMPILED_FCONTEXT_MODE		3
29*2d543d20SAndroid Build Coastguard Worker #define SELINUX_COMPILED_FCONTEXT_PREFIX_LEN	4
30*2d543d20SAndroid Build Coastguard Worker #define SELINUX_COMPILED_FCONTEXT_REGEX_ARCH	5
31*2d543d20SAndroid Build Coastguard Worker 
32*2d543d20SAndroid Build Coastguard Worker #define SELINUX_COMPILED_FCONTEXT_MAX_VERS \
33*2d543d20SAndroid Build Coastguard Worker 	SELINUX_COMPILED_FCONTEXT_REGEX_ARCH
34*2d543d20SAndroid Build Coastguard Worker 
35*2d543d20SAndroid Build Coastguard Worker /* Required selinux_restorecon and selabel_get_digests_all_partial_matches() */
36*2d543d20SAndroid Build Coastguard Worker #define RESTORECON_PARTIAL_MATCH_DIGEST  "security.sehash"
37*2d543d20SAndroid Build Coastguard Worker 
38*2d543d20SAndroid Build Coastguard Worker struct selabel_sub {
39*2d543d20SAndroid Build Coastguard Worker 	char *src;
40*2d543d20SAndroid Build Coastguard Worker 	int slen;
41*2d543d20SAndroid Build Coastguard Worker 	char *dst;
42*2d543d20SAndroid Build Coastguard Worker 	struct selabel_sub *next;
43*2d543d20SAndroid Build Coastguard Worker };
44*2d543d20SAndroid Build Coastguard Worker 
45*2d543d20SAndroid Build Coastguard Worker /* A file security context specification. */
46*2d543d20SAndroid Build Coastguard Worker struct spec {
47*2d543d20SAndroid Build Coastguard Worker 	struct selabel_lookup_rec lr;	/* holds contexts for lookup result */
48*2d543d20SAndroid Build Coastguard Worker 	char *regex_str;	/* regular expression string for diagnostics */
49*2d543d20SAndroid Build Coastguard Worker 	char *type_str;		/* type string for diagnostic messages */
50*2d543d20SAndroid Build Coastguard Worker 	struct regex_data * regex; /* backend dependent regular expression data */
51*2d543d20SAndroid Build Coastguard Worker 	bool regex_compiled; /* bool to indicate if the regex is compiled */
52*2d543d20SAndroid Build Coastguard Worker 	pthread_mutex_t regex_lock; /* lock for lazy compilation of regex */
53*2d543d20SAndroid Build Coastguard Worker 	mode_t mode;		/* mode format value */
54*2d543d20SAndroid Build Coastguard Worker 	bool any_matches;	/* did any pathname match? */
55*2d543d20SAndroid Build Coastguard Worker 	int stem_id;		/* indicates which stem-compression item */
56*2d543d20SAndroid Build Coastguard Worker 	char hasMetaChars;	/* regular expression has meta-chars */
57*2d543d20SAndroid Build Coastguard Worker 	char from_mmap;		/* this spec is from an mmap of the data */
58*2d543d20SAndroid Build Coastguard Worker 	size_t prefix_len;      /* length of fixed path prefix */
59*2d543d20SAndroid Build Coastguard Worker };
60*2d543d20SAndroid Build Coastguard Worker 
61*2d543d20SAndroid Build Coastguard Worker /* A regular expression stem */
62*2d543d20SAndroid Build Coastguard Worker struct stem {
63*2d543d20SAndroid Build Coastguard Worker 	char *buf;
64*2d543d20SAndroid Build Coastguard Worker 	int len;
65*2d543d20SAndroid Build Coastguard Worker 	char from_mmap;
66*2d543d20SAndroid Build Coastguard Worker };
67*2d543d20SAndroid Build Coastguard Worker 
68*2d543d20SAndroid Build Coastguard Worker /* Where we map the file in during selabel_open() */
69*2d543d20SAndroid Build Coastguard Worker struct mmap_area {
70*2d543d20SAndroid Build Coastguard Worker 	void *addr;	/* Start addr + len used to release memory at close */
71*2d543d20SAndroid Build Coastguard Worker 	size_t len;
72*2d543d20SAndroid Build Coastguard Worker 	void *next_addr;	/* Incremented by next_entry() */
73*2d543d20SAndroid Build Coastguard Worker 	size_t next_len;	/* Decremented by next_entry() */
74*2d543d20SAndroid Build Coastguard Worker 	struct mmap_area *next;
75*2d543d20SAndroid Build Coastguard Worker };
76*2d543d20SAndroid Build Coastguard Worker 
77*2d543d20SAndroid Build Coastguard Worker /* Our stored configuration */
78*2d543d20SAndroid Build Coastguard Worker struct saved_data {
79*2d543d20SAndroid Build Coastguard Worker 	/*
80*2d543d20SAndroid Build Coastguard Worker 	 * The array of specifications, initially in the same order as in
81*2d543d20SAndroid Build Coastguard Worker 	 * the specification file. Sorting occurs based on hasMetaChars.
82*2d543d20SAndroid Build Coastguard Worker 	 */
83*2d543d20SAndroid Build Coastguard Worker 	struct spec *spec_arr;
84*2d543d20SAndroid Build Coastguard Worker 	unsigned int nspec;
85*2d543d20SAndroid Build Coastguard Worker 	unsigned int alloc_specs;
86*2d543d20SAndroid Build Coastguard Worker 
87*2d543d20SAndroid Build Coastguard Worker 	/*
88*2d543d20SAndroid Build Coastguard Worker 	 * The array of regular expression stems.
89*2d543d20SAndroid Build Coastguard Worker 	 */
90*2d543d20SAndroid Build Coastguard Worker 	struct stem *stem_arr;
91*2d543d20SAndroid Build Coastguard Worker 	int num_stems;
92*2d543d20SAndroid Build Coastguard Worker 	int alloc_stems;
93*2d543d20SAndroid Build Coastguard Worker 	struct mmap_area *mmap_areas;
94*2d543d20SAndroid Build Coastguard Worker 
95*2d543d20SAndroid Build Coastguard Worker 	/* substitution support */
96*2d543d20SAndroid Build Coastguard Worker 	struct selabel_sub *dist_subs;
97*2d543d20SAndroid Build Coastguard Worker 	struct selabel_sub *subs;
98*2d543d20SAndroid Build Coastguard Worker };
99*2d543d20SAndroid Build Coastguard Worker 
string_to_mode(const char * mode)100*2d543d20SAndroid Build Coastguard Worker static inline mode_t string_to_mode(const char *mode)
101*2d543d20SAndroid Build Coastguard Worker {
102*2d543d20SAndroid Build Coastguard Worker 	if (mode[0] != '-' || mode[1] == '\0' || mode[2] != '\0')
103*2d543d20SAndroid Build Coastguard Worker 		return (mode_t)-1;
104*2d543d20SAndroid Build Coastguard Worker 	switch (mode[1]) {
105*2d543d20SAndroid Build Coastguard Worker 	case 'b':
106*2d543d20SAndroid Build Coastguard Worker 		return S_IFBLK;
107*2d543d20SAndroid Build Coastguard Worker 	case 'c':
108*2d543d20SAndroid Build Coastguard Worker 		return S_IFCHR;
109*2d543d20SAndroid Build Coastguard Worker 	case 'd':
110*2d543d20SAndroid Build Coastguard Worker 		return S_IFDIR;
111*2d543d20SAndroid Build Coastguard Worker 	case 'p':
112*2d543d20SAndroid Build Coastguard Worker 		return S_IFIFO;
113*2d543d20SAndroid Build Coastguard Worker 	case 'l':
114*2d543d20SAndroid Build Coastguard Worker 		return S_IFLNK;
115*2d543d20SAndroid Build Coastguard Worker 	case 's':
116*2d543d20SAndroid Build Coastguard Worker 		return S_IFSOCK;
117*2d543d20SAndroid Build Coastguard Worker 	case '-':
118*2d543d20SAndroid Build Coastguard Worker 		return S_IFREG;
119*2d543d20SAndroid Build Coastguard Worker 	default:
120*2d543d20SAndroid Build Coastguard Worker 		return (mode_t)-1;
121*2d543d20SAndroid Build Coastguard Worker 	}
122*2d543d20SAndroid Build Coastguard Worker }
123*2d543d20SAndroid Build Coastguard Worker 
grow_specs(struct saved_data * data)124*2d543d20SAndroid Build Coastguard Worker static inline int grow_specs(struct saved_data *data)
125*2d543d20SAndroid Build Coastguard Worker {
126*2d543d20SAndroid Build Coastguard Worker 	struct spec *specs;
127*2d543d20SAndroid Build Coastguard Worker 	size_t new_specs, total_specs;
128*2d543d20SAndroid Build Coastguard Worker 
129*2d543d20SAndroid Build Coastguard Worker 	if (data->nspec < data->alloc_specs)
130*2d543d20SAndroid Build Coastguard Worker 		return 0;
131*2d543d20SAndroid Build Coastguard Worker 
132*2d543d20SAndroid Build Coastguard Worker 	new_specs = data->nspec + 16;
133*2d543d20SAndroid Build Coastguard Worker 	total_specs = data->nspec + new_specs;
134*2d543d20SAndroid Build Coastguard Worker 
135*2d543d20SAndroid Build Coastguard Worker 	specs = realloc(data->spec_arr, total_specs * sizeof(*specs));
136*2d543d20SAndroid Build Coastguard Worker 	if (!specs) {
137*2d543d20SAndroid Build Coastguard Worker 		perror("realloc");
138*2d543d20SAndroid Build Coastguard Worker 		return -1;
139*2d543d20SAndroid Build Coastguard Worker 	}
140*2d543d20SAndroid Build Coastguard Worker 
141*2d543d20SAndroid Build Coastguard Worker 	/* blank the new entries */
142*2d543d20SAndroid Build Coastguard Worker 	memset(&specs[data->nspec], 0, new_specs * sizeof(*specs));
143*2d543d20SAndroid Build Coastguard Worker 
144*2d543d20SAndroid Build Coastguard Worker 	data->spec_arr = specs;
145*2d543d20SAndroid Build Coastguard Worker 	data->alloc_specs = total_specs;
146*2d543d20SAndroid Build Coastguard Worker 	return 0;
147*2d543d20SAndroid Build Coastguard Worker }
148*2d543d20SAndroid Build Coastguard Worker 
149*2d543d20SAndroid Build Coastguard Worker /* Determine if the regular expression specification has any meta characters. */
spec_hasMetaChars(struct spec * spec)150*2d543d20SAndroid Build Coastguard Worker static inline void spec_hasMetaChars(struct spec *spec)
151*2d543d20SAndroid Build Coastguard Worker {
152*2d543d20SAndroid Build Coastguard Worker 	char *c;
153*2d543d20SAndroid Build Coastguard Worker 	int len;
154*2d543d20SAndroid Build Coastguard Worker 	char *end;
155*2d543d20SAndroid Build Coastguard Worker 
156*2d543d20SAndroid Build Coastguard Worker 	c = spec->regex_str;
157*2d543d20SAndroid Build Coastguard Worker 	len = strlen(spec->regex_str);
158*2d543d20SAndroid Build Coastguard Worker 	end = c + len;
159*2d543d20SAndroid Build Coastguard Worker 
160*2d543d20SAndroid Build Coastguard Worker 	spec->hasMetaChars = 0;
161*2d543d20SAndroid Build Coastguard Worker 	spec->prefix_len = len;
162*2d543d20SAndroid Build Coastguard Worker 
163*2d543d20SAndroid Build Coastguard Worker 	/* Look at each character in the RE specification string for a
164*2d543d20SAndroid Build Coastguard Worker 	 * meta character. Return when any meta character reached. */
165*2d543d20SAndroid Build Coastguard Worker 	while (c < end) {
166*2d543d20SAndroid Build Coastguard Worker 		switch (*c) {
167*2d543d20SAndroid Build Coastguard Worker 		case '.':
168*2d543d20SAndroid Build Coastguard Worker 		case '^':
169*2d543d20SAndroid Build Coastguard Worker 		case '$':
170*2d543d20SAndroid Build Coastguard Worker 		case '?':
171*2d543d20SAndroid Build Coastguard Worker 		case '*':
172*2d543d20SAndroid Build Coastguard Worker 		case '+':
173*2d543d20SAndroid Build Coastguard Worker 		case '|':
174*2d543d20SAndroid Build Coastguard Worker 		case '[':
175*2d543d20SAndroid Build Coastguard Worker 		case '(':
176*2d543d20SAndroid Build Coastguard Worker 		case '{':
177*2d543d20SAndroid Build Coastguard Worker 			spec->hasMetaChars = 1;
178*2d543d20SAndroid Build Coastguard Worker 			spec->prefix_len = c - spec->regex_str;
179*2d543d20SAndroid Build Coastguard Worker 			return;
180*2d543d20SAndroid Build Coastguard Worker 		case '\\':	/* skip the next character */
181*2d543d20SAndroid Build Coastguard Worker 			c++;
182*2d543d20SAndroid Build Coastguard Worker 			break;
183*2d543d20SAndroid Build Coastguard Worker 		default:
184*2d543d20SAndroid Build Coastguard Worker 			break;
185*2d543d20SAndroid Build Coastguard Worker 
186*2d543d20SAndroid Build Coastguard Worker 		}
187*2d543d20SAndroid Build Coastguard Worker 		c++;
188*2d543d20SAndroid Build Coastguard Worker 	}
189*2d543d20SAndroid Build Coastguard Worker }
190*2d543d20SAndroid Build Coastguard Worker 
191*2d543d20SAndroid Build Coastguard Worker /* Move exact pathname specifications to the end. */
sort_specs(struct saved_data * data)192*2d543d20SAndroid Build Coastguard Worker static inline int sort_specs(struct saved_data *data)
193*2d543d20SAndroid Build Coastguard Worker {
194*2d543d20SAndroid Build Coastguard Worker 	struct spec *spec_copy;
195*2d543d20SAndroid Build Coastguard Worker 	struct spec spec;
196*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
197*2d543d20SAndroid Build Coastguard Worker 	int front, back;
198*2d543d20SAndroid Build Coastguard Worker 	size_t len = sizeof(*spec_copy);
199*2d543d20SAndroid Build Coastguard Worker 
200*2d543d20SAndroid Build Coastguard Worker 	spec_copy = malloc(len * data->nspec);
201*2d543d20SAndroid Build Coastguard Worker 	if (!spec_copy)
202*2d543d20SAndroid Build Coastguard Worker 		return -1;
203*2d543d20SAndroid Build Coastguard Worker 
204*2d543d20SAndroid Build Coastguard Worker 	/* first move the exact pathnames to the back */
205*2d543d20SAndroid Build Coastguard Worker 	front = 0;
206*2d543d20SAndroid Build Coastguard Worker 	back = data->nspec - 1;
207*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < data->nspec; i++) {
208*2d543d20SAndroid Build Coastguard Worker 		if (data->spec_arr[i].hasMetaChars)
209*2d543d20SAndroid Build Coastguard Worker 			memcpy(&spec_copy[front++], &data->spec_arr[i], len);
210*2d543d20SAndroid Build Coastguard Worker 		else
211*2d543d20SAndroid Build Coastguard Worker 			memcpy(&spec_copy[back--], &data->spec_arr[i], len);
212*2d543d20SAndroid Build Coastguard Worker 	}
213*2d543d20SAndroid Build Coastguard Worker 
214*2d543d20SAndroid Build Coastguard Worker 	/*
215*2d543d20SAndroid Build Coastguard Worker 	 * now the exact pathnames are at the end, but they are in the reverse
216*2d543d20SAndroid Build Coastguard Worker 	 * order. Since 'front' is now the first of the 'exact' we can run
217*2d543d20SAndroid Build Coastguard Worker 	 * that part of the array switching the front and back element.
218*2d543d20SAndroid Build Coastguard Worker 	 */
219*2d543d20SAndroid Build Coastguard Worker 	back = data->nspec - 1;
220*2d543d20SAndroid Build Coastguard Worker 	while (front < back) {
221*2d543d20SAndroid Build Coastguard Worker 		/* save the front */
222*2d543d20SAndroid Build Coastguard Worker 		memcpy(&spec, &spec_copy[front], len);
223*2d543d20SAndroid Build Coastguard Worker 		/* move the back to the front */
224*2d543d20SAndroid Build Coastguard Worker 		memcpy(&spec_copy[front], &spec_copy[back], len);
225*2d543d20SAndroid Build Coastguard Worker 		/* put the old front in the back */
226*2d543d20SAndroid Build Coastguard Worker 		memcpy(&spec_copy[back], &spec, len);
227*2d543d20SAndroid Build Coastguard Worker 		front++;
228*2d543d20SAndroid Build Coastguard Worker 		back--;
229*2d543d20SAndroid Build Coastguard Worker 	}
230*2d543d20SAndroid Build Coastguard Worker 
231*2d543d20SAndroid Build Coastguard Worker 	free(data->spec_arr);
232*2d543d20SAndroid Build Coastguard Worker 	data->spec_arr = spec_copy;
233*2d543d20SAndroid Build Coastguard Worker 
234*2d543d20SAndroid Build Coastguard Worker 	return 0;
235*2d543d20SAndroid Build Coastguard Worker }
236*2d543d20SAndroid Build Coastguard Worker 
237*2d543d20SAndroid Build Coastguard Worker /* Return the length of the text that can be considered the stem, returns 0
238*2d543d20SAndroid Build Coastguard Worker  * if there is no identifiable stem */
get_stem_from_spec(const char * const buf)239*2d543d20SAndroid Build Coastguard Worker static inline int get_stem_from_spec(const char *const buf)
240*2d543d20SAndroid Build Coastguard Worker {
241*2d543d20SAndroid Build Coastguard Worker 	const char *tmp = strchr(buf + 1, '/');
242*2d543d20SAndroid Build Coastguard Worker 	const char *ind;
243*2d543d20SAndroid Build Coastguard Worker 
244*2d543d20SAndroid Build Coastguard Worker 	if (!tmp)
245*2d543d20SAndroid Build Coastguard Worker 		return 0;
246*2d543d20SAndroid Build Coastguard Worker 
247*2d543d20SAndroid Build Coastguard Worker 	for (ind = buf; ind < tmp; ind++) {
248*2d543d20SAndroid Build Coastguard Worker 		if (strchr(".^$?*+|[({", (int)*ind))
249*2d543d20SAndroid Build Coastguard Worker 			return 0;
250*2d543d20SAndroid Build Coastguard Worker 	}
251*2d543d20SAndroid Build Coastguard Worker 	return tmp - buf;
252*2d543d20SAndroid Build Coastguard Worker }
253*2d543d20SAndroid Build Coastguard Worker 
254*2d543d20SAndroid Build Coastguard Worker /*
255*2d543d20SAndroid Build Coastguard Worker  * return the stemid given a string and a length
256*2d543d20SAndroid Build Coastguard Worker  */
find_stem(struct saved_data * data,const char * buf,int stem_len)257*2d543d20SAndroid Build Coastguard Worker static inline int find_stem(struct saved_data *data, const char *buf,
258*2d543d20SAndroid Build Coastguard Worker 						    int stem_len)
259*2d543d20SAndroid Build Coastguard Worker {
260*2d543d20SAndroid Build Coastguard Worker 	int i;
261*2d543d20SAndroid Build Coastguard Worker 
262*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < data->num_stems; i++) {
263*2d543d20SAndroid Build Coastguard Worker 		if (stem_len == data->stem_arr[i].len &&
264*2d543d20SAndroid Build Coastguard Worker 		    !strncmp(buf, data->stem_arr[i].buf, stem_len))
265*2d543d20SAndroid Build Coastguard Worker 			return i;
266*2d543d20SAndroid Build Coastguard Worker 	}
267*2d543d20SAndroid Build Coastguard Worker 
268*2d543d20SAndroid Build Coastguard Worker 	return -1;
269*2d543d20SAndroid Build Coastguard Worker }
270*2d543d20SAndroid Build Coastguard Worker 
271*2d543d20SAndroid Build Coastguard Worker /* returns the index of the new stored object */
store_stem(struct saved_data * data,char * buf,int stem_len)272*2d543d20SAndroid Build Coastguard Worker static inline int store_stem(struct saved_data *data, char *buf, int stem_len)
273*2d543d20SAndroid Build Coastguard Worker {
274*2d543d20SAndroid Build Coastguard Worker 	int num = data->num_stems;
275*2d543d20SAndroid Build Coastguard Worker 
276*2d543d20SAndroid Build Coastguard Worker 	if (data->alloc_stems == num) {
277*2d543d20SAndroid Build Coastguard Worker 		struct stem *tmp_arr;
278*2d543d20SAndroid Build Coastguard Worker 		int alloc_stems = data->alloc_stems * 2 + 16;
279*2d543d20SAndroid Build Coastguard Worker 		tmp_arr = realloc(data->stem_arr,
280*2d543d20SAndroid Build Coastguard Worker 				  sizeof(*tmp_arr) * alloc_stems);
281*2d543d20SAndroid Build Coastguard Worker 		if (!tmp_arr) {
282*2d543d20SAndroid Build Coastguard Worker 			return -1;
283*2d543d20SAndroid Build Coastguard Worker 		}
284*2d543d20SAndroid Build Coastguard Worker 		data->alloc_stems = alloc_stems;
285*2d543d20SAndroid Build Coastguard Worker 		data->stem_arr = tmp_arr;
286*2d543d20SAndroid Build Coastguard Worker 	}
287*2d543d20SAndroid Build Coastguard Worker 	data->stem_arr[num].len = stem_len;
288*2d543d20SAndroid Build Coastguard Worker 	data->stem_arr[num].buf = buf;
289*2d543d20SAndroid Build Coastguard Worker 	data->stem_arr[num].from_mmap = 0;
290*2d543d20SAndroid Build Coastguard Worker 	data->num_stems++;
291*2d543d20SAndroid Build Coastguard Worker 
292*2d543d20SAndroid Build Coastguard Worker 	return num;
293*2d543d20SAndroid Build Coastguard Worker }
294*2d543d20SAndroid Build Coastguard Worker 
295*2d543d20SAndroid Build Coastguard Worker /* find the stem of a file spec, returns the index into stem_arr for a new
296*2d543d20SAndroid Build Coastguard Worker  * or existing stem, (or -1 if there is no possible stem - IE for a file in
297*2d543d20SAndroid Build Coastguard Worker  * the root directory or a regex that is too complex for us). */
find_stem_from_spec(struct saved_data * data,const char * buf)298*2d543d20SAndroid Build Coastguard Worker static inline int find_stem_from_spec(struct saved_data *data, const char *buf)
299*2d543d20SAndroid Build Coastguard Worker {
300*2d543d20SAndroid Build Coastguard Worker 	int stem_len = get_stem_from_spec(buf);
301*2d543d20SAndroid Build Coastguard Worker 	int stemid;
302*2d543d20SAndroid Build Coastguard Worker 	char *stem;
303*2d543d20SAndroid Build Coastguard Worker 	int r;
304*2d543d20SAndroid Build Coastguard Worker 
305*2d543d20SAndroid Build Coastguard Worker 	if (!stem_len)
306*2d543d20SAndroid Build Coastguard Worker 		return -1;
307*2d543d20SAndroid Build Coastguard Worker 
308*2d543d20SAndroid Build Coastguard Worker 	stemid = find_stem(data, buf, stem_len);
309*2d543d20SAndroid Build Coastguard Worker 	if (stemid >= 0)
310*2d543d20SAndroid Build Coastguard Worker 		return stemid;
311*2d543d20SAndroid Build Coastguard Worker 
312*2d543d20SAndroid Build Coastguard Worker 	/* not found, allocate a new one */
313*2d543d20SAndroid Build Coastguard Worker 	stem = strndup(buf, stem_len);
314*2d543d20SAndroid Build Coastguard Worker 	if (!stem)
315*2d543d20SAndroid Build Coastguard Worker 		return -1;
316*2d543d20SAndroid Build Coastguard Worker 
317*2d543d20SAndroid Build Coastguard Worker 	r = store_stem(data, stem, stem_len);
318*2d543d20SAndroid Build Coastguard Worker 	if (r < 0)
319*2d543d20SAndroid Build Coastguard Worker 		free(stem);
320*2d543d20SAndroid Build Coastguard Worker 
321*2d543d20SAndroid Build Coastguard Worker 	return r;
322*2d543d20SAndroid Build Coastguard Worker }
323*2d543d20SAndroid Build Coastguard Worker 
324*2d543d20SAndroid Build Coastguard Worker /* This will always check for buffer over-runs and either read the next entry
325*2d543d20SAndroid Build Coastguard Worker  * if buf != NULL or skip over the entry (as these areas are mapped in the
326*2d543d20SAndroid Build Coastguard Worker  * current buffer). */
next_entry(void * buf,struct mmap_area * fp,size_t bytes)327*2d543d20SAndroid Build Coastguard Worker static inline int next_entry(void *buf, struct mmap_area *fp, size_t bytes)
328*2d543d20SAndroid Build Coastguard Worker {
329*2d543d20SAndroid Build Coastguard Worker 	if (bytes > fp->next_len)
330*2d543d20SAndroid Build Coastguard Worker 		return -1;
331*2d543d20SAndroid Build Coastguard Worker 
332*2d543d20SAndroid Build Coastguard Worker 	if (buf)
333*2d543d20SAndroid Build Coastguard Worker 		memcpy(buf, fp->next_addr, bytes);
334*2d543d20SAndroid Build Coastguard Worker 
335*2d543d20SAndroid Build Coastguard Worker 	fp->next_addr = (char *)fp->next_addr + bytes;
336*2d543d20SAndroid Build Coastguard Worker 	fp->next_len -= bytes;
337*2d543d20SAndroid Build Coastguard Worker 	return 0;
338*2d543d20SAndroid Build Coastguard Worker }
339*2d543d20SAndroid Build Coastguard Worker 
compile_regex(struct spec * spec,const char ** errbuf)340*2d543d20SAndroid Build Coastguard Worker static inline int compile_regex(struct spec *spec, const char **errbuf)
341*2d543d20SAndroid Build Coastguard Worker {
342*2d543d20SAndroid Build Coastguard Worker 	char *reg_buf, *anchored_regex, *cp;
343*2d543d20SAndroid Build Coastguard Worker 	struct regex_error_data error_data;
344*2d543d20SAndroid Build Coastguard Worker 	static char regex_error_format_buffer[256];
345*2d543d20SAndroid Build Coastguard Worker 	size_t len;
346*2d543d20SAndroid Build Coastguard Worker 	int rc;
347*2d543d20SAndroid Build Coastguard Worker 	bool regex_compiled;
348*2d543d20SAndroid Build Coastguard Worker 
349*2d543d20SAndroid Build Coastguard Worker 	/* We really want pthread_once() here, but since its
350*2d543d20SAndroid Build Coastguard Worker 	 * init_routine does not take a parameter, it's not possible
351*2d543d20SAndroid Build Coastguard Worker 	 * to use, so we generate the same effect with atomics and a
352*2d543d20SAndroid Build Coastguard Worker 	 * mutex */
353*2d543d20SAndroid Build Coastguard Worker #ifdef __ATOMIC_RELAXED
354*2d543d20SAndroid Build Coastguard Worker 	regex_compiled =
355*2d543d20SAndroid Build Coastguard Worker 		__atomic_load_n(&spec->regex_compiled, __ATOMIC_ACQUIRE);
356*2d543d20SAndroid Build Coastguard Worker #else
357*2d543d20SAndroid Build Coastguard Worker 	/* GCC <4.7 */
358*2d543d20SAndroid Build Coastguard Worker 	__sync_synchronize();
359*2d543d20SAndroid Build Coastguard Worker 	regex_compiled = spec->regex_compiled;
360*2d543d20SAndroid Build Coastguard Worker #endif
361*2d543d20SAndroid Build Coastguard Worker 	if (regex_compiled) {
362*2d543d20SAndroid Build Coastguard Worker 		return 0; /* already done */
363*2d543d20SAndroid Build Coastguard Worker 	}
364*2d543d20SAndroid Build Coastguard Worker 
365*2d543d20SAndroid Build Coastguard Worker 	__pthread_mutex_lock(&spec->regex_lock);
366*2d543d20SAndroid Build Coastguard Worker 	/* Check if another thread compiled the regex while we waited
367*2d543d20SAndroid Build Coastguard Worker 	 * on the mutex */
368*2d543d20SAndroid Build Coastguard Worker #ifdef __ATOMIC_RELAXED
369*2d543d20SAndroid Build Coastguard Worker 	regex_compiled =
370*2d543d20SAndroid Build Coastguard Worker 		__atomic_load_n(&spec->regex_compiled, __ATOMIC_ACQUIRE);
371*2d543d20SAndroid Build Coastguard Worker #else
372*2d543d20SAndroid Build Coastguard Worker 	/* GCC <4.7 */
373*2d543d20SAndroid Build Coastguard Worker 	__sync_synchronize();
374*2d543d20SAndroid Build Coastguard Worker 	regex_compiled = spec->regex_compiled;
375*2d543d20SAndroid Build Coastguard Worker #endif
376*2d543d20SAndroid Build Coastguard Worker 	if (regex_compiled) {
377*2d543d20SAndroid Build Coastguard Worker 		__pthread_mutex_unlock(&spec->regex_lock);
378*2d543d20SAndroid Build Coastguard Worker 		return 0;
379*2d543d20SAndroid Build Coastguard Worker 	}
380*2d543d20SAndroid Build Coastguard Worker 
381*2d543d20SAndroid Build Coastguard Worker 	reg_buf = spec->regex_str;
382*2d543d20SAndroid Build Coastguard Worker 	/* Anchor the regular expression. */
383*2d543d20SAndroid Build Coastguard Worker 	len = strlen(reg_buf);
384*2d543d20SAndroid Build Coastguard Worker 	cp = anchored_regex = malloc(len + 3);
385*2d543d20SAndroid Build Coastguard Worker 	if (!anchored_regex) {
386*2d543d20SAndroid Build Coastguard Worker 		if (errbuf)
387*2d543d20SAndroid Build Coastguard Worker 			*errbuf = "out of memory";
388*2d543d20SAndroid Build Coastguard Worker 		__pthread_mutex_unlock(&spec->regex_lock);
389*2d543d20SAndroid Build Coastguard Worker 		return -1;
390*2d543d20SAndroid Build Coastguard Worker 	}
391*2d543d20SAndroid Build Coastguard Worker 
392*2d543d20SAndroid Build Coastguard Worker 	/* Create ^...$ regexp.  */
393*2d543d20SAndroid Build Coastguard Worker 	*cp++ = '^';
394*2d543d20SAndroid Build Coastguard Worker 	memcpy(cp, reg_buf, len);
395*2d543d20SAndroid Build Coastguard Worker 	cp += len;
396*2d543d20SAndroid Build Coastguard Worker 	*cp++ = '$';
397*2d543d20SAndroid Build Coastguard Worker 	*cp = '\0';
398*2d543d20SAndroid Build Coastguard Worker 
399*2d543d20SAndroid Build Coastguard Worker 	/* Compile the regular expression. */
400*2d543d20SAndroid Build Coastguard Worker 	rc = regex_prepare_data(&spec->regex, anchored_regex, &error_data);
401*2d543d20SAndroid Build Coastguard Worker 	free(anchored_regex);
402*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0) {
403*2d543d20SAndroid Build Coastguard Worker 		if (errbuf) {
404*2d543d20SAndroid Build Coastguard Worker 			regex_format_error(&error_data,
405*2d543d20SAndroid Build Coastguard Worker 					regex_error_format_buffer,
406*2d543d20SAndroid Build Coastguard Worker 					sizeof(regex_error_format_buffer));
407*2d543d20SAndroid Build Coastguard Worker 			*errbuf = &regex_error_format_buffer[0];
408*2d543d20SAndroid Build Coastguard Worker 		}
409*2d543d20SAndroid Build Coastguard Worker 		__pthread_mutex_unlock(&spec->regex_lock);
410*2d543d20SAndroid Build Coastguard Worker 		errno = EINVAL;
411*2d543d20SAndroid Build Coastguard Worker 		return -1;
412*2d543d20SAndroid Build Coastguard Worker 	}
413*2d543d20SAndroid Build Coastguard Worker 
414*2d543d20SAndroid Build Coastguard Worker 	/* Done. */
415*2d543d20SAndroid Build Coastguard Worker #ifdef __ATOMIC_RELAXED
416*2d543d20SAndroid Build Coastguard Worker 	__atomic_store_n(&spec->regex_compiled, true, __ATOMIC_RELEASE);
417*2d543d20SAndroid Build Coastguard Worker #else
418*2d543d20SAndroid Build Coastguard Worker 	/* GCC <4.7 */
419*2d543d20SAndroid Build Coastguard Worker 	spec->regex_compiled = true;
420*2d543d20SAndroid Build Coastguard Worker 	__sync_synchronize();
421*2d543d20SAndroid Build Coastguard Worker #endif
422*2d543d20SAndroid Build Coastguard Worker 	__pthread_mutex_unlock(&spec->regex_lock);
423*2d543d20SAndroid Build Coastguard Worker 	return 0;
424*2d543d20SAndroid Build Coastguard Worker }
425*2d543d20SAndroid Build Coastguard Worker 
426*2d543d20SAndroid Build Coastguard Worker /* This service is used by label_file.c process_file() and
427*2d543d20SAndroid Build Coastguard Worker  * utils/sefcontext_compile.c */
process_line(struct selabel_handle * rec,const char * path,const char * prefix,char * line_buf,unsigned lineno)428*2d543d20SAndroid Build Coastguard Worker static inline int process_line(struct selabel_handle *rec,
429*2d543d20SAndroid Build Coastguard Worker 			const char *path, const char *prefix,
430*2d543d20SAndroid Build Coastguard Worker 			char *line_buf, unsigned lineno)
431*2d543d20SAndroid Build Coastguard Worker {
432*2d543d20SAndroid Build Coastguard Worker 	int items, len, rc;
433*2d543d20SAndroid Build Coastguard Worker 	char *regex = NULL, *type = NULL, *context = NULL;
434*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data = (struct saved_data *)rec->data;
435*2d543d20SAndroid Build Coastguard Worker 	struct spec *spec_arr;
436*2d543d20SAndroid Build Coastguard Worker 	unsigned int nspec = data->nspec;
437*2d543d20SAndroid Build Coastguard Worker 	const char *errbuf = NULL;
438*2d543d20SAndroid Build Coastguard Worker 
439*2d543d20SAndroid Build Coastguard Worker 	items = read_spec_entries(line_buf, &errbuf, 3, &regex, &type, &context);
440*2d543d20SAndroid Build Coastguard Worker 	if (items < 0) {
441*2d543d20SAndroid Build Coastguard Worker 		if (errbuf) {
442*2d543d20SAndroid Build Coastguard Worker 			selinux_log(SELINUX_ERROR,
443*2d543d20SAndroid Build Coastguard Worker 				    "%s:  line %u error due to: %s\n", path,
444*2d543d20SAndroid Build Coastguard Worker 				    lineno, errbuf);
445*2d543d20SAndroid Build Coastguard Worker 		} else {
446*2d543d20SAndroid Build Coastguard Worker 			selinux_log(SELINUX_ERROR,
447*2d543d20SAndroid Build Coastguard Worker 				    "%s:  line %u error due to: %m\n", path,
448*2d543d20SAndroid Build Coastguard Worker 				    lineno);
449*2d543d20SAndroid Build Coastguard Worker 		}
450*2d543d20SAndroid Build Coastguard Worker 		free(regex);
451*2d543d20SAndroid Build Coastguard Worker 		free(type);
452*2d543d20SAndroid Build Coastguard Worker 		free(context);
453*2d543d20SAndroid Build Coastguard Worker 		return -1;
454*2d543d20SAndroid Build Coastguard Worker 	}
455*2d543d20SAndroid Build Coastguard Worker 
456*2d543d20SAndroid Build Coastguard Worker 	if (items == 0)
457*2d543d20SAndroid Build Coastguard Worker 		return items;
458*2d543d20SAndroid Build Coastguard Worker 
459*2d543d20SAndroid Build Coastguard Worker 	if (items < 2) {
460*2d543d20SAndroid Build Coastguard Worker 		COMPAT_LOG(SELINUX_ERROR,
461*2d543d20SAndroid Build Coastguard Worker 			    "%s:  line %u is missing fields\n", path,
462*2d543d20SAndroid Build Coastguard Worker 			    lineno);
463*2d543d20SAndroid Build Coastguard Worker 		if (items == 1)
464*2d543d20SAndroid Build Coastguard Worker 			free(regex);
465*2d543d20SAndroid Build Coastguard Worker 		errno = EINVAL;
466*2d543d20SAndroid Build Coastguard Worker 		return -1;
467*2d543d20SAndroid Build Coastguard Worker 	} else if (items == 2) {
468*2d543d20SAndroid Build Coastguard Worker 		/* The type field is optional. */
469*2d543d20SAndroid Build Coastguard Worker 		context = type;
470*2d543d20SAndroid Build Coastguard Worker 		type = 0;
471*2d543d20SAndroid Build Coastguard Worker 	}
472*2d543d20SAndroid Build Coastguard Worker 
473*2d543d20SAndroid Build Coastguard Worker 	len = get_stem_from_spec(regex);
474*2d543d20SAndroid Build Coastguard Worker 	if (len && prefix && strncmp(prefix, regex, len)) {
475*2d543d20SAndroid Build Coastguard Worker 		/* Stem of regex does not match requested prefix, discard. */
476*2d543d20SAndroid Build Coastguard Worker 		free(regex);
477*2d543d20SAndroid Build Coastguard Worker 		free(type);
478*2d543d20SAndroid Build Coastguard Worker 		free(context);
479*2d543d20SAndroid Build Coastguard Worker 		return 0;
480*2d543d20SAndroid Build Coastguard Worker 	}
481*2d543d20SAndroid Build Coastguard Worker 
482*2d543d20SAndroid Build Coastguard Worker 	rc = grow_specs(data);
483*2d543d20SAndroid Build Coastguard Worker 	if (rc)
484*2d543d20SAndroid Build Coastguard Worker 		return rc;
485*2d543d20SAndroid Build Coastguard Worker 
486*2d543d20SAndroid Build Coastguard Worker 	spec_arr = data->spec_arr;
487*2d543d20SAndroid Build Coastguard Worker 
488*2d543d20SAndroid Build Coastguard Worker 	/* process and store the specification in spec. */
489*2d543d20SAndroid Build Coastguard Worker 	spec_arr[nspec].stem_id = find_stem_from_spec(data, regex);
490*2d543d20SAndroid Build Coastguard Worker 	spec_arr[nspec].regex_str = regex;
491*2d543d20SAndroid Build Coastguard Worker 	__pthread_mutex_init(&spec_arr[nspec].regex_lock, NULL);
492*2d543d20SAndroid Build Coastguard Worker 	spec_arr[nspec].regex_compiled = false;
493*2d543d20SAndroid Build Coastguard Worker 
494*2d543d20SAndroid Build Coastguard Worker 	spec_arr[nspec].type_str = type;
495*2d543d20SAndroid Build Coastguard Worker 	spec_arr[nspec].mode = 0;
496*2d543d20SAndroid Build Coastguard Worker 
497*2d543d20SAndroid Build Coastguard Worker 	spec_arr[nspec].lr.ctx_raw = context;
498*2d543d20SAndroid Build Coastguard Worker 	spec_arr[nspec].lr.lineno = lineno;
499*2d543d20SAndroid Build Coastguard Worker 
500*2d543d20SAndroid Build Coastguard Worker 	/*
501*2d543d20SAndroid Build Coastguard Worker 	 * bump data->nspecs to cause closef() to cover it in its free
502*2d543d20SAndroid Build Coastguard Worker 	 * but do not bump nspec since it's used below.
503*2d543d20SAndroid Build Coastguard Worker 	 */
504*2d543d20SAndroid Build Coastguard Worker 	data->nspec++;
505*2d543d20SAndroid Build Coastguard Worker 
506*2d543d20SAndroid Build Coastguard Worker 	if (rec->validating
507*2d543d20SAndroid Build Coastguard Worker 			&& compile_regex(&spec_arr[nspec], &errbuf)) {
508*2d543d20SAndroid Build Coastguard Worker 		COMPAT_LOG(SELINUX_ERROR,
509*2d543d20SAndroid Build Coastguard Worker 			   "%s:  line %u has invalid regex %s:  %s\n",
510*2d543d20SAndroid Build Coastguard Worker 			   path, lineno, regex, errbuf);
511*2d543d20SAndroid Build Coastguard Worker 		errno = EINVAL;
512*2d543d20SAndroid Build Coastguard Worker 		return -1;
513*2d543d20SAndroid Build Coastguard Worker 	}
514*2d543d20SAndroid Build Coastguard Worker 
515*2d543d20SAndroid Build Coastguard Worker 	if (type) {
516*2d543d20SAndroid Build Coastguard Worker 		mode_t mode = string_to_mode(type);
517*2d543d20SAndroid Build Coastguard Worker 
518*2d543d20SAndroid Build Coastguard Worker 		if (mode == (mode_t)-1) {
519*2d543d20SAndroid Build Coastguard Worker 			COMPAT_LOG(SELINUX_ERROR,
520*2d543d20SAndroid Build Coastguard Worker 				   "%s:  line %u has invalid file type %s\n",
521*2d543d20SAndroid Build Coastguard Worker 				   path, lineno, type);
522*2d543d20SAndroid Build Coastguard Worker 			errno = EINVAL;
523*2d543d20SAndroid Build Coastguard Worker 			return -1;
524*2d543d20SAndroid Build Coastguard Worker 		}
525*2d543d20SAndroid Build Coastguard Worker 		spec_arr[nspec].mode = mode;
526*2d543d20SAndroid Build Coastguard Worker 	}
527*2d543d20SAndroid Build Coastguard Worker 
528*2d543d20SAndroid Build Coastguard Worker 	/* Determine if specification has
529*2d543d20SAndroid Build Coastguard Worker 	 * any meta characters in the RE */
530*2d543d20SAndroid Build Coastguard Worker 	spec_hasMetaChars(&spec_arr[nspec]);
531*2d543d20SAndroid Build Coastguard Worker 
532*2d543d20SAndroid Build Coastguard Worker 	if (strcmp(context, "<<none>>") && rec->validating)
533*2d543d20SAndroid Build Coastguard Worker 		return compat_validate(rec, &spec_arr[nspec].lr, path, lineno);
534*2d543d20SAndroid Build Coastguard Worker 
535*2d543d20SAndroid Build Coastguard Worker 	return 0;
536*2d543d20SAndroid Build Coastguard Worker }
537*2d543d20SAndroid Build Coastguard Worker 
538*2d543d20SAndroid Build Coastguard Worker #endif /* _SELABEL_FILE_H_ */
539