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