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