xref: /aosp_15_r20/external/selinux/libselinux/utils/sefcontext_compile.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1*2d543d20SAndroid Build Coastguard Worker #include <ctype.h>
2*2d543d20SAndroid Build Coastguard Worker #include <errno.h>
3*2d543d20SAndroid Build Coastguard Worker #include <stdint.h>
4*2d543d20SAndroid Build Coastguard Worker #include <stdio.h>
5*2d543d20SAndroid Build Coastguard Worker #include <string.h>
6*2d543d20SAndroid Build Coastguard Worker #include <unistd.h>
7*2d543d20SAndroid Build Coastguard Worker #include <sys/types.h>
8*2d543d20SAndroid Build Coastguard Worker #include <sys/stat.h>
9*2d543d20SAndroid Build Coastguard Worker #include <getopt.h>
10*2d543d20SAndroid Build Coastguard Worker #include <limits.h>
11*2d543d20SAndroid Build Coastguard Worker #include <selinux/selinux.h>
12*2d543d20SAndroid Build Coastguard Worker #include <sepol/sepol.h>
13*2d543d20SAndroid Build Coastguard Worker 
14*2d543d20SAndroid Build Coastguard Worker #include "../src/label_file.h"
15*2d543d20SAndroid Build Coastguard Worker #include "../src/regex.h"
16*2d543d20SAndroid Build Coastguard Worker 
17*2d543d20SAndroid Build Coastguard Worker static const char *policy_file;
18*2d543d20SAndroid Build Coastguard Worker static int ctx_err;
19*2d543d20SAndroid Build Coastguard Worker 
validate_context(char ** ctxp)20*2d543d20SAndroid Build Coastguard Worker static int validate_context(char **ctxp)
21*2d543d20SAndroid Build Coastguard Worker {
22*2d543d20SAndroid Build Coastguard Worker 	char *ctx = *ctxp;
23*2d543d20SAndroid Build Coastguard Worker 
24*2d543d20SAndroid Build Coastguard Worker 	if (policy_file && sepol_check_context(ctx) < 0) {
25*2d543d20SAndroid Build Coastguard Worker 		ctx_err = -1;
26*2d543d20SAndroid Build Coastguard Worker 		return ctx_err;
27*2d543d20SAndroid Build Coastguard Worker 	}
28*2d543d20SAndroid Build Coastguard Worker 
29*2d543d20SAndroid Build Coastguard Worker 	return 0;
30*2d543d20SAndroid Build Coastguard Worker }
31*2d543d20SAndroid Build Coastguard Worker 
process_file(struct selabel_handle * rec,const char * filename)32*2d543d20SAndroid Build Coastguard Worker static int process_file(struct selabel_handle *rec, const char *filename)
33*2d543d20SAndroid Build Coastguard Worker {
34*2d543d20SAndroid Build Coastguard Worker 	unsigned int line_num;
35*2d543d20SAndroid Build Coastguard Worker 	int rc;
36*2d543d20SAndroid Build Coastguard Worker 	char *line_buf = NULL;
37*2d543d20SAndroid Build Coastguard Worker 	size_t line_len = 0;
38*2d543d20SAndroid Build Coastguard Worker 	FILE *context_file;
39*2d543d20SAndroid Build Coastguard Worker 	const char *prefix = NULL;
40*2d543d20SAndroid Build Coastguard Worker 
41*2d543d20SAndroid Build Coastguard Worker 	context_file = fopen(filename, "r");
42*2d543d20SAndroid Build Coastguard Worker 	if (!context_file) {
43*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, "Error opening %s: %s\n",
44*2d543d20SAndroid Build Coastguard Worker 			    filename, strerror(errno));
45*2d543d20SAndroid Build Coastguard Worker 		return -1;
46*2d543d20SAndroid Build Coastguard Worker 	}
47*2d543d20SAndroid Build Coastguard Worker 
48*2d543d20SAndroid Build Coastguard Worker 	line_num = 0;
49*2d543d20SAndroid Build Coastguard Worker 	rc = 0;
50*2d543d20SAndroid Build Coastguard Worker 	while (getline(&line_buf, &line_len, context_file) > 0) {
51*2d543d20SAndroid Build Coastguard Worker 		rc = process_line(rec, filename, prefix, line_buf, ++line_num);
52*2d543d20SAndroid Build Coastguard Worker 		if (rc || ctx_err) {
53*2d543d20SAndroid Build Coastguard Worker 			/* With -p option need to check and fail if ctx err as
54*2d543d20SAndroid Build Coastguard Worker 			 * process_line() context validation on Linux does not
55*2d543d20SAndroid Build Coastguard Worker 			 * return an error, but does print the error line to
56*2d543d20SAndroid Build Coastguard Worker 			 * stderr. Android will set both to error and print
57*2d543d20SAndroid Build Coastguard Worker 			 * the error line. */
58*2d543d20SAndroid Build Coastguard Worker 			rc = -1;
59*2d543d20SAndroid Build Coastguard Worker 			goto out;
60*2d543d20SAndroid Build Coastguard Worker 		}
61*2d543d20SAndroid Build Coastguard Worker 	}
62*2d543d20SAndroid Build Coastguard Worker out:
63*2d543d20SAndroid Build Coastguard Worker 	free(line_buf);
64*2d543d20SAndroid Build Coastguard Worker 	fclose(context_file);
65*2d543d20SAndroid Build Coastguard Worker 	return rc;
66*2d543d20SAndroid Build Coastguard Worker }
67*2d543d20SAndroid Build Coastguard Worker 
68*2d543d20SAndroid Build Coastguard Worker /*
69*2d543d20SAndroid Build Coastguard Worker  * File Format
70*2d543d20SAndroid Build Coastguard Worker  *
71*2d543d20SAndroid Build Coastguard Worker  * u32 - magic number
72*2d543d20SAndroid Build Coastguard Worker  * u32 - version
73*2d543d20SAndroid Build Coastguard Worker  * u32 - length of pcre version EXCLUDING nul
74*2d543d20SAndroid Build Coastguard Worker  * char - pcre version string EXCLUDING nul
75*2d543d20SAndroid Build Coastguard Worker  * u32 - number of stems
76*2d543d20SAndroid Build Coastguard Worker  * ** Stems
77*2d543d20SAndroid Build Coastguard Worker  *	u32  - length of stem EXCLUDING nul
78*2d543d20SAndroid Build Coastguard Worker  *	char - stem char array INCLUDING nul
79*2d543d20SAndroid Build Coastguard Worker  * u32 - number of regexs
80*2d543d20SAndroid Build Coastguard Worker  * ** Regexes
81*2d543d20SAndroid Build Coastguard Worker  *	u32  - length of upcoming context INCLUDING nul
82*2d543d20SAndroid Build Coastguard Worker  *	char - char array of the raw context
83*2d543d20SAndroid Build Coastguard Worker  *	u32  - length of the upcoming regex_str
84*2d543d20SAndroid Build Coastguard Worker  *	char - char array of the original regex string including the stem.
85*2d543d20SAndroid Build Coastguard Worker  *	u32  - mode bits for >= SELINUX_COMPILED_FCONTEXT_MODE
86*2d543d20SAndroid Build Coastguard Worker  *	       mode_t for <= SELINUX_COMPILED_FCONTEXT_PCRE_VERS
87*2d543d20SAndroid Build Coastguard Worker  *	s32  - stemid associated with the regex
88*2d543d20SAndroid Build Coastguard Worker  *	u32  - spec has meta characters
89*2d543d20SAndroid Build Coastguard Worker  *	u32  - The specs prefix_len if >= SELINUX_COMPILED_FCONTEXT_PREFIX_LEN
90*2d543d20SAndroid Build Coastguard Worker  *	u32  - data length of the pcre regex
91*2d543d20SAndroid Build Coastguard Worker  *	char - a buffer holding the raw pcre regex info
92*2d543d20SAndroid Build Coastguard Worker  *	u32  - data length of the pcre regex study daya
93*2d543d20SAndroid Build Coastguard Worker  *	char - a buffer holding the raw pcre regex study data
94*2d543d20SAndroid Build Coastguard Worker  */
write_binary_file(struct saved_data * data,int fd,int do_write_precompregex)95*2d543d20SAndroid Build Coastguard Worker static int write_binary_file(struct saved_data *data, int fd,
96*2d543d20SAndroid Build Coastguard Worker 			     int do_write_precompregex)
97*2d543d20SAndroid Build Coastguard Worker {
98*2d543d20SAndroid Build Coastguard Worker 	struct spec *specs = data->spec_arr;
99*2d543d20SAndroid Build Coastguard Worker 	FILE *bin_file;
100*2d543d20SAndroid Build Coastguard Worker 	size_t len;
101*2d543d20SAndroid Build Coastguard Worker 	uint32_t magic = SELINUX_MAGIC_COMPILED_FCONTEXT;
102*2d543d20SAndroid Build Coastguard Worker 	uint32_t section_len;
103*2d543d20SAndroid Build Coastguard Worker 	uint32_t i;
104*2d543d20SAndroid Build Coastguard Worker 	int rc;
105*2d543d20SAndroid Build Coastguard Worker 	const char *reg_version;
106*2d543d20SAndroid Build Coastguard Worker 	const char *reg_arch;
107*2d543d20SAndroid Build Coastguard Worker 
108*2d543d20SAndroid Build Coastguard Worker 	bin_file = fdopen(fd, "w");
109*2d543d20SAndroid Build Coastguard Worker 	if (!bin_file) {
110*2d543d20SAndroid Build Coastguard Worker 		perror("fopen output_file");
111*2d543d20SAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
112*2d543d20SAndroid Build Coastguard Worker 	}
113*2d543d20SAndroid Build Coastguard Worker 
114*2d543d20SAndroid Build Coastguard Worker 	/* write some magic number */
115*2d543d20SAndroid Build Coastguard Worker 	len = fwrite(&magic, sizeof(uint32_t), 1, bin_file);
116*2d543d20SAndroid Build Coastguard Worker 	if (len != 1)
117*2d543d20SAndroid Build Coastguard Worker 		goto err;
118*2d543d20SAndroid Build Coastguard Worker 
119*2d543d20SAndroid Build Coastguard Worker 	/* write the version */
120*2d543d20SAndroid Build Coastguard Worker 	section_len = SELINUX_COMPILED_FCONTEXT_MAX_VERS;
121*2d543d20SAndroid Build Coastguard Worker 	len = fwrite(&section_len, sizeof(uint32_t), 1, bin_file);
122*2d543d20SAndroid Build Coastguard Worker 	if (len != 1)
123*2d543d20SAndroid Build Coastguard Worker 		goto err;
124*2d543d20SAndroid Build Coastguard Worker 
125*2d543d20SAndroid Build Coastguard Worker 	/* write version of the regex back-end */
126*2d543d20SAndroid Build Coastguard Worker 	reg_version = regex_version();
127*2d543d20SAndroid Build Coastguard Worker 	if (!reg_version)
128*2d543d20SAndroid Build Coastguard Worker 		goto err;
129*2d543d20SAndroid Build Coastguard Worker 	section_len = strlen(reg_version);
130*2d543d20SAndroid Build Coastguard Worker 	len = fwrite(&section_len, sizeof(uint32_t), 1, bin_file);
131*2d543d20SAndroid Build Coastguard Worker 	if (len != 1)
132*2d543d20SAndroid Build Coastguard Worker 		goto err;
133*2d543d20SAndroid Build Coastguard Worker 	len = fwrite(reg_version, sizeof(char), section_len, bin_file);
134*2d543d20SAndroid Build Coastguard Worker 	if (len != section_len)
135*2d543d20SAndroid Build Coastguard Worker 		goto err;
136*2d543d20SAndroid Build Coastguard Worker 
137*2d543d20SAndroid Build Coastguard Worker 	/* write regex arch string */
138*2d543d20SAndroid Build Coastguard Worker 	reg_arch = regex_arch_string();
139*2d543d20SAndroid Build Coastguard Worker 	if (!reg_arch)
140*2d543d20SAndroid Build Coastguard Worker 		goto err;
141*2d543d20SAndroid Build Coastguard Worker 	section_len = strlen(reg_arch);
142*2d543d20SAndroid Build Coastguard Worker 	len = fwrite(&section_len, sizeof(uint32_t), 1, bin_file);
143*2d543d20SAndroid Build Coastguard Worker 	if (len != 1)
144*2d543d20SAndroid Build Coastguard Worker 		goto err;
145*2d543d20SAndroid Build Coastguard Worker 	len = fwrite(reg_arch, sizeof(char), section_len, bin_file);
146*2d543d20SAndroid Build Coastguard Worker 	if (len != section_len)
147*2d543d20SAndroid Build Coastguard Worker 		goto err;
148*2d543d20SAndroid Build Coastguard Worker 
149*2d543d20SAndroid Build Coastguard Worker 	/* write the number of stems coming */
150*2d543d20SAndroid Build Coastguard Worker 	section_len = data->num_stems;
151*2d543d20SAndroid Build Coastguard Worker 	len = fwrite(&section_len, sizeof(uint32_t), 1, bin_file);
152*2d543d20SAndroid Build Coastguard Worker 	if (len != 1)
153*2d543d20SAndroid Build Coastguard Worker 		goto err;
154*2d543d20SAndroid Build Coastguard Worker 
155*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < section_len; i++) {
156*2d543d20SAndroid Build Coastguard Worker 		char *stem = data->stem_arr[i].buf;
157*2d543d20SAndroid Build Coastguard Worker 		uint32_t stem_len = data->stem_arr[i].len;
158*2d543d20SAndroid Build Coastguard Worker 
159*2d543d20SAndroid Build Coastguard Worker 		/* write the strlen (aka no nul) */
160*2d543d20SAndroid Build Coastguard Worker 		len = fwrite(&stem_len, sizeof(uint32_t), 1, bin_file);
161*2d543d20SAndroid Build Coastguard Worker 		if (len != 1)
162*2d543d20SAndroid Build Coastguard Worker 			goto err;
163*2d543d20SAndroid Build Coastguard Worker 
164*2d543d20SAndroid Build Coastguard Worker 		/* include the nul in the file */
165*2d543d20SAndroid Build Coastguard Worker 		stem_len += 1;
166*2d543d20SAndroid Build Coastguard Worker 		len = fwrite(stem, sizeof(char), stem_len, bin_file);
167*2d543d20SAndroid Build Coastguard Worker 		if (len != stem_len)
168*2d543d20SAndroid Build Coastguard Worker 			goto err;
169*2d543d20SAndroid Build Coastguard Worker 	}
170*2d543d20SAndroid Build Coastguard Worker 
171*2d543d20SAndroid Build Coastguard Worker 	/* write the number of regexes coming */
172*2d543d20SAndroid Build Coastguard Worker 	section_len = data->nspec;
173*2d543d20SAndroid Build Coastguard Worker 	len = fwrite(&section_len, sizeof(uint32_t), 1, bin_file);
174*2d543d20SAndroid Build Coastguard Worker 	if (len != 1)
175*2d543d20SAndroid Build Coastguard Worker 		goto err;
176*2d543d20SAndroid Build Coastguard Worker 
177*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < section_len; i++) {
178*2d543d20SAndroid Build Coastguard Worker 		char *context = specs[i].lr.ctx_raw;
179*2d543d20SAndroid Build Coastguard Worker 		char *regex_str = specs[i].regex_str;
180*2d543d20SAndroid Build Coastguard Worker 		mode_t mode = specs[i].mode;
181*2d543d20SAndroid Build Coastguard Worker 		size_t prefix_len = specs[i].prefix_len;
182*2d543d20SAndroid Build Coastguard Worker 		int32_t stem_id = specs[i].stem_id;
183*2d543d20SAndroid Build Coastguard Worker 		struct regex_data *re = specs[i].regex;
184*2d543d20SAndroid Build Coastguard Worker 		uint32_t to_write;
185*2d543d20SAndroid Build Coastguard Worker 
186*2d543d20SAndroid Build Coastguard Worker 		/* length of the context string (including nul) */
187*2d543d20SAndroid Build Coastguard Worker 		to_write = strlen(context) + 1;
188*2d543d20SAndroid Build Coastguard Worker 		len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file);
189*2d543d20SAndroid Build Coastguard Worker 		if (len != 1)
190*2d543d20SAndroid Build Coastguard Worker 			goto err;
191*2d543d20SAndroid Build Coastguard Worker 
192*2d543d20SAndroid Build Coastguard Worker 		/* original context string (including nul) */
193*2d543d20SAndroid Build Coastguard Worker 		len = fwrite(context, sizeof(char), to_write, bin_file);
194*2d543d20SAndroid Build Coastguard Worker 		if (len != to_write)
195*2d543d20SAndroid Build Coastguard Worker 			goto err;
196*2d543d20SAndroid Build Coastguard Worker 
197*2d543d20SAndroid Build Coastguard Worker 		/* length of the original regex string (including nul) */
198*2d543d20SAndroid Build Coastguard Worker 		to_write = strlen(regex_str) + 1;
199*2d543d20SAndroid Build Coastguard Worker 		len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file);
200*2d543d20SAndroid Build Coastguard Worker 		if (len != 1)
201*2d543d20SAndroid Build Coastguard Worker 			goto err;
202*2d543d20SAndroid Build Coastguard Worker 
203*2d543d20SAndroid Build Coastguard Worker 		/* original regex string */
204*2d543d20SAndroid Build Coastguard Worker 		len = fwrite(regex_str, sizeof(char), to_write, bin_file);
205*2d543d20SAndroid Build Coastguard Worker 		if (len != to_write)
206*2d543d20SAndroid Build Coastguard Worker 			goto err;
207*2d543d20SAndroid Build Coastguard Worker 
208*2d543d20SAndroid Build Coastguard Worker 		/* binary F_MODE bits */
209*2d543d20SAndroid Build Coastguard Worker 		to_write = mode;
210*2d543d20SAndroid Build Coastguard Worker 		len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file);
211*2d543d20SAndroid Build Coastguard Worker 		if (len != 1)
212*2d543d20SAndroid Build Coastguard Worker 			goto err;
213*2d543d20SAndroid Build Coastguard Worker 
214*2d543d20SAndroid Build Coastguard Worker 		/* stem for this regex (could be -1) */
215*2d543d20SAndroid Build Coastguard Worker 		len = fwrite(&stem_id, sizeof(stem_id), 1, bin_file);
216*2d543d20SAndroid Build Coastguard Worker 		if (len != 1)
217*2d543d20SAndroid Build Coastguard Worker 			goto err;
218*2d543d20SAndroid Build Coastguard Worker 
219*2d543d20SAndroid Build Coastguard Worker 		/* does this spec have a metaChar? */
220*2d543d20SAndroid Build Coastguard Worker 		to_write = specs[i].hasMetaChars;
221*2d543d20SAndroid Build Coastguard Worker 		len = fwrite(&to_write, sizeof(to_write), 1, bin_file);
222*2d543d20SAndroid Build Coastguard Worker 		if (len != 1)
223*2d543d20SAndroid Build Coastguard Worker 			goto err;
224*2d543d20SAndroid Build Coastguard Worker 
225*2d543d20SAndroid Build Coastguard Worker 		/* For SELINUX_COMPILED_FCONTEXT_PREFIX_LEN */
226*2d543d20SAndroid Build Coastguard Worker 		to_write = prefix_len;
227*2d543d20SAndroid Build Coastguard Worker 		len = fwrite(&to_write, sizeof(to_write), 1, bin_file);
228*2d543d20SAndroid Build Coastguard Worker 		if (len != 1)
229*2d543d20SAndroid Build Coastguard Worker 			goto err;
230*2d543d20SAndroid Build Coastguard Worker 
231*2d543d20SAndroid Build Coastguard Worker 		/* Write regex related data */
232*2d543d20SAndroid Build Coastguard Worker 		rc = regex_writef(re, bin_file, do_write_precompregex);
233*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0)
234*2d543d20SAndroid Build Coastguard Worker 			goto err;
235*2d543d20SAndroid Build Coastguard Worker 	}
236*2d543d20SAndroid Build Coastguard Worker 
237*2d543d20SAndroid Build Coastguard Worker 	rc = 0;
238*2d543d20SAndroid Build Coastguard Worker out:
239*2d543d20SAndroid Build Coastguard Worker 	fclose(bin_file);
240*2d543d20SAndroid Build Coastguard Worker 	return rc;
241*2d543d20SAndroid Build Coastguard Worker err:
242*2d543d20SAndroid Build Coastguard Worker 	rc = -1;
243*2d543d20SAndroid Build Coastguard Worker 	goto out;
244*2d543d20SAndroid Build Coastguard Worker }
245*2d543d20SAndroid Build Coastguard Worker 
free_specs(struct saved_data * data)246*2d543d20SAndroid Build Coastguard Worker static void free_specs(struct saved_data *data)
247*2d543d20SAndroid Build Coastguard Worker {
248*2d543d20SAndroid Build Coastguard Worker 	struct spec *specs = data->spec_arr;
249*2d543d20SAndroid Build Coastguard Worker 	unsigned int num_entries = data->nspec;
250*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
251*2d543d20SAndroid Build Coastguard Worker 
252*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < num_entries; i++) {
253*2d543d20SAndroid Build Coastguard Worker 		free(specs[i].lr.ctx_raw);
254*2d543d20SAndroid Build Coastguard Worker 		free(specs[i].lr.ctx_trans);
255*2d543d20SAndroid Build Coastguard Worker 		free(specs[i].regex_str);
256*2d543d20SAndroid Build Coastguard Worker 		free(specs[i].type_str);
257*2d543d20SAndroid Build Coastguard Worker 		regex_data_free(specs[i].regex);
258*2d543d20SAndroid Build Coastguard Worker 	}
259*2d543d20SAndroid Build Coastguard Worker 	free(specs);
260*2d543d20SAndroid Build Coastguard Worker 
261*2d543d20SAndroid Build Coastguard Worker 	num_entries = data->num_stems;
262*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < num_entries; i++)
263*2d543d20SAndroid Build Coastguard Worker 		free(data->stem_arr[i].buf);
264*2d543d20SAndroid Build Coastguard Worker 	free(data->stem_arr);
265*2d543d20SAndroid Build Coastguard Worker 
266*2d543d20SAndroid Build Coastguard Worker 	memset(data, 0, sizeof(*data));
267*2d543d20SAndroid Build Coastguard Worker }
268*2d543d20SAndroid Build Coastguard Worker 
usage(const char * progname)269*2d543d20SAndroid Build Coastguard Worker static __attribute__ ((__noreturn__)) void usage(const char *progname)
270*2d543d20SAndroid Build Coastguard Worker {
271*2d543d20SAndroid Build Coastguard Worker 	fprintf(stderr,
272*2d543d20SAndroid Build Coastguard Worker 	    "usage: %s [-o out_file] [-p policy_file] fc_file\n"
273*2d543d20SAndroid Build Coastguard Worker 	    "Where:\n\t"
274*2d543d20SAndroid Build Coastguard Worker 	    "-o       Optional file name of the PCRE formatted binary\n\t"
275*2d543d20SAndroid Build Coastguard Worker 	    "         file to be output. If not specified the default\n\t"
276*2d543d20SAndroid Build Coastguard Worker 	    "         will be fc_file with the .bin suffix appended.\n\t"
277*2d543d20SAndroid Build Coastguard Worker 	    "-p       Optional binary policy file that will be used to\n\t"
278*2d543d20SAndroid Build Coastguard Worker 	    "         validate contexts defined in the fc_file.\n\t"
279*2d543d20SAndroid Build Coastguard Worker 	    "-r       Omit precompiled regular expressions from the output.\n\t"
280*2d543d20SAndroid Build Coastguard Worker 	    "         (PCRE2 only. Compiled PCRE2 regular expressions are\n\t"
281*2d543d20SAndroid Build Coastguard Worker 	    "         not portable across architectures. Use this flag\n\t"
282*2d543d20SAndroid Build Coastguard Worker 	    "         if you know that you build for an incompatible\n\t"
283*2d543d20SAndroid Build Coastguard Worker 	    "         architecture to save space. When linked against\n\t"
284*2d543d20SAndroid Build Coastguard Worker 	    "         PCRE1 this flag is ignored.)\n\t"
285*2d543d20SAndroid Build Coastguard Worker 	    "-i       Print regular expression info end exit. That is, back\n\t"
286*2d543d20SAndroid Build Coastguard Worker 	    "         end version and architecture identifier.\n\t"
287*2d543d20SAndroid Build Coastguard Worker 	    "         Arch identifier format (PCRE2):\n\t"
288*2d543d20SAndroid Build Coastguard Worker 	    "         <pointer width>-<size type width>-<endianness>, e.g.,\n\t"
289*2d543d20SAndroid Build Coastguard Worker 	    "         \"8-8-el\" for x86_64.\n\t"
290*2d543d20SAndroid Build Coastguard Worker 	    "fc_file  The text based file contexts file to be processed.\n",
291*2d543d20SAndroid Build Coastguard Worker 	    progname);
292*2d543d20SAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
293*2d543d20SAndroid Build Coastguard Worker }
294*2d543d20SAndroid Build Coastguard Worker 
main(int argc,char * argv[])295*2d543d20SAndroid Build Coastguard Worker int main(int argc, char *argv[])
296*2d543d20SAndroid Build Coastguard Worker {
297*2d543d20SAndroid Build Coastguard Worker 	const char *path = NULL;
298*2d543d20SAndroid Build Coastguard Worker 	const char *out_file = NULL;
299*2d543d20SAndroid Build Coastguard Worker 	int do_write_precompregex = 1;
300*2d543d20SAndroid Build Coastguard Worker 	char stack_path[PATH_MAX + 1];
301*2d543d20SAndroid Build Coastguard Worker 	char *tmp = NULL;
302*2d543d20SAndroid Build Coastguard Worker 	int fd, rc, opt;
303*2d543d20SAndroid Build Coastguard Worker 	FILE *policy_fp = NULL;
304*2d543d20SAndroid Build Coastguard Worker 	struct stat buf;
305*2d543d20SAndroid Build Coastguard Worker 	struct selabel_handle *rec = NULL;
306*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data = NULL;
307*2d543d20SAndroid Build Coastguard Worker 
308*2d543d20SAndroid Build Coastguard Worker 	if (argc < 2)
309*2d543d20SAndroid Build Coastguard Worker 		usage(argv[0]);
310*2d543d20SAndroid Build Coastguard Worker 
311*2d543d20SAndroid Build Coastguard Worker 	while ((opt = getopt(argc, argv, "io:p:r")) > 0) {
312*2d543d20SAndroid Build Coastguard Worker 		switch (opt) {
313*2d543d20SAndroid Build Coastguard Worker 		case 'o':
314*2d543d20SAndroid Build Coastguard Worker 			out_file = optarg;
315*2d543d20SAndroid Build Coastguard Worker 			break;
316*2d543d20SAndroid Build Coastguard Worker 		case 'p':
317*2d543d20SAndroid Build Coastguard Worker 			policy_file = optarg;
318*2d543d20SAndroid Build Coastguard Worker 			break;
319*2d543d20SAndroid Build Coastguard Worker 		case 'r':
320*2d543d20SAndroid Build Coastguard Worker 			do_write_precompregex = 0;
321*2d543d20SAndroid Build Coastguard Worker 			break;
322*2d543d20SAndroid Build Coastguard Worker 		case 'i':
323*2d543d20SAndroid Build Coastguard Worker 			printf("%s (%s)\n", regex_version(),
324*2d543d20SAndroid Build Coastguard Worker 					regex_arch_string());
325*2d543d20SAndroid Build Coastguard Worker 			return 0;
326*2d543d20SAndroid Build Coastguard Worker 		default:
327*2d543d20SAndroid Build Coastguard Worker 			usage(argv[0]);
328*2d543d20SAndroid Build Coastguard Worker 		}
329*2d543d20SAndroid Build Coastguard Worker 	}
330*2d543d20SAndroid Build Coastguard Worker 
331*2d543d20SAndroid Build Coastguard Worker 	if (optind >= argc)
332*2d543d20SAndroid Build Coastguard Worker 		usage(argv[0]);
333*2d543d20SAndroid Build Coastguard Worker 
334*2d543d20SAndroid Build Coastguard Worker 	path = argv[optind];
335*2d543d20SAndroid Build Coastguard Worker 	if (stat(path, &buf) < 0) {
336*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, "%s: could not stat: %s: %s\n", argv[0], path, strerror(errno));
337*2d543d20SAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
338*2d543d20SAndroid Build Coastguard Worker 	}
339*2d543d20SAndroid Build Coastguard Worker 
340*2d543d20SAndroid Build Coastguard Worker 	/* Open binary policy if supplied. */
341*2d543d20SAndroid Build Coastguard Worker 	if (policy_file) {
342*2d543d20SAndroid Build Coastguard Worker 		policy_fp = fopen(policy_file, "r");
343*2d543d20SAndroid Build Coastguard Worker 
344*2d543d20SAndroid Build Coastguard Worker 		if (!policy_fp) {
345*2d543d20SAndroid Build Coastguard Worker 			fprintf(stderr, "%s: failed to open %s: %s\n",
346*2d543d20SAndroid Build Coastguard Worker 				argv[0], policy_file, strerror(errno));
347*2d543d20SAndroid Build Coastguard Worker 			exit(EXIT_FAILURE);
348*2d543d20SAndroid Build Coastguard Worker 		}
349*2d543d20SAndroid Build Coastguard Worker 
350*2d543d20SAndroid Build Coastguard Worker 		if (sepol_set_policydb_from_file(policy_fp) < 0) {
351*2d543d20SAndroid Build Coastguard Worker 			fprintf(stderr, "%s: failed to load policy from %s\n",
352*2d543d20SAndroid Build Coastguard Worker 				argv[0], policy_file);
353*2d543d20SAndroid Build Coastguard Worker 			fclose(policy_fp);
354*2d543d20SAndroid Build Coastguard Worker 			exit(EXIT_FAILURE);
355*2d543d20SAndroid Build Coastguard Worker 		}
356*2d543d20SAndroid Build Coastguard Worker 	}
357*2d543d20SAndroid Build Coastguard Worker 
358*2d543d20SAndroid Build Coastguard Worker 	/* Generate dummy handle for process_line() function */
359*2d543d20SAndroid Build Coastguard Worker 	rec = (struct selabel_handle *)calloc(1, sizeof(*rec));
360*2d543d20SAndroid Build Coastguard Worker 	if (!rec) {
361*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, "%s: calloc failed: %s\n", argv[0], strerror(errno));
362*2d543d20SAndroid Build Coastguard Worker 		if (policy_fp)
363*2d543d20SAndroid Build Coastguard Worker 			fclose(policy_fp);
364*2d543d20SAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
365*2d543d20SAndroid Build Coastguard Worker 	}
366*2d543d20SAndroid Build Coastguard Worker 	rec->backend = SELABEL_CTX_FILE;
367*2d543d20SAndroid Build Coastguard Worker 
368*2d543d20SAndroid Build Coastguard Worker 	/* Need to set validation on to get the bin file generated by the
369*2d543d20SAndroid Build Coastguard Worker 	 * process_line function, however as the bin file being generated
370*2d543d20SAndroid Build Coastguard Worker 	 * may not be related to the currently loaded policy (that it
371*2d543d20SAndroid Build Coastguard Worker 	 * would be validated against), then set callback to ignore any
372*2d543d20SAndroid Build Coastguard Worker 	 * validation - unless the -p option is used in which case if an
373*2d543d20SAndroid Build Coastguard Worker 	 * error is detected, the process will be aborted. */
374*2d543d20SAndroid Build Coastguard Worker 	rec->validating = 1;
375*2d543d20SAndroid Build Coastguard Worker 	selinux_set_callback(SELINUX_CB_VALIDATE,
376*2d543d20SAndroid Build Coastguard Worker 			    (union selinux_callback)&validate_context);
377*2d543d20SAndroid Build Coastguard Worker 
378*2d543d20SAndroid Build Coastguard Worker 	data = (struct saved_data *)calloc(1, sizeof(*data));
379*2d543d20SAndroid Build Coastguard Worker 	if (!data) {
380*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, "%s: calloc failed: %s\n", argv[0], strerror(errno));
381*2d543d20SAndroid Build Coastguard Worker 		free(rec);
382*2d543d20SAndroid Build Coastguard Worker 		if (policy_fp)
383*2d543d20SAndroid Build Coastguard Worker 			fclose(policy_fp);
384*2d543d20SAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
385*2d543d20SAndroid Build Coastguard Worker 	}
386*2d543d20SAndroid Build Coastguard Worker 
387*2d543d20SAndroid Build Coastguard Worker 	rec->data = data;
388*2d543d20SAndroid Build Coastguard Worker 
389*2d543d20SAndroid Build Coastguard Worker 	rc = process_file(rec, path);
390*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0) {
391*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, "%s: process_file failed\n", argv[0]);
392*2d543d20SAndroid Build Coastguard Worker 		goto err;
393*2d543d20SAndroid Build Coastguard Worker 	}
394*2d543d20SAndroid Build Coastguard Worker 
395*2d543d20SAndroid Build Coastguard Worker 	rc = sort_specs(data);
396*2d543d20SAndroid Build Coastguard Worker 	if (rc) {
397*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, "%s: sort_specs failed\n", argv[0]);
398*2d543d20SAndroid Build Coastguard Worker 		goto err;
399*2d543d20SAndroid Build Coastguard Worker 	}
400*2d543d20SAndroid Build Coastguard Worker 
401*2d543d20SAndroid Build Coastguard Worker 	if (out_file)
402*2d543d20SAndroid Build Coastguard Worker 		rc = snprintf(stack_path, sizeof(stack_path), "%s", out_file);
403*2d543d20SAndroid Build Coastguard Worker 	else
404*2d543d20SAndroid Build Coastguard Worker 		rc = snprintf(stack_path, sizeof(stack_path), "%s.bin", path);
405*2d543d20SAndroid Build Coastguard Worker 
406*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0 || rc >= (int)sizeof(stack_path)) {
407*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, "%s: snprintf failed\n", argv[0]);
408*2d543d20SAndroid Build Coastguard Worker 		goto err;
409*2d543d20SAndroid Build Coastguard Worker 	}
410*2d543d20SAndroid Build Coastguard Worker 
411*2d543d20SAndroid Build Coastguard Worker 	tmp = malloc(strlen(stack_path) + 7);
412*2d543d20SAndroid Build Coastguard Worker 	if (!tmp) {
413*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, "%s: malloc failed: %s\n", argv[0], strerror(errno));
414*2d543d20SAndroid Build Coastguard Worker 		goto err;
415*2d543d20SAndroid Build Coastguard Worker 	}
416*2d543d20SAndroid Build Coastguard Worker 
417*2d543d20SAndroid Build Coastguard Worker 	rc = sprintf(tmp, "%sXXXXXX", stack_path);
418*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0) {
419*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, "%s: sprintf failed\n", argv[0]);
420*2d543d20SAndroid Build Coastguard Worker 		goto err;
421*2d543d20SAndroid Build Coastguard Worker 	}
422*2d543d20SAndroid Build Coastguard Worker 
423*2d543d20SAndroid Build Coastguard Worker 	fd  = mkstemp(tmp);
424*2d543d20SAndroid Build Coastguard Worker 	if (fd < 0) {
425*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, "%s: mkstemp %s failed: %s\n", argv[0], tmp, strerror(errno));
426*2d543d20SAndroid Build Coastguard Worker 		goto err;
427*2d543d20SAndroid Build Coastguard Worker 	}
428*2d543d20SAndroid Build Coastguard Worker 
429*2d543d20SAndroid Build Coastguard Worker 	rc = fchmod(fd, buf.st_mode);
430*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0) {
431*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, "%s: fchmod %s failed: %s\n", argv[0], tmp, strerror(errno));
432*2d543d20SAndroid Build Coastguard Worker 		goto err_unlink;
433*2d543d20SAndroid Build Coastguard Worker 	}
434*2d543d20SAndroid Build Coastguard Worker 
435*2d543d20SAndroid Build Coastguard Worker 	rc = write_binary_file(data, fd, do_write_precompregex);
436*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0) {
437*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, "%s: write_binary_file %s failed\n", argv[0], tmp);
438*2d543d20SAndroid Build Coastguard Worker 		goto err_unlink;
439*2d543d20SAndroid Build Coastguard Worker 	}
440*2d543d20SAndroid Build Coastguard Worker 
441*2d543d20SAndroid Build Coastguard Worker 	rc = rename(tmp, stack_path);
442*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0) {
443*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, "%s: rename %s -> %s failed: %s\n", argv[0], tmp, stack_path, strerror(errno));
444*2d543d20SAndroid Build Coastguard Worker 		goto err_unlink;
445*2d543d20SAndroid Build Coastguard Worker 	}
446*2d543d20SAndroid Build Coastguard Worker 
447*2d543d20SAndroid Build Coastguard Worker 	rc = 0;
448*2d543d20SAndroid Build Coastguard Worker out:
449*2d543d20SAndroid Build Coastguard Worker 	if (policy_fp)
450*2d543d20SAndroid Build Coastguard Worker 		fclose(policy_fp);
451*2d543d20SAndroid Build Coastguard Worker 
452*2d543d20SAndroid Build Coastguard Worker 	free_specs(data);
453*2d543d20SAndroid Build Coastguard Worker 	free(rec);
454*2d543d20SAndroid Build Coastguard Worker 	free(data);
455*2d543d20SAndroid Build Coastguard Worker 	free(tmp);
456*2d543d20SAndroid Build Coastguard Worker 	return rc;
457*2d543d20SAndroid Build Coastguard Worker 
458*2d543d20SAndroid Build Coastguard Worker err_unlink:
459*2d543d20SAndroid Build Coastguard Worker 	unlink(tmp);
460*2d543d20SAndroid Build Coastguard Worker err:
461*2d543d20SAndroid Build Coastguard Worker 	rc = -1;
462*2d543d20SAndroid Build Coastguard Worker 	goto out;
463*2d543d20SAndroid Build Coastguard Worker }
464