1*e4a36f41SAndroid Build Coastguard Worker #include <getopt.h>
2*e4a36f41SAndroid Build Coastguard Worker #include <stddef.h>
3*e4a36f41SAndroid Build Coastguard Worker #include <stdint.h>
4*e4a36f41SAndroid Build Coastguard Worker #include <stdio.h>
5*e4a36f41SAndroid Build Coastguard Worker #include <stdlib.h>
6*e4a36f41SAndroid Build Coastguard Worker #include <string.h>
7*e4a36f41SAndroid Build Coastguard Worker #include <sys/stat.h>
8*e4a36f41SAndroid Build Coastguard Worker
9*e4a36f41SAndroid Build Coastguard Worker #include <cil/cil.h>
10*e4a36f41SAndroid Build Coastguard Worker #include <cil/android.h>
11*e4a36f41SAndroid Build Coastguard Worker #include <sepol/policydb.h>
12*e4a36f41SAndroid Build Coastguard Worker #include "sepol/handle.h"
13*e4a36f41SAndroid Build Coastguard Worker
usage(const char * prog)14*e4a36f41SAndroid Build Coastguard Worker void usage(const char *prog)
15*e4a36f41SAndroid Build Coastguard Worker {
16*e4a36f41SAndroid Build Coastguard Worker printf("Usage: %s [OPTION]... FILE...\n", prog);
17*e4a36f41SAndroid Build Coastguard Worker printf("Takes a binary policy file as input and applies the rules and definitions specified ");
18*e4a36f41SAndroid Build Coastguard Worker printf("in the provided FILEs. Each FILE must be a policy file in CIL format.\n");
19*e4a36f41SAndroid Build Coastguard Worker printf("\n");
20*e4a36f41SAndroid Build Coastguard Worker printf("Options:\n");
21*e4a36f41SAndroid Build Coastguard Worker printf(" -b, --base=<file> (required) base binary policy.\n");
22*e4a36f41SAndroid Build Coastguard Worker printf(" -o, --output=<file> (required) write binary policy to <file>\n");
23*e4a36f41SAndroid Build Coastguard Worker printf(" -v, --verbose increment verbosity level\n");
24*e4a36f41SAndroid Build Coastguard Worker printf(" -h, --help display usage information\n");
25*e4a36f41SAndroid Build Coastguard Worker exit(1);
26*e4a36f41SAndroid Build Coastguard Worker }
27*e4a36f41SAndroid Build Coastguard Worker
28*e4a36f41SAndroid Build Coastguard Worker /*
29*e4a36f41SAndroid Build Coastguard Worker * Read binary policy file from path into the allocated pdb.
30*e4a36f41SAndroid Build Coastguard Worker *
31*e4a36f41SAndroid Build Coastguard Worker * We first read the binary policy into memory, and then we parse it to a
32*e4a36f41SAndroid Build Coastguard Worker * policydb object using sepol_policydb_from_image. This combination is slightly
33*e4a36f41SAndroid Build Coastguard Worker * faster than using sepol_policydb_read that reads the binary file in small
34*e4a36f41SAndroid Build Coastguard Worker * chunks at a time.
35*e4a36f41SAndroid Build Coastguard Worker */
read_binary_policy(char * path,sepol_policydb_t * pdb)36*e4a36f41SAndroid Build Coastguard Worker static int read_binary_policy(char *path, sepol_policydb_t *pdb)
37*e4a36f41SAndroid Build Coastguard Worker {
38*e4a36f41SAndroid Build Coastguard Worker int rc = SEPOL_OK;
39*e4a36f41SAndroid Build Coastguard Worker char *buff = NULL;
40*e4a36f41SAndroid Build Coastguard Worker sepol_handle_t *handle = NULL;
41*e4a36f41SAndroid Build Coastguard Worker
42*e4a36f41SAndroid Build Coastguard Worker FILE *file = fopen(path, "r");
43*e4a36f41SAndroid Build Coastguard Worker if (!file) {
44*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Could not open %s: %s.\n", path, strerror(errno));
45*e4a36f41SAndroid Build Coastguard Worker rc = SEPOL_ERR;
46*e4a36f41SAndroid Build Coastguard Worker goto exit;
47*e4a36f41SAndroid Build Coastguard Worker }
48*e4a36f41SAndroid Build Coastguard Worker
49*e4a36f41SAndroid Build Coastguard Worker struct stat binarydata;
50*e4a36f41SAndroid Build Coastguard Worker rc = stat(path, &binarydata);
51*e4a36f41SAndroid Build Coastguard Worker if (rc == -1) {
52*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Could not stat %s: %s.\n", path, strerror(errno));
53*e4a36f41SAndroid Build Coastguard Worker goto exit;
54*e4a36f41SAndroid Build Coastguard Worker }
55*e4a36f41SAndroid Build Coastguard Worker
56*e4a36f41SAndroid Build Coastguard Worker uint32_t file_size = binarydata.st_size;
57*e4a36f41SAndroid Build Coastguard Worker if (!file_size) {
58*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Binary policy file is empty.\n");
59*e4a36f41SAndroid Build Coastguard Worker rc = SEPOL_ERR;
60*e4a36f41SAndroid Build Coastguard Worker goto exit;
61*e4a36f41SAndroid Build Coastguard Worker }
62*e4a36f41SAndroid Build Coastguard Worker
63*e4a36f41SAndroid Build Coastguard Worker buff = malloc(file_size);
64*e4a36f41SAndroid Build Coastguard Worker if (buff == NULL) {
65*e4a36f41SAndroid Build Coastguard Worker perror("malloc failed");
66*e4a36f41SAndroid Build Coastguard Worker rc = SEPOL_ERR;
67*e4a36f41SAndroid Build Coastguard Worker goto exit;
68*e4a36f41SAndroid Build Coastguard Worker }
69*e4a36f41SAndroid Build Coastguard Worker
70*e4a36f41SAndroid Build Coastguard Worker rc = fread(buff, file_size, 1, file);
71*e4a36f41SAndroid Build Coastguard Worker if (rc != 1) {
72*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Failure reading %s: %s.\n", path, strerror(errno));
73*e4a36f41SAndroid Build Coastguard Worker rc = SEPOL_ERR;
74*e4a36f41SAndroid Build Coastguard Worker goto exit;
75*e4a36f41SAndroid Build Coastguard Worker }
76*e4a36f41SAndroid Build Coastguard Worker
77*e4a36f41SAndroid Build Coastguard Worker handle = sepol_handle_create();
78*e4a36f41SAndroid Build Coastguard Worker if (!handle) {
79*e4a36f41SAndroid Build Coastguard Worker perror("Could not create policy handle");
80*e4a36f41SAndroid Build Coastguard Worker rc = SEPOL_ERR;
81*e4a36f41SAndroid Build Coastguard Worker goto exit;
82*e4a36f41SAndroid Build Coastguard Worker }
83*e4a36f41SAndroid Build Coastguard Worker
84*e4a36f41SAndroid Build Coastguard Worker rc = sepol_policydb_from_image(handle, buff, file_size, pdb);
85*e4a36f41SAndroid Build Coastguard Worker if (rc != 0) {
86*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Failed to read binary policy: %d.\n", rc);
87*e4a36f41SAndroid Build Coastguard Worker }
88*e4a36f41SAndroid Build Coastguard Worker
89*e4a36f41SAndroid Build Coastguard Worker exit:
90*e4a36f41SAndroid Build Coastguard Worker if (file != NULL && fclose(file) == EOF && rc == SEPOL_OK) {
91*e4a36f41SAndroid Build Coastguard Worker perror("Failure closing binary file");
92*e4a36f41SAndroid Build Coastguard Worker rc = SEPOL_ERR;
93*e4a36f41SAndroid Build Coastguard Worker }
94*e4a36f41SAndroid Build Coastguard Worker if(handle != NULL) {
95*e4a36f41SAndroid Build Coastguard Worker sepol_handle_destroy(handle);
96*e4a36f41SAndroid Build Coastguard Worker }
97*e4a36f41SAndroid Build Coastguard Worker free(buff);
98*e4a36f41SAndroid Build Coastguard Worker return rc;
99*e4a36f41SAndroid Build Coastguard Worker }
100*e4a36f41SAndroid Build Coastguard Worker
101*e4a36f41SAndroid Build Coastguard Worker /*
102*e4a36f41SAndroid Build Coastguard Worker * read_cil_files - Initialize db and parse CIL input files.
103*e4a36f41SAndroid Build Coastguard Worker */
read_cil_files(struct cil_db ** db,char ** paths,unsigned int n_files)104*e4a36f41SAndroid Build Coastguard Worker static int read_cil_files(struct cil_db **db, char **paths,
105*e4a36f41SAndroid Build Coastguard Worker unsigned int n_files)
106*e4a36f41SAndroid Build Coastguard Worker {
107*e4a36f41SAndroid Build Coastguard Worker int rc = SEPOL_ERR;
108*e4a36f41SAndroid Build Coastguard Worker FILE *file = NULL;
109*e4a36f41SAndroid Build Coastguard Worker char *buff = NULL;
110*e4a36f41SAndroid Build Coastguard Worker
111*e4a36f41SAndroid Build Coastguard Worker for (int i = 0; i < n_files; i++) {
112*e4a36f41SAndroid Build Coastguard Worker char *path = paths[i];
113*e4a36f41SAndroid Build Coastguard Worker
114*e4a36f41SAndroid Build Coastguard Worker file = fopen(path, "r");
115*e4a36f41SAndroid Build Coastguard Worker if (file == NULL) {
116*e4a36f41SAndroid Build Coastguard Worker rc = SEPOL_ERR;
117*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Could not open %s: %s.\n", path, strerror(errno));
118*e4a36f41SAndroid Build Coastguard Worker goto file_err;
119*e4a36f41SAndroid Build Coastguard Worker }
120*e4a36f41SAndroid Build Coastguard Worker
121*e4a36f41SAndroid Build Coastguard Worker struct stat filedata;
122*e4a36f41SAndroid Build Coastguard Worker rc = stat(path, &filedata);
123*e4a36f41SAndroid Build Coastguard Worker if (rc == -1) {
124*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Could not stat %s: %s.\n", path, strerror(errno));
125*e4a36f41SAndroid Build Coastguard Worker goto err;
126*e4a36f41SAndroid Build Coastguard Worker }
127*e4a36f41SAndroid Build Coastguard Worker
128*e4a36f41SAndroid Build Coastguard Worker uint32_t file_size = filedata.st_size;
129*e4a36f41SAndroid Build Coastguard Worker buff = malloc(file_size);
130*e4a36f41SAndroid Build Coastguard Worker if (buff == NULL) {
131*e4a36f41SAndroid Build Coastguard Worker perror("malloc failed");
132*e4a36f41SAndroid Build Coastguard Worker rc = SEPOL_ERR;
133*e4a36f41SAndroid Build Coastguard Worker goto err;
134*e4a36f41SAndroid Build Coastguard Worker }
135*e4a36f41SAndroid Build Coastguard Worker
136*e4a36f41SAndroid Build Coastguard Worker rc = fread(buff, file_size, 1, file);
137*e4a36f41SAndroid Build Coastguard Worker if (rc != 1) {
138*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Failure reading %s: %s.\n", path, strerror(errno));
139*e4a36f41SAndroid Build Coastguard Worker rc = SEPOL_ERR;
140*e4a36f41SAndroid Build Coastguard Worker goto err;
141*e4a36f41SAndroid Build Coastguard Worker }
142*e4a36f41SAndroid Build Coastguard Worker fclose(file);
143*e4a36f41SAndroid Build Coastguard Worker file = NULL;
144*e4a36f41SAndroid Build Coastguard Worker
145*e4a36f41SAndroid Build Coastguard Worker /* create parse_tree */
146*e4a36f41SAndroid Build Coastguard Worker rc = cil_add_file(*db, path, buff, file_size);
147*e4a36f41SAndroid Build Coastguard Worker if (rc != SEPOL_OK) {
148*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Failure adding %s to parse tree.\n", path);
149*e4a36f41SAndroid Build Coastguard Worker goto parse_err;
150*e4a36f41SAndroid Build Coastguard Worker }
151*e4a36f41SAndroid Build Coastguard Worker free(buff);
152*e4a36f41SAndroid Build Coastguard Worker buff = NULL;
153*e4a36f41SAndroid Build Coastguard Worker }
154*e4a36f41SAndroid Build Coastguard Worker
155*e4a36f41SAndroid Build Coastguard Worker return SEPOL_OK;
156*e4a36f41SAndroid Build Coastguard Worker err:
157*e4a36f41SAndroid Build Coastguard Worker fclose(file);
158*e4a36f41SAndroid Build Coastguard Worker parse_err:
159*e4a36f41SAndroid Build Coastguard Worker free(buff);
160*e4a36f41SAndroid Build Coastguard Worker file_err:
161*e4a36f41SAndroid Build Coastguard Worker return rc;
162*e4a36f41SAndroid Build Coastguard Worker }
163*e4a36f41SAndroid Build Coastguard Worker
164*e4a36f41SAndroid Build Coastguard Worker /*
165*e4a36f41SAndroid Build Coastguard Worker * Write binary policy in pdb to file at path.
166*e4a36f41SAndroid Build Coastguard Worker */
write_binary_policy(sepol_policydb_t * pdb,char * path)167*e4a36f41SAndroid Build Coastguard Worker static int write_binary_policy(sepol_policydb_t *pdb, char *path)
168*e4a36f41SAndroid Build Coastguard Worker {
169*e4a36f41SAndroid Build Coastguard Worker int rc = SEPOL_OK;
170*e4a36f41SAndroid Build Coastguard Worker
171*e4a36f41SAndroid Build Coastguard Worker FILE *file = fopen(path, "w");
172*e4a36f41SAndroid Build Coastguard Worker if (file == NULL) {
173*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Could not open %s: %s.\n", path, strerror(errno));
174*e4a36f41SAndroid Build Coastguard Worker rc = SEPOL_ERR;
175*e4a36f41SAndroid Build Coastguard Worker goto exit;
176*e4a36f41SAndroid Build Coastguard Worker }
177*e4a36f41SAndroid Build Coastguard Worker
178*e4a36f41SAndroid Build Coastguard Worker struct sepol_policy_file *pf = NULL;
179*e4a36f41SAndroid Build Coastguard Worker rc = sepol_policy_file_create(&pf);
180*e4a36f41SAndroid Build Coastguard Worker if (rc != 0) {
181*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Failed to create policy file: %d.\n", rc);
182*e4a36f41SAndroid Build Coastguard Worker goto exit;
183*e4a36f41SAndroid Build Coastguard Worker }
184*e4a36f41SAndroid Build Coastguard Worker sepol_policy_file_set_fp(pf, file);
185*e4a36f41SAndroid Build Coastguard Worker
186*e4a36f41SAndroid Build Coastguard Worker rc = sepol_policydb_write(pdb, pf);
187*e4a36f41SAndroid Build Coastguard Worker if (rc != 0) {
188*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "failed to write binary policy: %d.\n", rc);
189*e4a36f41SAndroid Build Coastguard Worker goto exit;
190*e4a36f41SAndroid Build Coastguard Worker }
191*e4a36f41SAndroid Build Coastguard Worker
192*e4a36f41SAndroid Build Coastguard Worker exit:
193*e4a36f41SAndroid Build Coastguard Worker if (file != NULL && fclose(file) == EOF && rc == SEPOL_OK) {
194*e4a36f41SAndroid Build Coastguard Worker perror("Failure closing binary file");
195*e4a36f41SAndroid Build Coastguard Worker rc = SEPOL_ERR;
196*e4a36f41SAndroid Build Coastguard Worker }
197*e4a36f41SAndroid Build Coastguard Worker return rc;
198*e4a36f41SAndroid Build Coastguard Worker }
199*e4a36f41SAndroid Build Coastguard Worker
main(int argc,char * argv[])200*e4a36f41SAndroid Build Coastguard Worker int main(int argc, char *argv[])
201*e4a36f41SAndroid Build Coastguard Worker {
202*e4a36f41SAndroid Build Coastguard Worker char *base = NULL;
203*e4a36f41SAndroid Build Coastguard Worker char *output = NULL;
204*e4a36f41SAndroid Build Coastguard Worker enum cil_log_level log_level = CIL_ERR;
205*e4a36f41SAndroid Build Coastguard Worker static struct option long_opts[] = {{"base", required_argument, 0, 'b'},
206*e4a36f41SAndroid Build Coastguard Worker {"output", required_argument, 0, 'o'},
207*e4a36f41SAndroid Build Coastguard Worker {"verbose", no_argument, 0, 'v'},
208*e4a36f41SAndroid Build Coastguard Worker {"help", no_argument, 0, 'h'},
209*e4a36f41SAndroid Build Coastguard Worker {0, 0, 0, 0}};
210*e4a36f41SAndroid Build Coastguard Worker
211*e4a36f41SAndroid Build Coastguard Worker while (1) {
212*e4a36f41SAndroid Build Coastguard Worker int opt_index = 0;
213*e4a36f41SAndroid Build Coastguard Worker int opt_char = getopt_long(argc, argv, "b:o:vh", long_opts, &opt_index);
214*e4a36f41SAndroid Build Coastguard Worker if (opt_char == -1) {
215*e4a36f41SAndroid Build Coastguard Worker break;
216*e4a36f41SAndroid Build Coastguard Worker }
217*e4a36f41SAndroid Build Coastguard Worker switch (opt_char)
218*e4a36f41SAndroid Build Coastguard Worker {
219*e4a36f41SAndroid Build Coastguard Worker case 'b':
220*e4a36f41SAndroid Build Coastguard Worker base = optarg;
221*e4a36f41SAndroid Build Coastguard Worker break;
222*e4a36f41SAndroid Build Coastguard Worker case 'o':
223*e4a36f41SAndroid Build Coastguard Worker output = optarg;
224*e4a36f41SAndroid Build Coastguard Worker break;
225*e4a36f41SAndroid Build Coastguard Worker case 'v':
226*e4a36f41SAndroid Build Coastguard Worker log_level++;
227*e4a36f41SAndroid Build Coastguard Worker break;
228*e4a36f41SAndroid Build Coastguard Worker case 'h':
229*e4a36f41SAndroid Build Coastguard Worker usage(argv[0]);
230*e4a36f41SAndroid Build Coastguard Worker default:
231*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Unsupported option: %s.\n", optarg);
232*e4a36f41SAndroid Build Coastguard Worker usage(argv[0]);
233*e4a36f41SAndroid Build Coastguard Worker }
234*e4a36f41SAndroid Build Coastguard Worker }
235*e4a36f41SAndroid Build Coastguard Worker if (base == NULL || output == NULL) {
236*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Please specify required arguments.\n");
237*e4a36f41SAndroid Build Coastguard Worker usage(argv[0]);
238*e4a36f41SAndroid Build Coastguard Worker }
239*e4a36f41SAndroid Build Coastguard Worker
240*e4a36f41SAndroid Build Coastguard Worker cil_set_log_level(log_level);
241*e4a36f41SAndroid Build Coastguard Worker
242*e4a36f41SAndroid Build Coastguard Worker // Initialize and read input policydb file.
243*e4a36f41SAndroid Build Coastguard Worker sepol_policydb_t *pdb = NULL;
244*e4a36f41SAndroid Build Coastguard Worker int rc = sepol_policydb_create(&pdb);
245*e4a36f41SAndroid Build Coastguard Worker if (rc != 0) {
246*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Could not create policy db: %d.\n", rc);
247*e4a36f41SAndroid Build Coastguard Worker exit(rc);
248*e4a36f41SAndroid Build Coastguard Worker }
249*e4a36f41SAndroid Build Coastguard Worker
250*e4a36f41SAndroid Build Coastguard Worker rc = read_binary_policy(base, pdb);
251*e4a36f41SAndroid Build Coastguard Worker if (rc != SEPOL_OK) {
252*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Failed to read binary policy: %d.\n", rc);
253*e4a36f41SAndroid Build Coastguard Worker exit(rc);
254*e4a36f41SAndroid Build Coastguard Worker }
255*e4a36f41SAndroid Build Coastguard Worker
256*e4a36f41SAndroid Build Coastguard Worker // Initialize cil_db.
257*e4a36f41SAndroid Build Coastguard Worker struct cil_db *incremental_db = NULL;
258*e4a36f41SAndroid Build Coastguard Worker cil_db_init(&incremental_db);
259*e4a36f41SAndroid Build Coastguard Worker cil_set_attrs_expand_generated(incremental_db, 1);
260*e4a36f41SAndroid Build Coastguard Worker
261*e4a36f41SAndroid Build Coastguard Worker // Read input cil files and compile them into cil_db.
262*e4a36f41SAndroid Build Coastguard Worker rc = read_cil_files(&incremental_db, argv + optind, argc - optind);
263*e4a36f41SAndroid Build Coastguard Worker if (rc != SEPOL_OK) {
264*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Failed to read CIL files: %d.\n", rc);
265*e4a36f41SAndroid Build Coastguard Worker exit(rc);
266*e4a36f41SAndroid Build Coastguard Worker }
267*e4a36f41SAndroid Build Coastguard Worker
268*e4a36f41SAndroid Build Coastguard Worker rc = cil_compile(incremental_db);
269*e4a36f41SAndroid Build Coastguard Worker if (rc != SEPOL_OK) {
270*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Failed to compile cildb: %d.\n", rc);
271*e4a36f41SAndroid Build Coastguard Worker exit(rc);
272*e4a36f41SAndroid Build Coastguard Worker }
273*e4a36f41SAndroid Build Coastguard Worker
274*e4a36f41SAndroid Build Coastguard Worker // Amend the policydb.
275*e4a36f41SAndroid Build Coastguard Worker rc = cil_amend_policydb(incremental_db, pdb);
276*e4a36f41SAndroid Build Coastguard Worker if (rc != SEPOL_OK) {
277*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Failed to build policydb.\n");
278*e4a36f41SAndroid Build Coastguard Worker exit(rc);
279*e4a36f41SAndroid Build Coastguard Worker }
280*e4a36f41SAndroid Build Coastguard Worker
281*e4a36f41SAndroid Build Coastguard Worker rc = write_binary_policy(pdb, output);
282*e4a36f41SAndroid Build Coastguard Worker if (rc != SEPOL_OK) {
283*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Failed to write binary policy: %d.\n", rc);
284*e4a36f41SAndroid Build Coastguard Worker exit(rc);
285*e4a36f41SAndroid Build Coastguard Worker }
286*e4a36f41SAndroid Build Coastguard Worker }
287