1*e4a36f41SAndroid Build Coastguard Worker #include <getopt.h>
2*e4a36f41SAndroid Build Coastguard Worker #include <stdbool.h>
3*e4a36f41SAndroid Build Coastguard Worker #include <stdio.h>
4*e4a36f41SAndroid Build Coastguard Worker #include <stdlib.h>
5*e4a36f41SAndroid Build Coastguard Worker #include <string.h>
6*e4a36f41SAndroid Build Coastguard Worker #include <unistd.h>
7*e4a36f41SAndroid Build Coastguard Worker #include <sepol/module.h>
8*e4a36f41SAndroid Build Coastguard Worker #include <sepol/policydb/policydb.h>
9*e4a36f41SAndroid Build Coastguard Worker #include <sepol/sepol.h>
10*e4a36f41SAndroid Build Coastguard Worker #include <selinux/context.h>
11*e4a36f41SAndroid Build Coastguard Worker #include <selinux/selinux.h>
12*e4a36f41SAndroid Build Coastguard Worker #include <selinux/label.h>
13*e4a36f41SAndroid Build Coastguard Worker #include <sys/stat.h>
14*e4a36f41SAndroid Build Coastguard Worker #include <sys/types.h>
15*e4a36f41SAndroid Build Coastguard Worker
16*e4a36f41SAndroid Build Coastguard Worker static const char * const CHECK_FC_ASSERT_ATTRS[] = { "fs_type", "dev_type", "file_type", NULL };
17*e4a36f41SAndroid Build Coastguard Worker static const char * const CHECK_PC_ASSERT_ATTRS[] = { "property_type", NULL };
18*e4a36f41SAndroid Build Coastguard Worker static const char * const CHECK_SC_ASSERT_ATTRS[] = { "service_manager_type", NULL };
19*e4a36f41SAndroid Build Coastguard Worker static const char * const CHECK_HW_SC_ASSERT_ATTRS[] = { "hwservice_manager_type", NULL };
20*e4a36f41SAndroid Build Coastguard Worker static const char * const CHECK_VND_SC_ASSERT_ATTRS[] = { "vndservice_manager_type", NULL };
21*e4a36f41SAndroid Build Coastguard Worker
22*e4a36f41SAndroid Build Coastguard Worker typedef enum filemode filemode;
23*e4a36f41SAndroid Build Coastguard Worker enum filemode {
24*e4a36f41SAndroid Build Coastguard Worker filemode_file_contexts = 0,
25*e4a36f41SAndroid Build Coastguard Worker filemode_property_contexts,
26*e4a36f41SAndroid Build Coastguard Worker filemode_service_contexts,
27*e4a36f41SAndroid Build Coastguard Worker filemode_hw_service_contexts,
28*e4a36f41SAndroid Build Coastguard Worker filemode_vendor_service_contexts
29*e4a36f41SAndroid Build Coastguard Worker };
30*e4a36f41SAndroid Build Coastguard Worker
31*e4a36f41SAndroid Build Coastguard Worker static struct {
32*e4a36f41SAndroid Build Coastguard Worker /* policy */
33*e4a36f41SAndroid Build Coastguard Worker struct {
34*e4a36f41SAndroid Build Coastguard Worker union {
35*e4a36f41SAndroid Build Coastguard Worker /* Union these so we don't have to cast */
36*e4a36f41SAndroid Build Coastguard Worker sepol_policydb_t *sdb;
37*e4a36f41SAndroid Build Coastguard Worker policydb_t *pdb;
38*e4a36f41SAndroid Build Coastguard Worker };
39*e4a36f41SAndroid Build Coastguard Worker sepol_policy_file_t *pf;
40*e4a36f41SAndroid Build Coastguard Worker sepol_handle_t *handle;
41*e4a36f41SAndroid Build Coastguard Worker FILE *file;
42*e4a36f41SAndroid Build Coastguard Worker #define SEHANDLE_CNT 2
43*e4a36f41SAndroid Build Coastguard Worker struct selabel_handle *sehnd[SEHANDLE_CNT];
44*e4a36f41SAndroid Build Coastguard Worker } sepolicy;
45*e4a36f41SAndroid Build Coastguard Worker
46*e4a36f41SAndroid Build Coastguard Worker /* assertions */
47*e4a36f41SAndroid Build Coastguard Worker struct {
48*e4a36f41SAndroid Build Coastguard Worker const char * const *attrs; /* for the original set to print on error */
49*e4a36f41SAndroid Build Coastguard Worker ebitmap_t set; /* the ebitmap representation of the attrs */
50*e4a36f41SAndroid Build Coastguard Worker } assert;
51*e4a36f41SAndroid Build Coastguard Worker
52*e4a36f41SAndroid Build Coastguard Worker } global_state;
53*e4a36f41SAndroid Build Coastguard Worker
filemode_to_assert_attrs(filemode mode)54*e4a36f41SAndroid Build Coastguard Worker static const char * const *filemode_to_assert_attrs(filemode mode)
55*e4a36f41SAndroid Build Coastguard Worker {
56*e4a36f41SAndroid Build Coastguard Worker switch (mode) {
57*e4a36f41SAndroid Build Coastguard Worker case filemode_file_contexts:
58*e4a36f41SAndroid Build Coastguard Worker return CHECK_FC_ASSERT_ATTRS;
59*e4a36f41SAndroid Build Coastguard Worker case filemode_property_contexts:
60*e4a36f41SAndroid Build Coastguard Worker return CHECK_PC_ASSERT_ATTRS;
61*e4a36f41SAndroid Build Coastguard Worker case filemode_service_contexts:
62*e4a36f41SAndroid Build Coastguard Worker return CHECK_SC_ASSERT_ATTRS;
63*e4a36f41SAndroid Build Coastguard Worker case filemode_hw_service_contexts:
64*e4a36f41SAndroid Build Coastguard Worker return CHECK_HW_SC_ASSERT_ATTRS;
65*e4a36f41SAndroid Build Coastguard Worker case filemode_vendor_service_contexts:
66*e4a36f41SAndroid Build Coastguard Worker return CHECK_VND_SC_ASSERT_ATTRS;
67*e4a36f41SAndroid Build Coastguard Worker }
68*e4a36f41SAndroid Build Coastguard Worker /* die on invalid parameters */
69*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Error: Invalid mode of operation: %d\n", mode);
70*e4a36f41SAndroid Build Coastguard Worker exit(1);
71*e4a36f41SAndroid Build Coastguard Worker }
72*e4a36f41SAndroid Build Coastguard Worker
get_attr_bit(policydb_t * policydb,const char * attr_name)73*e4a36f41SAndroid Build Coastguard Worker static int get_attr_bit(policydb_t *policydb, const char *attr_name)
74*e4a36f41SAndroid Build Coastguard Worker {
75*e4a36f41SAndroid Build Coastguard Worker struct type_datum *attr = hashtab_search(policydb->p_types.table, (char *)attr_name);
76*e4a36f41SAndroid Build Coastguard Worker if (!attr) {
77*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Error: \"%s\" is not defined in this policy.\n", attr_name);
78*e4a36f41SAndroid Build Coastguard Worker return -1;
79*e4a36f41SAndroid Build Coastguard Worker }
80*e4a36f41SAndroid Build Coastguard Worker
81*e4a36f41SAndroid Build Coastguard Worker if (attr->flavor != TYPE_ATTRIB) {
82*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Error: \"%s\" is not an attribute in this policy.\n", attr_name);
83*e4a36f41SAndroid Build Coastguard Worker return -1;
84*e4a36f41SAndroid Build Coastguard Worker }
85*e4a36f41SAndroid Build Coastguard Worker
86*e4a36f41SAndroid Build Coastguard Worker return attr->s.value - 1;
87*e4a36f41SAndroid Build Coastguard Worker }
88*e4a36f41SAndroid Build Coastguard Worker
ebitmap_attribute_assertion_init(ebitmap_t * assertions,const char * const attributes[])89*e4a36f41SAndroid Build Coastguard Worker static bool ebitmap_attribute_assertion_init(ebitmap_t *assertions, const char * const attributes[])
90*e4a36f41SAndroid Build Coastguard Worker {
91*e4a36f41SAndroid Build Coastguard Worker
92*e4a36f41SAndroid Build Coastguard Worker while (*attributes) {
93*e4a36f41SAndroid Build Coastguard Worker
94*e4a36f41SAndroid Build Coastguard Worker int bit_pos = get_attr_bit(global_state.sepolicy.pdb, *attributes);
95*e4a36f41SAndroid Build Coastguard Worker if (bit_pos < 0) {
96*e4a36f41SAndroid Build Coastguard Worker /* get_attr_bit() logs error */
97*e4a36f41SAndroid Build Coastguard Worker return false;
98*e4a36f41SAndroid Build Coastguard Worker }
99*e4a36f41SAndroid Build Coastguard Worker
100*e4a36f41SAndroid Build Coastguard Worker int err = ebitmap_set_bit(assertions, bit_pos, 1);
101*e4a36f41SAndroid Build Coastguard Worker if (err) {
102*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Error: setting bit on assertion ebitmap!\n");
103*e4a36f41SAndroid Build Coastguard Worker return false;
104*e4a36f41SAndroid Build Coastguard Worker }
105*e4a36f41SAndroid Build Coastguard Worker attributes++;
106*e4a36f41SAndroid Build Coastguard Worker }
107*e4a36f41SAndroid Build Coastguard Worker return true;
108*e4a36f41SAndroid Build Coastguard Worker }
109*e4a36f41SAndroid Build Coastguard Worker
is_type_of_attribute_set(policydb_t * policydb,const char * type_name,ebitmap_t * attr_set)110*e4a36f41SAndroid Build Coastguard Worker static bool is_type_of_attribute_set(policydb_t *policydb, const char *type_name,
111*e4a36f41SAndroid Build Coastguard Worker ebitmap_t *attr_set)
112*e4a36f41SAndroid Build Coastguard Worker {
113*e4a36f41SAndroid Build Coastguard Worker struct type_datum *type = hashtab_search(policydb->p_types.table, (char *)type_name);
114*e4a36f41SAndroid Build Coastguard Worker if (!type) {
115*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Error: \"%s\" is not defined in this policy.\n", type_name);
116*e4a36f41SAndroid Build Coastguard Worker return false;
117*e4a36f41SAndroid Build Coastguard Worker }
118*e4a36f41SAndroid Build Coastguard Worker
119*e4a36f41SAndroid Build Coastguard Worker if (type->flavor != TYPE_TYPE) {
120*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Error: \"%s\" is not a type in this policy.\n", type_name);
121*e4a36f41SAndroid Build Coastguard Worker return false;
122*e4a36f41SAndroid Build Coastguard Worker }
123*e4a36f41SAndroid Build Coastguard Worker
124*e4a36f41SAndroid Build Coastguard Worker ebitmap_t dst;
125*e4a36f41SAndroid Build Coastguard Worker ebitmap_init(&dst);
126*e4a36f41SAndroid Build Coastguard Worker
127*e4a36f41SAndroid Build Coastguard Worker /* Take the intersection, if the set is empty, then its a failure */
128*e4a36f41SAndroid Build Coastguard Worker int rc = ebitmap_and(&dst, attr_set, &policydb->type_attr_map[type->s.value - 1]);
129*e4a36f41SAndroid Build Coastguard Worker if (rc) {
130*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Error: Could not perform ebitmap_and: %d\n", rc);
131*e4a36f41SAndroid Build Coastguard Worker exit(1);
132*e4a36f41SAndroid Build Coastguard Worker }
133*e4a36f41SAndroid Build Coastguard Worker
134*e4a36f41SAndroid Build Coastguard Worker bool res = (bool)ebitmap_length(&dst);
135*e4a36f41SAndroid Build Coastguard Worker
136*e4a36f41SAndroid Build Coastguard Worker ebitmap_destroy(&dst);
137*e4a36f41SAndroid Build Coastguard Worker return res;
138*e4a36f41SAndroid Build Coastguard Worker }
139*e4a36f41SAndroid Build Coastguard Worker
dump_char_array(FILE * stream,const char * const * strings)140*e4a36f41SAndroid Build Coastguard Worker static void dump_char_array(FILE *stream, const char * const *strings)
141*e4a36f41SAndroid Build Coastguard Worker {
142*e4a36f41SAndroid Build Coastguard Worker
143*e4a36f41SAndroid Build Coastguard Worker const char * const *p = strings;
144*e4a36f41SAndroid Build Coastguard Worker
145*e4a36f41SAndroid Build Coastguard Worker fprintf(stream, "\"");
146*e4a36f41SAndroid Build Coastguard Worker
147*e4a36f41SAndroid Build Coastguard Worker while (*p) {
148*e4a36f41SAndroid Build Coastguard Worker const char *s = *p++;
149*e4a36f41SAndroid Build Coastguard Worker const char *fmt = *p ? "%s, " : "%s\"";
150*e4a36f41SAndroid Build Coastguard Worker fprintf(stream, fmt, s);
151*e4a36f41SAndroid Build Coastguard Worker }
152*e4a36f41SAndroid Build Coastguard Worker }
153*e4a36f41SAndroid Build Coastguard Worker
validate(char ** contextp)154*e4a36f41SAndroid Build Coastguard Worker static int validate(char **contextp)
155*e4a36f41SAndroid Build Coastguard Worker {
156*e4a36f41SAndroid Build Coastguard Worker bool res;
157*e4a36f41SAndroid Build Coastguard Worker char *context = *contextp;
158*e4a36f41SAndroid Build Coastguard Worker
159*e4a36f41SAndroid Build Coastguard Worker sepol_context_t *ctx;
160*e4a36f41SAndroid Build Coastguard Worker int rc = sepol_context_from_string(global_state.sepolicy.handle, context,
161*e4a36f41SAndroid Build Coastguard Worker &ctx);
162*e4a36f41SAndroid Build Coastguard Worker if (rc < 0) {
163*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Error: Could not allocate context from string");
164*e4a36f41SAndroid Build Coastguard Worker exit(1);
165*e4a36f41SAndroid Build Coastguard Worker }
166*e4a36f41SAndroid Build Coastguard Worker
167*e4a36f41SAndroid Build Coastguard Worker rc = sepol_context_check(global_state.sepolicy.handle,
168*e4a36f41SAndroid Build Coastguard Worker global_state.sepolicy.sdb, ctx);
169*e4a36f41SAndroid Build Coastguard Worker if (rc < 0) {
170*e4a36f41SAndroid Build Coastguard Worker goto out;
171*e4a36f41SAndroid Build Coastguard Worker }
172*e4a36f41SAndroid Build Coastguard Worker
173*e4a36f41SAndroid Build Coastguard Worker const char *type_name = sepol_context_get_type(ctx);
174*e4a36f41SAndroid Build Coastguard Worker
175*e4a36f41SAndroid Build Coastguard Worker // Temporarily exempt hal_power_stats_vendor_service from the check.
176*e4a36f41SAndroid Build Coastguard Worker // TODO(b/211953546): remove this
177*e4a36f41SAndroid Build Coastguard Worker if (strcmp(type_name, "hal_power_stats_vendor_service") == 0) {
178*e4a36f41SAndroid Build Coastguard Worker goto out;
179*e4a36f41SAndroid Build Coastguard Worker }
180*e4a36f41SAndroid Build Coastguard Worker
181*e4a36f41SAndroid Build Coastguard Worker uint32_t len = ebitmap_length(&global_state.assert.set);
182*e4a36f41SAndroid Build Coastguard Worker if (len > 0) {
183*e4a36f41SAndroid Build Coastguard Worker res = !is_type_of_attribute_set(global_state.sepolicy.pdb, type_name,
184*e4a36f41SAndroid Build Coastguard Worker &global_state.assert.set);
185*e4a36f41SAndroid Build Coastguard Worker if (res) {
186*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Error: type \"%s\" is not of set: ", type_name);
187*e4a36f41SAndroid Build Coastguard Worker dump_char_array(stderr, global_state.assert.attrs);
188*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "\n");
189*e4a36f41SAndroid Build Coastguard Worker /* The calls above did not affect rc, so set error before going to out */
190*e4a36f41SAndroid Build Coastguard Worker rc = -1;
191*e4a36f41SAndroid Build Coastguard Worker goto out;
192*e4a36f41SAndroid Build Coastguard Worker }
193*e4a36f41SAndroid Build Coastguard Worker }
194*e4a36f41SAndroid Build Coastguard Worker /* Success: Although it should be 0, we explicitly set rc to 0 for clarity */
195*e4a36f41SAndroid Build Coastguard Worker rc = 0;
196*e4a36f41SAndroid Build Coastguard Worker
197*e4a36f41SAndroid Build Coastguard Worker out:
198*e4a36f41SAndroid Build Coastguard Worker sepol_context_free(ctx);
199*e4a36f41SAndroid Build Coastguard Worker return rc;
200*e4a36f41SAndroid Build Coastguard Worker }
201*e4a36f41SAndroid Build Coastguard Worker
usage(char * name)202*e4a36f41SAndroid Build Coastguard Worker static void usage(char *name) {
203*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "usage1: %s [-l|-p|-s|-v] [-e] sepolicy context_file\n\n"
204*e4a36f41SAndroid Build Coastguard Worker "Parses a context file and checks for syntax errors.\n"
205*e4a36f41SAndroid Build Coastguard Worker "If -p is specified, the property backend is used.\n"
206*e4a36f41SAndroid Build Coastguard Worker "If -s is specified, the service backend is used to verify binder services.\n"
207*e4a36f41SAndroid Build Coastguard Worker "If -l is specified, the service backend is used to verify hwbinder services.\n"
208*e4a36f41SAndroid Build Coastguard Worker "If -v is specified, the service backend is used to verify vndbinder services.\n"
209*e4a36f41SAndroid Build Coastguard Worker "Otherwise, context_file is assumed to be a file_contexts file\n"
210*e4a36f41SAndroid Build Coastguard Worker "If -e is specified, then the context_file is allowed to be empty.\n\n"
211*e4a36f41SAndroid Build Coastguard Worker
212*e4a36f41SAndroid Build Coastguard Worker "usage2: %s -c file_contexts1 file_contexts2\n\n"
213*e4a36f41SAndroid Build Coastguard Worker "Compares two file contexts files and reports one of \n"
214*e4a36f41SAndroid Build Coastguard Worker "subset, equal, superset, or incomparable.\n\n"
215*e4a36f41SAndroid Build Coastguard Worker
216*e4a36f41SAndroid Build Coastguard Worker "usage3: %s -t file_contexts test_data\n\n"
217*e4a36f41SAndroid Build Coastguard Worker "Validates a file contexts file against test_data.\n"
218*e4a36f41SAndroid Build Coastguard Worker "test_data is a text file where each line has the format:\n"
219*e4a36f41SAndroid Build Coastguard Worker " path expected_type\n\n\n",
220*e4a36f41SAndroid Build Coastguard Worker name, name, name);
221*e4a36f41SAndroid Build Coastguard Worker exit(1);
222*e4a36f41SAndroid Build Coastguard Worker }
223*e4a36f41SAndroid Build Coastguard Worker
cleanup(void)224*e4a36f41SAndroid Build Coastguard Worker static void cleanup(void) {
225*e4a36f41SAndroid Build Coastguard Worker
226*e4a36f41SAndroid Build Coastguard Worker if (global_state.sepolicy.file) {
227*e4a36f41SAndroid Build Coastguard Worker fclose(global_state.sepolicy.file);
228*e4a36f41SAndroid Build Coastguard Worker }
229*e4a36f41SAndroid Build Coastguard Worker
230*e4a36f41SAndroid Build Coastguard Worker if (global_state.sepolicy.sdb) {
231*e4a36f41SAndroid Build Coastguard Worker sepol_policydb_free(global_state.sepolicy.sdb);
232*e4a36f41SAndroid Build Coastguard Worker }
233*e4a36f41SAndroid Build Coastguard Worker
234*e4a36f41SAndroid Build Coastguard Worker if (global_state.sepolicy.pf) {
235*e4a36f41SAndroid Build Coastguard Worker sepol_policy_file_free(global_state.sepolicy.pf);
236*e4a36f41SAndroid Build Coastguard Worker }
237*e4a36f41SAndroid Build Coastguard Worker
238*e4a36f41SAndroid Build Coastguard Worker if (global_state.sepolicy.handle) {
239*e4a36f41SAndroid Build Coastguard Worker sepol_handle_destroy(global_state.sepolicy.handle);
240*e4a36f41SAndroid Build Coastguard Worker }
241*e4a36f41SAndroid Build Coastguard Worker
242*e4a36f41SAndroid Build Coastguard Worker ebitmap_destroy(&global_state.assert.set);
243*e4a36f41SAndroid Build Coastguard Worker
244*e4a36f41SAndroid Build Coastguard Worker int i;
245*e4a36f41SAndroid Build Coastguard Worker for (i = 0; i < SEHANDLE_CNT; i++) {
246*e4a36f41SAndroid Build Coastguard Worker struct selabel_handle *sehnd = global_state.sepolicy.sehnd[i];
247*e4a36f41SAndroid Build Coastguard Worker if (sehnd) {
248*e4a36f41SAndroid Build Coastguard Worker selabel_close(sehnd);
249*e4a36f41SAndroid Build Coastguard Worker }
250*e4a36f41SAndroid Build Coastguard Worker }
251*e4a36f41SAndroid Build Coastguard Worker }
252*e4a36f41SAndroid Build Coastguard Worker
do_compare_and_die_on_error(struct selinux_opt opts[],unsigned int backend,char * paths[])253*e4a36f41SAndroid Build Coastguard Worker static void do_compare_and_die_on_error(struct selinux_opt opts[], unsigned int backend, char *paths[])
254*e4a36f41SAndroid Build Coastguard Worker {
255*e4a36f41SAndroid Build Coastguard Worker enum selabel_cmp_result result;
256*e4a36f41SAndroid Build Coastguard Worker char *result_str[] = { "subset", "equal", "superset", "incomparable" };
257*e4a36f41SAndroid Build Coastguard Worker int i;
258*e4a36f41SAndroid Build Coastguard Worker
259*e4a36f41SAndroid Build Coastguard Worker opts[0].value = NULL; /* not validating against a policy when comparing */
260*e4a36f41SAndroid Build Coastguard Worker
261*e4a36f41SAndroid Build Coastguard Worker for (i = 0; i < SEHANDLE_CNT; i++) {
262*e4a36f41SAndroid Build Coastguard Worker opts[1].value = paths[i];
263*e4a36f41SAndroid Build Coastguard Worker global_state.sepolicy.sehnd[i] = selabel_open(backend, opts, 2);
264*e4a36f41SAndroid Build Coastguard Worker if (!global_state.sepolicy.sehnd[i]) {
265*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Error: could not load context file from %s\n", paths[i]);
266*e4a36f41SAndroid Build Coastguard Worker exit(1);
267*e4a36f41SAndroid Build Coastguard Worker }
268*e4a36f41SAndroid Build Coastguard Worker }
269*e4a36f41SAndroid Build Coastguard Worker
270*e4a36f41SAndroid Build Coastguard Worker result = selabel_cmp(global_state.sepolicy.sehnd[0], global_state.sepolicy.sehnd[1]);
271*e4a36f41SAndroid Build Coastguard Worker printf("%s\n", result_str[result]);
272*e4a36f41SAndroid Build Coastguard Worker }
273*e4a36f41SAndroid Build Coastguard Worker
274*e4a36f41SAndroid Build Coastguard Worker static int warnings = 0;
log_callback(int type,const char * fmt,...)275*e4a36f41SAndroid Build Coastguard Worker static int log_callback(int type, const char *fmt, ...) {
276*e4a36f41SAndroid Build Coastguard Worker va_list ap;
277*e4a36f41SAndroid Build Coastguard Worker
278*e4a36f41SAndroid Build Coastguard Worker if (type == SELINUX_WARNING) {
279*e4a36f41SAndroid Build Coastguard Worker warnings += 1;
280*e4a36f41SAndroid Build Coastguard Worker }
281*e4a36f41SAndroid Build Coastguard Worker va_start(ap, fmt);
282*e4a36f41SAndroid Build Coastguard Worker vfprintf(stderr, fmt, ap);
283*e4a36f41SAndroid Build Coastguard Worker va_end(ap);
284*e4a36f41SAndroid Build Coastguard Worker return 0;
285*e4a36f41SAndroid Build Coastguard Worker }
286*e4a36f41SAndroid Build Coastguard Worker
do_test_data_and_die_on_error(struct selinux_opt opts[],unsigned int backend,char * paths[])287*e4a36f41SAndroid Build Coastguard Worker static void do_test_data_and_die_on_error(struct selinux_opt opts[], unsigned int backend,
288*e4a36f41SAndroid Build Coastguard Worker char *paths[])
289*e4a36f41SAndroid Build Coastguard Worker {
290*e4a36f41SAndroid Build Coastguard Worker opts[0].value = NULL; /* not validating against a policy */
291*e4a36f41SAndroid Build Coastguard Worker opts[1].value = paths[0];
292*e4a36f41SAndroid Build Coastguard Worker global_state.sepolicy.sehnd[0] = selabel_open(backend, opts, 2);
293*e4a36f41SAndroid Build Coastguard Worker if (!global_state.sepolicy.sehnd[0]) {
294*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Error: could not load context file from %s: %s\n",
295*e4a36f41SAndroid Build Coastguard Worker paths[0], strerror(errno));
296*e4a36f41SAndroid Build Coastguard Worker exit(1);
297*e4a36f41SAndroid Build Coastguard Worker }
298*e4a36f41SAndroid Build Coastguard Worker
299*e4a36f41SAndroid Build Coastguard Worker FILE* test_data = fopen(paths[1], "r");
300*e4a36f41SAndroid Build Coastguard Worker if (test_data == NULL) {
301*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Error: could not load test file from %s : %s\n",
302*e4a36f41SAndroid Build Coastguard Worker paths[1], strerror(errno));
303*e4a36f41SAndroid Build Coastguard Worker exit(1);
304*e4a36f41SAndroid Build Coastguard Worker }
305*e4a36f41SAndroid Build Coastguard Worker
306*e4a36f41SAndroid Build Coastguard Worker char line[1024];
307*e4a36f41SAndroid Build Coastguard Worker bool non_matching_entries = false;
308*e4a36f41SAndroid Build Coastguard Worker while (fgets(line, sizeof(line), test_data)) {
309*e4a36f41SAndroid Build Coastguard Worker char *path;
310*e4a36f41SAndroid Build Coastguard Worker char *expected_type;
311*e4a36f41SAndroid Build Coastguard Worker
312*e4a36f41SAndroid Build Coastguard Worker if (!strcmp(line, "\n") || line[0] == '#') {
313*e4a36f41SAndroid Build Coastguard Worker continue;
314*e4a36f41SAndroid Build Coastguard Worker }
315*e4a36f41SAndroid Build Coastguard Worker
316*e4a36f41SAndroid Build Coastguard Worker int ret = sscanf(line, "%ms %ms", &path, &expected_type);
317*e4a36f41SAndroid Build Coastguard Worker if (ret != 2) {
318*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Error: unable to parse the line %s\n", line);
319*e4a36f41SAndroid Build Coastguard Worker exit(1);
320*e4a36f41SAndroid Build Coastguard Worker }
321*e4a36f41SAndroid Build Coastguard Worker
322*e4a36f41SAndroid Build Coastguard Worker char *found_context;
323*e4a36f41SAndroid Build Coastguard Worker ret = selabel_lookup(global_state.sepolicy.sehnd[0], &found_context, path, 0);
324*e4a36f41SAndroid Build Coastguard Worker if (ret != 0) {
325*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Error: unable to lookup the path for %s\n", line);
326*e4a36f41SAndroid Build Coastguard Worker exit(1);
327*e4a36f41SAndroid Build Coastguard Worker }
328*e4a36f41SAndroid Build Coastguard Worker
329*e4a36f41SAndroid Build Coastguard Worker context_t found = context_new(found_context);
330*e4a36f41SAndroid Build Coastguard Worker const char *found_type = context_type_get(found);
331*e4a36f41SAndroid Build Coastguard Worker
332*e4a36f41SAndroid Build Coastguard Worker if (strcmp(found_type, expected_type)) {
333*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Incorrect type for %s: resolved to %s, expected %s\n",
334*e4a36f41SAndroid Build Coastguard Worker path, found_type, expected_type);
335*e4a36f41SAndroid Build Coastguard Worker non_matching_entries = true;
336*e4a36f41SAndroid Build Coastguard Worker }
337*e4a36f41SAndroid Build Coastguard Worker
338*e4a36f41SAndroid Build Coastguard Worker free(found_context);
339*e4a36f41SAndroid Build Coastguard Worker context_free(found);
340*e4a36f41SAndroid Build Coastguard Worker free(path);
341*e4a36f41SAndroid Build Coastguard Worker free(expected_type);
342*e4a36f41SAndroid Build Coastguard Worker }
343*e4a36f41SAndroid Build Coastguard Worker fclose(test_data);
344*e4a36f41SAndroid Build Coastguard Worker
345*e4a36f41SAndroid Build Coastguard Worker if (non_matching_entries) {
346*e4a36f41SAndroid Build Coastguard Worker exit(1);
347*e4a36f41SAndroid Build Coastguard Worker }
348*e4a36f41SAndroid Build Coastguard Worker
349*e4a36f41SAndroid Build Coastguard Worker // Prints the coverage of file_contexts on the test data. It includes
350*e4a36f41SAndroid Build Coastguard Worker // warnings for rules that have not been hit by any test example.
351*e4a36f41SAndroid Build Coastguard Worker union selinux_callback cb;
352*e4a36f41SAndroid Build Coastguard Worker cb.func_log = log_callback;
353*e4a36f41SAndroid Build Coastguard Worker selinux_set_callback(SELINUX_CB_LOG, cb);
354*e4a36f41SAndroid Build Coastguard Worker selabel_stats(global_state.sepolicy.sehnd[0]);
355*e4a36f41SAndroid Build Coastguard Worker if (warnings) {
356*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "No test entries were found for the contexts above. " \
357*e4a36f41SAndroid Build Coastguard Worker "You may need to update %s.\n", paths[1]);
358*e4a36f41SAndroid Build Coastguard Worker exit(1);
359*e4a36f41SAndroid Build Coastguard Worker }
360*e4a36f41SAndroid Build Coastguard Worker }
361*e4a36f41SAndroid Build Coastguard Worker
do_fc_check_and_die_on_error(struct selinux_opt opts[],unsigned int backend,filemode mode,const char * sepolicy_file,const char * context_file,bool allow_empty)362*e4a36f41SAndroid Build Coastguard Worker static void do_fc_check_and_die_on_error(struct selinux_opt opts[], unsigned int backend, filemode mode,
363*e4a36f41SAndroid Build Coastguard Worker const char *sepolicy_file, const char *context_file, bool allow_empty)
364*e4a36f41SAndroid Build Coastguard Worker {
365*e4a36f41SAndroid Build Coastguard Worker struct stat sb;
366*e4a36f41SAndroid Build Coastguard Worker if (stat(context_file, &sb) < 0) {
367*e4a36f41SAndroid Build Coastguard Worker perror("Error: could not get stat on file contexts file");
368*e4a36f41SAndroid Build Coastguard Worker exit(1);
369*e4a36f41SAndroid Build Coastguard Worker }
370*e4a36f41SAndroid Build Coastguard Worker
371*e4a36f41SAndroid Build Coastguard Worker if (sb.st_size == 0) {
372*e4a36f41SAndroid Build Coastguard Worker /* Nothing to check on empty file_contexts file if allowed*/
373*e4a36f41SAndroid Build Coastguard Worker if (allow_empty) {
374*e4a36f41SAndroid Build Coastguard Worker return;
375*e4a36f41SAndroid Build Coastguard Worker }
376*e4a36f41SAndroid Build Coastguard Worker /* else: We could throw the error here, but libselinux backend will catch it */
377*e4a36f41SAndroid Build Coastguard Worker }
378*e4a36f41SAndroid Build Coastguard Worker
379*e4a36f41SAndroid Build Coastguard Worker global_state.sepolicy.file = fopen(sepolicy_file, "r");
380*e4a36f41SAndroid Build Coastguard Worker if (!global_state.sepolicy.file) {
381*e4a36f41SAndroid Build Coastguard Worker perror("Error: could not open policy file");
382*e4a36f41SAndroid Build Coastguard Worker exit(1);
383*e4a36f41SAndroid Build Coastguard Worker }
384*e4a36f41SAndroid Build Coastguard Worker
385*e4a36f41SAndroid Build Coastguard Worker global_state.sepolicy.handle = sepol_handle_create();
386*e4a36f41SAndroid Build Coastguard Worker if (!global_state.sepolicy.handle) {
387*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Error: could not create policy handle: %s\n", strerror(errno));
388*e4a36f41SAndroid Build Coastguard Worker exit(1);
389*e4a36f41SAndroid Build Coastguard Worker }
390*e4a36f41SAndroid Build Coastguard Worker
391*e4a36f41SAndroid Build Coastguard Worker if (sepol_policy_file_create(&global_state.sepolicy.pf) < 0) {
392*e4a36f41SAndroid Build Coastguard Worker perror("Error: could not create policy handle");
393*e4a36f41SAndroid Build Coastguard Worker exit(1);
394*e4a36f41SAndroid Build Coastguard Worker }
395*e4a36f41SAndroid Build Coastguard Worker
396*e4a36f41SAndroid Build Coastguard Worker sepol_policy_file_set_fp(global_state.sepolicy.pf, global_state.sepolicy.file);
397*e4a36f41SAndroid Build Coastguard Worker sepol_policy_file_set_handle(global_state.sepolicy.pf, global_state.sepolicy.handle);
398*e4a36f41SAndroid Build Coastguard Worker
399*e4a36f41SAndroid Build Coastguard Worker int rc = sepol_policydb_create(&global_state.sepolicy.sdb);
400*e4a36f41SAndroid Build Coastguard Worker if (rc < 0) {
401*e4a36f41SAndroid Build Coastguard Worker perror("Error: could not create policy db");
402*e4a36f41SAndroid Build Coastguard Worker exit(1);
403*e4a36f41SAndroid Build Coastguard Worker }
404*e4a36f41SAndroid Build Coastguard Worker
405*e4a36f41SAndroid Build Coastguard Worker rc = sepol_policydb_read(global_state.sepolicy.sdb, global_state.sepolicy.pf);
406*e4a36f41SAndroid Build Coastguard Worker if (rc < 0) {
407*e4a36f41SAndroid Build Coastguard Worker perror("Error: could not read file into policy db");
408*e4a36f41SAndroid Build Coastguard Worker exit(1);
409*e4a36f41SAndroid Build Coastguard Worker }
410*e4a36f41SAndroid Build Coastguard Worker
411*e4a36f41SAndroid Build Coastguard Worker global_state.assert.attrs = filemode_to_assert_attrs(mode);
412*e4a36f41SAndroid Build Coastguard Worker
413*e4a36f41SAndroid Build Coastguard Worker bool ret = ebitmap_attribute_assertion_init(&global_state.assert.set, global_state.assert.attrs);
414*e4a36f41SAndroid Build Coastguard Worker if (!ret) {
415*e4a36f41SAndroid Build Coastguard Worker /* error messages logged by ebitmap_attribute_assertion_init() */
416*e4a36f41SAndroid Build Coastguard Worker exit(1);
417*e4a36f41SAndroid Build Coastguard Worker }
418*e4a36f41SAndroid Build Coastguard Worker
419*e4a36f41SAndroid Build Coastguard Worker selinux_set_callback(SELINUX_CB_VALIDATE,
420*e4a36f41SAndroid Build Coastguard Worker (union selinux_callback)&validate);
421*e4a36f41SAndroid Build Coastguard Worker
422*e4a36f41SAndroid Build Coastguard Worker opts[1].value = context_file;
423*e4a36f41SAndroid Build Coastguard Worker
424*e4a36f41SAndroid Build Coastguard Worker global_state.sepolicy.sehnd[0] = selabel_open(backend, opts, 2);
425*e4a36f41SAndroid Build Coastguard Worker if (!global_state.sepolicy.sehnd[0]) {
426*e4a36f41SAndroid Build Coastguard Worker fprintf(stderr, "Error: could not load context file from %s\n", context_file);
427*e4a36f41SAndroid Build Coastguard Worker exit(1);
428*e4a36f41SAndroid Build Coastguard Worker }
429*e4a36f41SAndroid Build Coastguard Worker }
430*e4a36f41SAndroid Build Coastguard Worker
main(int argc,char ** argv)431*e4a36f41SAndroid Build Coastguard Worker int main(int argc, char **argv)
432*e4a36f41SAndroid Build Coastguard Worker {
433*e4a36f41SAndroid Build Coastguard Worker struct selinux_opt opts[] = {
434*e4a36f41SAndroid Build Coastguard Worker { SELABEL_OPT_VALIDATE, (void*)1 },
435*e4a36f41SAndroid Build Coastguard Worker { SELABEL_OPT_PATH, NULL }
436*e4a36f41SAndroid Build Coastguard Worker };
437*e4a36f41SAndroid Build Coastguard Worker
438*e4a36f41SAndroid Build Coastguard Worker // Default backend unless changed by input argument.
439*e4a36f41SAndroid Build Coastguard Worker unsigned int backend = SELABEL_CTX_FILE;
440*e4a36f41SAndroid Build Coastguard Worker
441*e4a36f41SAndroid Build Coastguard Worker bool allow_empty = false;
442*e4a36f41SAndroid Build Coastguard Worker bool compare = false;
443*e4a36f41SAndroid Build Coastguard Worker bool test_data = false;
444*e4a36f41SAndroid Build Coastguard Worker char c;
445*e4a36f41SAndroid Build Coastguard Worker
446*e4a36f41SAndroid Build Coastguard Worker filemode mode = filemode_file_contexts;
447*e4a36f41SAndroid Build Coastguard Worker
448*e4a36f41SAndroid Build Coastguard Worker while ((c = getopt(argc, argv, "clpsvet")) != -1) {
449*e4a36f41SAndroid Build Coastguard Worker switch (c) {
450*e4a36f41SAndroid Build Coastguard Worker case 'c':
451*e4a36f41SAndroid Build Coastguard Worker compare = true;
452*e4a36f41SAndroid Build Coastguard Worker break;
453*e4a36f41SAndroid Build Coastguard Worker case 'e':
454*e4a36f41SAndroid Build Coastguard Worker allow_empty = true;
455*e4a36f41SAndroid Build Coastguard Worker break;
456*e4a36f41SAndroid Build Coastguard Worker case 'p':
457*e4a36f41SAndroid Build Coastguard Worker mode = filemode_property_contexts;
458*e4a36f41SAndroid Build Coastguard Worker backend = SELABEL_CTX_ANDROID_PROP;
459*e4a36f41SAndroid Build Coastguard Worker break;
460*e4a36f41SAndroid Build Coastguard Worker case 's':
461*e4a36f41SAndroid Build Coastguard Worker mode = filemode_service_contexts;
462*e4a36f41SAndroid Build Coastguard Worker backend = SELABEL_CTX_ANDROID_SERVICE;
463*e4a36f41SAndroid Build Coastguard Worker break;
464*e4a36f41SAndroid Build Coastguard Worker case 'l':
465*e4a36f41SAndroid Build Coastguard Worker mode = filemode_hw_service_contexts;
466*e4a36f41SAndroid Build Coastguard Worker backend = SELABEL_CTX_ANDROID_SERVICE;
467*e4a36f41SAndroid Build Coastguard Worker break;
468*e4a36f41SAndroid Build Coastguard Worker case 'v':
469*e4a36f41SAndroid Build Coastguard Worker mode = filemode_vendor_service_contexts;
470*e4a36f41SAndroid Build Coastguard Worker backend = SELABEL_CTX_ANDROID_SERVICE;
471*e4a36f41SAndroid Build Coastguard Worker break;
472*e4a36f41SAndroid Build Coastguard Worker case 't':
473*e4a36f41SAndroid Build Coastguard Worker test_data = true;
474*e4a36f41SAndroid Build Coastguard Worker break;
475*e4a36f41SAndroid Build Coastguard Worker case 'h':
476*e4a36f41SAndroid Build Coastguard Worker default:
477*e4a36f41SAndroid Build Coastguard Worker usage(argv[0]);
478*e4a36f41SAndroid Build Coastguard Worker break;
479*e4a36f41SAndroid Build Coastguard Worker }
480*e4a36f41SAndroid Build Coastguard Worker }
481*e4a36f41SAndroid Build Coastguard Worker
482*e4a36f41SAndroid Build Coastguard Worker int index = optind;
483*e4a36f41SAndroid Build Coastguard Worker if (argc - optind != 2) {
484*e4a36f41SAndroid Build Coastguard Worker usage(argv[0]);
485*e4a36f41SAndroid Build Coastguard Worker }
486*e4a36f41SAndroid Build Coastguard Worker
487*e4a36f41SAndroid Build Coastguard Worker if ((compare || test_data) && backend != SELABEL_CTX_FILE) {
488*e4a36f41SAndroid Build Coastguard Worker usage(argv[0]);
489*e4a36f41SAndroid Build Coastguard Worker }
490*e4a36f41SAndroid Build Coastguard Worker
491*e4a36f41SAndroid Build Coastguard Worker atexit(cleanup);
492*e4a36f41SAndroid Build Coastguard Worker
493*e4a36f41SAndroid Build Coastguard Worker if (compare) {
494*e4a36f41SAndroid Build Coastguard Worker do_compare_and_die_on_error(opts, backend, &(argv[index]));
495*e4a36f41SAndroid Build Coastguard Worker } else if (test_data) {
496*e4a36f41SAndroid Build Coastguard Worker do_test_data_and_die_on_error(opts, backend, &(argv[index]));
497*e4a36f41SAndroid Build Coastguard Worker } else {
498*e4a36f41SAndroid Build Coastguard Worker /* remaining args are sepolicy file and context file */
499*e4a36f41SAndroid Build Coastguard Worker char *sepolicy_file = argv[index];
500*e4a36f41SAndroid Build Coastguard Worker char *context_file = argv[index + 1];
501*e4a36f41SAndroid Build Coastguard Worker
502*e4a36f41SAndroid Build Coastguard Worker do_fc_check_and_die_on_error(opts, backend, mode, sepolicy_file, context_file, allow_empty);
503*e4a36f41SAndroid Build Coastguard Worker }
504*e4a36f41SAndroid Build Coastguard Worker exit(0);
505*e4a36f41SAndroid Build Coastguard Worker }
506