xref: /aosp_15_r20/system/sepolicy/tools/seamendc.c (revision e4a36f4174b17bbab9dc043f4a65dc8d87377290)
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