xref: /aosp_15_r20/external/selinux/checkpolicy/fuzz/checkpolicy-fuzzer.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1*2d543d20SAndroid Build Coastguard Worker #include <assert.h>
2*2d543d20SAndroid Build Coastguard Worker #include <setjmp.h>
3*2d543d20SAndroid Build Coastguard Worker #include <unistd.h>
4*2d543d20SAndroid Build Coastguard Worker #include <sys/mman.h>
5*2d543d20SAndroid Build Coastguard Worker 
6*2d543d20SAndroid Build Coastguard Worker #include <sepol/debug.h>
7*2d543d20SAndroid Build Coastguard Worker #include <sepol/kernel_to_cil.h>
8*2d543d20SAndroid Build Coastguard Worker #include <sepol/kernel_to_conf.h>
9*2d543d20SAndroid Build Coastguard Worker #include <sepol/module_to_cil.h>
10*2d543d20SAndroid Build Coastguard Worker #include <sepol/policydb/policydb.h>
11*2d543d20SAndroid Build Coastguard Worker #include <sepol/policydb/hierarchy.h>
12*2d543d20SAndroid Build Coastguard Worker #include <sepol/policydb/expand.h>
13*2d543d20SAndroid Build Coastguard Worker #include <sepol/policydb/link.h>
14*2d543d20SAndroid Build Coastguard Worker 
15*2d543d20SAndroid Build Coastguard Worker #include "module_compiler.h"
16*2d543d20SAndroid Build Coastguard Worker #include "queue.h"
17*2d543d20SAndroid Build Coastguard Worker 
18*2d543d20SAndroid Build Coastguard Worker extern int policydb_validate(sepol_handle_t *handle, const policydb_t *p);
19*2d543d20SAndroid Build Coastguard Worker extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
20*2d543d20SAndroid Build Coastguard Worker 
21*2d543d20SAndroid Build Coastguard Worker extern int mlspol;
22*2d543d20SAndroid Build Coastguard Worker extern policydb_t *policydbp;
23*2d543d20SAndroid Build Coastguard Worker extern queue_t id_queue;
24*2d543d20SAndroid Build Coastguard Worker extern unsigned int policydb_errors;
25*2d543d20SAndroid Build Coastguard Worker 
26*2d543d20SAndroid Build Coastguard Worker extern int yynerrs;
27*2d543d20SAndroid Build Coastguard Worker extern FILE *yyin;
28*2d543d20SAndroid Build Coastguard Worker extern void init_parser(int);
29*2d543d20SAndroid Build Coastguard Worker extern int yyparse(void);
30*2d543d20SAndroid Build Coastguard Worker extern void yyrestart(FILE *);
31*2d543d20SAndroid Build Coastguard Worker extern int yylex_destroy(void);
32*2d543d20SAndroid Build Coastguard Worker extern void set_source_file(const char *name);
33*2d543d20SAndroid Build Coastguard Worker 
34*2d543d20SAndroid Build Coastguard Worker jmp_buf fuzzing_pre_parse_stack_state;
35*2d543d20SAndroid Build Coastguard Worker 
36*2d543d20SAndroid Build Coastguard Worker // Set to 1 for verbose libsepol logging
37*2d543d20SAndroid Build Coastguard Worker #define VERBOSE 0
38*2d543d20SAndroid Build Coastguard Worker 
full_write(int fd,const void * buf,size_t count)39*2d543d20SAndroid Build Coastguard Worker static ssize_t full_write(int fd, const void *buf, size_t count)
40*2d543d20SAndroid Build Coastguard Worker {
41*2d543d20SAndroid Build Coastguard Worker 	ssize_t written = 0;
42*2d543d20SAndroid Build Coastguard Worker 
43*2d543d20SAndroid Build Coastguard Worker 	while (count > 0) {
44*2d543d20SAndroid Build Coastguard Worker 		ssize_t ret = write(fd, buf, count);
45*2d543d20SAndroid Build Coastguard Worker 		if (ret < 0) {
46*2d543d20SAndroid Build Coastguard Worker 			if (errno == EINTR)
47*2d543d20SAndroid Build Coastguard Worker 				continue;
48*2d543d20SAndroid Build Coastguard Worker 
49*2d543d20SAndroid Build Coastguard Worker 			return ret;
50*2d543d20SAndroid Build Coastguard Worker 		}
51*2d543d20SAndroid Build Coastguard Worker 
52*2d543d20SAndroid Build Coastguard Worker 		if (ret == 0)
53*2d543d20SAndroid Build Coastguard Worker 			break;
54*2d543d20SAndroid Build Coastguard Worker 
55*2d543d20SAndroid Build Coastguard Worker 		written += ret;
56*2d543d20SAndroid Build Coastguard Worker 		buf = (const unsigned char *)buf + (size_t)ret;
57*2d543d20SAndroid Build Coastguard Worker 		count -= (size_t)ret;
58*2d543d20SAndroid Build Coastguard Worker 	}
59*2d543d20SAndroid Build Coastguard Worker 
60*2d543d20SAndroid Build Coastguard Worker 	return written;
61*2d543d20SAndroid Build Coastguard Worker }
62*2d543d20SAndroid Build Coastguard Worker 
read_source_policy(policydb_t * p,const uint8_t * data,size_t size)63*2d543d20SAndroid Build Coastguard Worker static int read_source_policy(policydb_t *p, const uint8_t *data, size_t size)
64*2d543d20SAndroid Build Coastguard Worker {
65*2d543d20SAndroid Build Coastguard Worker 	int fd, rc;
66*2d543d20SAndroid Build Coastguard Worker 	ssize_t wr;
67*2d543d20SAndroid Build Coastguard Worker 
68*2d543d20SAndroid Build Coastguard Worker 	fd = memfd_create("fuzz-input", MFD_CLOEXEC);
69*2d543d20SAndroid Build Coastguard Worker 	if (fd < 0)
70*2d543d20SAndroid Build Coastguard Worker 		return -1;
71*2d543d20SAndroid Build Coastguard Worker 
72*2d543d20SAndroid Build Coastguard Worker 	wr = full_write(fd, data, size);
73*2d543d20SAndroid Build Coastguard Worker 	if (wr < 0 || (size_t)wr != size) {
74*2d543d20SAndroid Build Coastguard Worker 		close(fd);
75*2d543d20SAndroid Build Coastguard Worker 		return -1;
76*2d543d20SAndroid Build Coastguard Worker 	}
77*2d543d20SAndroid Build Coastguard Worker 
78*2d543d20SAndroid Build Coastguard Worker 	fsync(fd);
79*2d543d20SAndroid Build Coastguard Worker 
80*2d543d20SAndroid Build Coastguard Worker 	yynerrs = 0;
81*2d543d20SAndroid Build Coastguard Worker 
82*2d543d20SAndroid Build Coastguard Worker 	yyin = fdopen(fd, "r");
83*2d543d20SAndroid Build Coastguard Worker 	if (!yyin) {
84*2d543d20SAndroid Build Coastguard Worker 		close(fd);
85*2d543d20SAndroid Build Coastguard Worker 		return -1;
86*2d543d20SAndroid Build Coastguard Worker 	}
87*2d543d20SAndroid Build Coastguard Worker 
88*2d543d20SAndroid Build Coastguard Worker 	rewind(yyin);
89*2d543d20SAndroid Build Coastguard Worker 
90*2d543d20SAndroid Build Coastguard Worker 	set_source_file("fuzz-input");
91*2d543d20SAndroid Build Coastguard Worker 
92*2d543d20SAndroid Build Coastguard Worker 	id_queue = queue_create();
93*2d543d20SAndroid Build Coastguard Worker 	if (id_queue == NULL) {
94*2d543d20SAndroid Build Coastguard Worker 		fclose(yyin);
95*2d543d20SAndroid Build Coastguard Worker 		yylex_destroy();
96*2d543d20SAndroid Build Coastguard Worker 		return -1;
97*2d543d20SAndroid Build Coastguard Worker 	}
98*2d543d20SAndroid Build Coastguard Worker 
99*2d543d20SAndroid Build Coastguard Worker 	policydbp = p;
100*2d543d20SAndroid Build Coastguard Worker 	mlspol = p->mls;
101*2d543d20SAndroid Build Coastguard Worker 
102*2d543d20SAndroid Build Coastguard Worker 	init_parser(1);
103*2d543d20SAndroid Build Coastguard Worker 
104*2d543d20SAndroid Build Coastguard Worker 	if (setjmp(fuzzing_pre_parse_stack_state) != 0) {
105*2d543d20SAndroid Build Coastguard Worker 		queue_destroy(id_queue);
106*2d543d20SAndroid Build Coastguard Worker 		fclose(yyin);
107*2d543d20SAndroid Build Coastguard Worker 		yylex_destroy();
108*2d543d20SAndroid Build Coastguard Worker 		return -1;
109*2d543d20SAndroid Build Coastguard Worker 	}
110*2d543d20SAndroid Build Coastguard Worker 
111*2d543d20SAndroid Build Coastguard Worker 	rc = yyparse();
112*2d543d20SAndroid Build Coastguard Worker 	// TODO: drop global variable policydb_errors if proven to be redundant
113*2d543d20SAndroid Build Coastguard Worker 	assert(rc || !policydb_errors);
114*2d543d20SAndroid Build Coastguard Worker 	if (rc || policydb_errors) {
115*2d543d20SAndroid Build Coastguard Worker 		queue_destroy(id_queue);
116*2d543d20SAndroid Build Coastguard Worker 		fclose(yyin);
117*2d543d20SAndroid Build Coastguard Worker 		yylex_destroy();
118*2d543d20SAndroid Build Coastguard Worker 		return -1;
119*2d543d20SAndroid Build Coastguard Worker 	}
120*2d543d20SAndroid Build Coastguard Worker 
121*2d543d20SAndroid Build Coastguard Worker 	rewind(yyin);
122*2d543d20SAndroid Build Coastguard Worker 	init_parser(2);
123*2d543d20SAndroid Build Coastguard Worker 	set_source_file("fuzz-input");
124*2d543d20SAndroid Build Coastguard Worker 	yyrestart(yyin);
125*2d543d20SAndroid Build Coastguard Worker 
126*2d543d20SAndroid Build Coastguard Worker 	rc = yyparse();
127*2d543d20SAndroid Build Coastguard Worker 	assert(rc || !policydb_errors);
128*2d543d20SAndroid Build Coastguard Worker 	if (rc || policydb_errors) {
129*2d543d20SAndroid Build Coastguard Worker 		queue_destroy(id_queue);
130*2d543d20SAndroid Build Coastguard Worker 		fclose(yyin);
131*2d543d20SAndroid Build Coastguard Worker 		yylex_destroy();
132*2d543d20SAndroid Build Coastguard Worker 		return -1;
133*2d543d20SAndroid Build Coastguard Worker 	}
134*2d543d20SAndroid Build Coastguard Worker 
135*2d543d20SAndroid Build Coastguard Worker 	queue_destroy(id_queue);
136*2d543d20SAndroid Build Coastguard Worker 	fclose(yyin);
137*2d543d20SAndroid Build Coastguard Worker 	yylex_destroy();
138*2d543d20SAndroid Build Coastguard Worker 
139*2d543d20SAndroid Build Coastguard Worker 	return 0;
140*2d543d20SAndroid Build Coastguard Worker }
141*2d543d20SAndroid Build Coastguard Worker 
write_binary_policy(FILE * outfp,policydb_t * p)142*2d543d20SAndroid Build Coastguard Worker static int write_binary_policy(FILE *outfp, policydb_t *p)
143*2d543d20SAndroid Build Coastguard Worker {
144*2d543d20SAndroid Build Coastguard Worker 	struct policy_file pf;
145*2d543d20SAndroid Build Coastguard Worker 
146*2d543d20SAndroid Build Coastguard Worker 	policy_file_init(&pf);
147*2d543d20SAndroid Build Coastguard Worker 	pf.type = PF_USE_STDIO;
148*2d543d20SAndroid Build Coastguard Worker 	pf.fp = outfp;
149*2d543d20SAndroid Build Coastguard Worker 	return policydb_write(p, &pf);
150*2d543d20SAndroid Build Coastguard Worker }
151*2d543d20SAndroid Build Coastguard Worker 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)152*2d543d20SAndroid Build Coastguard Worker int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
153*2d543d20SAndroid Build Coastguard Worker {
154*2d543d20SAndroid Build Coastguard Worker 	policydb_t parsepolicydb = {};
155*2d543d20SAndroid Build Coastguard Worker 	policydb_t kernpolicydb = {};
156*2d543d20SAndroid Build Coastguard Worker 	policydb_t *finalpolicydb;
157*2d543d20SAndroid Build Coastguard Worker 	sidtab_t sidtab = {};
158*2d543d20SAndroid Build Coastguard Worker 	FILE *devnull = NULL;
159*2d543d20SAndroid Build Coastguard Worker 	int mls, platform, policyvers;
160*2d543d20SAndroid Build Coastguard Worker 
161*2d543d20SAndroid Build Coastguard Worker 	sepol_debug(VERBOSE);
162*2d543d20SAndroid Build Coastguard Worker 
163*2d543d20SAndroid Build Coastguard Worker 	/*
164*2d543d20SAndroid Build Coastguard Worker 	 * Take the first byte whether to generate a SELinux or Xen policy,
165*2d543d20SAndroid Build Coastguard Worker 	 * the second byte whether to parse as MLS policy,
166*2d543d20SAndroid Build Coastguard Worker 	 * and the second byte as policy version.
167*2d543d20SAndroid Build Coastguard Worker 	 */
168*2d543d20SAndroid Build Coastguard Worker 	if (size < 3)
169*2d543d20SAndroid Build Coastguard Worker 		return 0;
170*2d543d20SAndroid Build Coastguard Worker 	switch (data[0]) {
171*2d543d20SAndroid Build Coastguard Worker 	case 'S':
172*2d543d20SAndroid Build Coastguard Worker 		platform = SEPOL_TARGET_SELINUX;
173*2d543d20SAndroid Build Coastguard Worker 		break;
174*2d543d20SAndroid Build Coastguard Worker 	case 'X':
175*2d543d20SAndroid Build Coastguard Worker 		platform = SEPOL_TARGET_XEN;
176*2d543d20SAndroid Build Coastguard Worker 		break;
177*2d543d20SAndroid Build Coastguard Worker 	default:
178*2d543d20SAndroid Build Coastguard Worker 		return 0;
179*2d543d20SAndroid Build Coastguard Worker 	}
180*2d543d20SAndroid Build Coastguard Worker 	switch (data[1]) {
181*2d543d20SAndroid Build Coastguard Worker 	case '0':
182*2d543d20SAndroid Build Coastguard Worker 		mls = 0;
183*2d543d20SAndroid Build Coastguard Worker 		break;
184*2d543d20SAndroid Build Coastguard Worker 	case '1':
185*2d543d20SAndroid Build Coastguard Worker 		mls = 1;
186*2d543d20SAndroid Build Coastguard Worker 		break;
187*2d543d20SAndroid Build Coastguard Worker 	default:
188*2d543d20SAndroid Build Coastguard Worker 		return 0;
189*2d543d20SAndroid Build Coastguard Worker 	}
190*2d543d20SAndroid Build Coastguard Worker 	static_assert(0x7F - 'A' >= POLICYDB_VERSION_MAX, "Max policy version should be representable");
191*2d543d20SAndroid Build Coastguard Worker 	policyvers = data[2] - 'A';
192*2d543d20SAndroid Build Coastguard Worker 	if (policyvers < POLICYDB_VERSION_MIN || policyvers > POLICYDB_VERSION_MAX)
193*2d543d20SAndroid Build Coastguard Worker 		return 0;
194*2d543d20SAndroid Build Coastguard Worker 	data += 3;
195*2d543d20SAndroid Build Coastguard Worker 	size -= 3;
196*2d543d20SAndroid Build Coastguard Worker 
197*2d543d20SAndroid Build Coastguard Worker 	if (policydb_init(&parsepolicydb))
198*2d543d20SAndroid Build Coastguard Worker 		goto exit;
199*2d543d20SAndroid Build Coastguard Worker 
200*2d543d20SAndroid Build Coastguard Worker 	parsepolicydb.policy_type = POLICY_BASE;
201*2d543d20SAndroid Build Coastguard Worker 	parsepolicydb.mls = mls;
202*2d543d20SAndroid Build Coastguard Worker 	parsepolicydb.handle_unknown = DENY_UNKNOWN;
203*2d543d20SAndroid Build Coastguard Worker 	parsepolicydb.policyvers = policyvers;
204*2d543d20SAndroid Build Coastguard Worker 	policydb_set_target_platform(&parsepolicydb, platform);
205*2d543d20SAndroid Build Coastguard Worker 
206*2d543d20SAndroid Build Coastguard Worker 	if (read_source_policy(&parsepolicydb, data, size))
207*2d543d20SAndroid Build Coastguard Worker 		goto exit;
208*2d543d20SAndroid Build Coastguard Worker 
209*2d543d20SAndroid Build Coastguard Worker 	if (parsepolicydb.policy_type == POLICY_BASE) {
210*2d543d20SAndroid Build Coastguard Worker 		if (link_modules(NULL, &parsepolicydb, NULL, 0, VERBOSE))
211*2d543d20SAndroid Build Coastguard Worker 			goto exit;
212*2d543d20SAndroid Build Coastguard Worker 
213*2d543d20SAndroid Build Coastguard Worker 		if (policydb_init(&kernpolicydb))
214*2d543d20SAndroid Build Coastguard Worker 			goto exit;
215*2d543d20SAndroid Build Coastguard Worker 
216*2d543d20SAndroid Build Coastguard Worker 		if (expand_module(NULL, &parsepolicydb, &kernpolicydb, VERBOSE, /*check_assertions=*/0))
217*2d543d20SAndroid Build Coastguard Worker 			goto exit;
218*2d543d20SAndroid Build Coastguard Worker 
219*2d543d20SAndroid Build Coastguard Worker 		(void) check_assertions(NULL, &kernpolicydb, kernpolicydb.global->branch_list->avrules);
220*2d543d20SAndroid Build Coastguard Worker 		(void) hierarchy_check_constraints(NULL, &kernpolicydb);
221*2d543d20SAndroid Build Coastguard Worker 
222*2d543d20SAndroid Build Coastguard Worker 		kernpolicydb.policyvers = policyvers;
223*2d543d20SAndroid Build Coastguard Worker 
224*2d543d20SAndroid Build Coastguard Worker 		assert(kernpolicydb.policy_type     == POLICY_KERN);
225*2d543d20SAndroid Build Coastguard Worker 		assert(kernpolicydb.handle_unknown  == SEPOL_DENY_UNKNOWN);
226*2d543d20SAndroid Build Coastguard Worker 		assert(kernpolicydb.mls             == mls);
227*2d543d20SAndroid Build Coastguard Worker 		assert(kernpolicydb.target_platform == platform);
228*2d543d20SAndroid Build Coastguard Worker 
229*2d543d20SAndroid Build Coastguard Worker 		finalpolicydb = &kernpolicydb;
230*2d543d20SAndroid Build Coastguard Worker 	} else {
231*2d543d20SAndroid Build Coastguard Worker 		assert(parsepolicydb.policy_type     == POLICY_MOD);
232*2d543d20SAndroid Build Coastguard Worker 		assert(parsepolicydb.handle_unknown  == SEPOL_DENY_UNKNOWN);
233*2d543d20SAndroid Build Coastguard Worker 		assert(parsepolicydb.mls             == mls);
234*2d543d20SAndroid Build Coastguard Worker 		assert(parsepolicydb.target_platform == platform);
235*2d543d20SAndroid Build Coastguard Worker 
236*2d543d20SAndroid Build Coastguard Worker 		finalpolicydb = &parsepolicydb;
237*2d543d20SAndroid Build Coastguard Worker 	}
238*2d543d20SAndroid Build Coastguard Worker 
239*2d543d20SAndroid Build Coastguard Worker 	if (policydb_load_isids(finalpolicydb, &sidtab))
240*2d543d20SAndroid Build Coastguard Worker 		goto exit;
241*2d543d20SAndroid Build Coastguard Worker 
242*2d543d20SAndroid Build Coastguard Worker 	if (finalpolicydb->policy_type == POLICY_KERN && policydb_optimize(finalpolicydb))
243*2d543d20SAndroid Build Coastguard Worker 		goto exit;
244*2d543d20SAndroid Build Coastguard Worker 
245*2d543d20SAndroid Build Coastguard Worker 	if (policydb_sort_ocontexts(finalpolicydb))
246*2d543d20SAndroid Build Coastguard Worker 		goto exit;
247*2d543d20SAndroid Build Coastguard Worker 
248*2d543d20SAndroid Build Coastguard Worker 	if (policydb_validate(NULL, finalpolicydb))
249*2d543d20SAndroid Build Coastguard Worker 		/* never generate an invalid policy */
250*2d543d20SAndroid Build Coastguard Worker 		abort();
251*2d543d20SAndroid Build Coastguard Worker 
252*2d543d20SAndroid Build Coastguard Worker 	devnull = fopen("/dev/null", "we");
253*2d543d20SAndroid Build Coastguard Worker 	if (devnull == NULL)
254*2d543d20SAndroid Build Coastguard Worker 		goto exit;
255*2d543d20SAndroid Build Coastguard Worker 
256*2d543d20SAndroid Build Coastguard Worker 	if (write_binary_policy(devnull, finalpolicydb))
257*2d543d20SAndroid Build Coastguard Worker 		abort();
258*2d543d20SAndroid Build Coastguard Worker 
259*2d543d20SAndroid Build Coastguard Worker 	if (finalpolicydb->policy_type == POLICY_KERN && sepol_kernel_policydb_to_conf(devnull, finalpolicydb))
260*2d543d20SAndroid Build Coastguard Worker 		abort();
261*2d543d20SAndroid Build Coastguard Worker 
262*2d543d20SAndroid Build Coastguard Worker 	if (finalpolicydb->policy_type == POLICY_KERN && sepol_kernel_policydb_to_cil(devnull, finalpolicydb))
263*2d543d20SAndroid Build Coastguard Worker 		abort();
264*2d543d20SAndroid Build Coastguard Worker 
265*2d543d20SAndroid Build Coastguard Worker 	if (finalpolicydb->policy_type == POLICY_MOD && sepol_module_policydb_to_cil(devnull, finalpolicydb, /*linked=*/0))
266*2d543d20SAndroid Build Coastguard Worker 		abort();
267*2d543d20SAndroid Build Coastguard Worker 
268*2d543d20SAndroid Build Coastguard Worker exit:
269*2d543d20SAndroid Build Coastguard Worker 	if (devnull != NULL)
270*2d543d20SAndroid Build Coastguard Worker 		fclose(devnull);
271*2d543d20SAndroid Build Coastguard Worker 
272*2d543d20SAndroid Build Coastguard Worker 	sepol_sidtab_destroy(&sidtab);
273*2d543d20SAndroid Build Coastguard Worker 	policydb_destroy(&kernpolicydb);
274*2d543d20SAndroid Build Coastguard Worker 	policydb_destroy(&parsepolicydb);
275*2d543d20SAndroid Build Coastguard Worker 
276*2d543d20SAndroid Build Coastguard Worker 	id_queue = NULL;
277*2d543d20SAndroid Build Coastguard Worker 	policydbp = NULL;
278*2d543d20SAndroid Build Coastguard Worker 	module_compiler_reset();
279*2d543d20SAndroid Build Coastguard Worker 
280*2d543d20SAndroid Build Coastguard Worker 	/* Non-zero return values are reserved for future use. */
281*2d543d20SAndroid Build Coastguard Worker 	return 0;
282*2d543d20SAndroid Build Coastguard Worker }
283