1 #include <ctype.h>
2 #include <fcntl.h>
3 #include <getopt.h>
4 #include <stdbool.h>
5 #include <stdio.h>
6 #include <sys/mman.h>
7 #include <sys/stat.h>
8 #include <sys/types.h>
9 #include <unistd.h>
10
11 #include "neverallow.h"
12
13 static int debug;
14 static int warn;
15
neverallow_usage()16 void neverallow_usage() {
17 fprintf(stderr, "\tneverallow [-w|--warn] [-d|--debug] [-n|--neverallows <neverallow-rules>] | [-f|--file <neverallow-file>]\n");
18 }
19
read_typeset(policydb_t * policydb,char ** ptr,char * end,type_set_t * typeset,uint32_t * flags)20 static int read_typeset(policydb_t *policydb, char **ptr, char *end,
21 type_set_t *typeset, uint32_t *flags)
22 {
23 const char *keyword = "self";
24 size_t keyword_size = strlen(keyword), len;
25 char *p = *ptr;
26 unsigned openparens = 0;
27 char *start, *id;
28 type_datum_t *type;
29 struct ebitmap_node *n;
30 unsigned int bit;
31 bool negate = false;
32 int rc;
33
34 do {
35 while (p < end && isspace(*p))
36 p++;
37
38 if (p == end)
39 goto err;
40
41 if (*p == '~') {
42 if (debug)
43 printf(" ~");
44 typeset->flags = TYPE_COMP;
45 p++;
46 while (p < end && isspace(*p))
47 p++;
48 if (p == end)
49 goto err;
50 }
51
52 if (*p == '{') {
53 if (debug && !openparens)
54 printf(" {");
55 openparens++;
56 p++;
57 continue;
58 }
59
60 if (*p == '}') {
61 if (debug && openparens == 1)
62 printf(" }");
63 if (openparens == 0)
64 goto err;
65 openparens--;
66 p++;
67 continue;
68 }
69
70 if (*p == '*') {
71 if (debug)
72 printf(" *");
73 typeset->flags = TYPE_STAR;
74 p++;
75 continue;
76 }
77
78 if (*p == '-') {
79 if (debug)
80 printf(" -");
81 negate = true;
82 p++;
83 continue;
84 }
85
86 if (*p == '#') {
87 while (p < end && *p != '\n')
88 p++;
89 continue;
90 }
91
92 start = p;
93 while (p < end && !isspace(*p) && *p != ':' && *p != ';' && *p != '{' && *p != '}' && *p != '#')
94 p++;
95
96 if (p == start)
97 goto err;
98
99 len = p - start;
100 if (len == keyword_size && !strncmp(start, keyword, keyword_size)) {
101 if (debug)
102 printf(" self");
103 *flags |= RULE_SELF;
104 continue;
105 }
106
107 id = calloc(1, len + 1);
108 if (!id)
109 goto err;
110 memcpy(id, start, len);
111 if (debug)
112 printf(" %s", id);
113 type = hashtab_search(policydb->p_types.table, id);
114 if (!type) {
115 if (warn)
116 fprintf(stderr, "Warning! Type or attribute %s used in neverallow undefined in policy being checked.\n", id);
117 negate = false;
118 continue;
119 }
120 free(id);
121
122 if (type->flavor == TYPE_ATTRIB) {
123 if (negate)
124 rc = ebitmap_union(&typeset->negset, &policydb->attr_type_map[type->s.value - 1]);
125 else
126 rc = ebitmap_union(&typeset->types, &policydb->attr_type_map[type->s.value - 1]);
127 } else if (negate) {
128 rc = ebitmap_set_bit(&typeset->negset, type->s.value - 1, 1);
129 } else {
130 rc = ebitmap_set_bit(&typeset->types, type->s.value - 1, 1);
131 }
132
133 negate = false;
134
135 if (rc)
136 goto err;
137
138 } while (p < end && openparens);
139
140 if (p == end)
141 goto err;
142
143 if (typeset->flags & TYPE_STAR) {
144 for (bit = 0; bit < policydb->p_types.nprim; bit++) {
145 if (ebitmap_get_bit(&typeset->negset, bit))
146 continue;
147 if (policydb->type_val_to_struct[bit] &&
148 policydb->type_val_to_struct[bit]->flavor == TYPE_ATTRIB)
149 continue;
150 if (ebitmap_set_bit(&typeset->types, bit, 1))
151 goto err;
152 }
153 }
154
155 ebitmap_for_each_bit(&typeset->negset, n, bit) {
156 if (!ebitmap_node_get_bit(n, bit))
157 continue;
158 if (ebitmap_set_bit(&typeset->types, bit, 0))
159 goto err;
160 }
161
162 if (typeset->flags & TYPE_COMP) {
163 for (bit = 0; bit < policydb->p_types.nprim; bit++) {
164 if (policydb->type_val_to_struct[bit] &&
165 policydb->type_val_to_struct[bit]->flavor == TYPE_ATTRIB)
166 continue;
167 if (ebitmap_get_bit(&typeset->types, bit))
168 ebitmap_set_bit(&typeset->types, bit, 0);
169 else {
170 if (ebitmap_set_bit(&typeset->types, bit, 1))
171 goto err;
172 }
173 }
174 }
175
176 if (warn && ebitmap_length(&typeset->types) == 0 && !(*flags))
177 fprintf(stderr, "Warning! Empty type set\n");
178
179 *ptr = p;
180 return 0;
181 err:
182 return -1;
183 }
184
read_classperms(policydb_t * policydb,char ** ptr,char * end,class_perm_node_t ** perms)185 static int read_classperms(policydb_t *policydb, char **ptr, char *end,
186 class_perm_node_t **perms)
187 {
188 char *p = *ptr;
189 unsigned openparens = 0;
190 char *id, *start;
191 class_datum_t *cls = NULL;
192 perm_datum_t *perm = NULL;
193 class_perm_node_t *classperms = NULL, *node = NULL;
194 bool complement = false;
195
196 while (p < end && isspace(*p))
197 p++;
198
199 if (p == end || *p != ':')
200 goto err;
201 p++;
202
203 if (debug)
204 printf(" :");
205
206 do {
207 while (p < end && isspace(*p))
208 p++;
209
210 if (p == end)
211 goto err;
212
213 if (*p == '{') {
214 if (debug && !openparens)
215 printf(" {");
216 openparens++;
217 p++;
218 continue;
219 }
220
221 if (*p == '}') {
222 if (debug && openparens == 1)
223 printf(" }");
224 if (openparens == 0)
225 goto err;
226 openparens--;
227 p++;
228 continue;
229 }
230
231 if (*p == '#') {
232 while (p < end && *p != '\n')
233 p++;
234 continue;
235 }
236
237 start = p;
238 while (p < end && !isspace(*p) && *p != '{' && *p != '}' && *p != ';' && *p != '#')
239 p++;
240
241 if (p == start)
242 goto err;
243
244 id = calloc(1, p - start + 1);
245 if (!id)
246 goto err;
247 memcpy(id, start, p - start);
248 if (debug)
249 printf(" %s", id);
250 cls = hashtab_search(policydb->p_classes.table, id);
251 if (!cls) {
252 if (warn)
253 fprintf(stderr, "Warning! Class %s used in neverallow undefined in policy being checked.\n", id);
254 continue;
255 }
256
257 node = calloc(1, sizeof *node);
258 if (!node)
259 goto err;
260 node->tclass = cls->s.value;
261 node->next = classperms;
262 classperms = node;
263 free(id);
264 } while (p < end && openparens);
265
266 if (p == end)
267 goto err;
268
269 if (warn && !classperms)
270 fprintf(stderr, "Warning! Empty class set\n");
271
272 do {
273 while (p < end && isspace(*p))
274 p++;
275
276 if (p == end)
277 goto err;
278
279 if (*p == '~') {
280 if (debug)
281 printf(" ~");
282 complement = true;
283 p++;
284 while (p < end && isspace(*p))
285 p++;
286 if (p == end)
287 goto err;
288 }
289
290 if (*p == '{') {
291 if (debug && !openparens)
292 printf(" {");
293 openparens++;
294 p++;
295 continue;
296 }
297
298 if (*p == '}') {
299 if (debug && openparens == 1)
300 printf(" }");
301 if (openparens == 0)
302 goto err;
303 openparens--;
304 p++;
305 continue;
306 }
307
308 if (*p == '#') {
309 while (p < end && *p != '\n')
310 p++;
311 continue;
312 }
313
314 start = p;
315 while (p < end && !isspace(*p) && *p != '{' && *p != '}' && *p != ';' && *p != '#')
316 p++;
317
318 if (p == start)
319 goto err;
320
321 id = calloc(1, p - start + 1);
322 if (!id)
323 goto err;
324 memcpy(id, start, p - start);
325 if (debug)
326 printf(" %s", id);
327
328 if (!strcmp(id, "*")) {
329 for (node = classperms; node; node = node->next)
330 node->data = ~0;
331 continue;
332 }
333
334 for (node = classperms; node; node = node->next) {
335 cls = policydb->class_val_to_struct[node->tclass-1];
336 perm = hashtab_search(cls->permissions.table, id);
337 if (cls->comdatum && !perm)
338 perm = hashtab_search(cls->comdatum->permissions.table, id);
339 if (!perm) {
340 if (warn)
341 fprintf(stderr, "Warning! Permission %s used in neverallow undefined in class %s in policy being checked.\n", id, policydb->p_class_val_to_name[node->tclass-1]);
342 continue;
343 }
344 node->data |= 1U << (perm->s.value - 1);
345 }
346 free(id);
347 } while (p < end && openparens);
348
349 if (p == end)
350 goto err;
351
352 if (complement) {
353 for (node = classperms; node; node = node->next)
354 node->data = ~node->data;
355 }
356
357 if (warn) {
358 for (node = classperms; node; node = node->next)
359 if (!node->data)
360 fprintf(stderr, "Warning! Empty permission set\n");
361 }
362
363 *perms = classperms;
364 *ptr = p;
365 return 0;
366 err:
367 return -1;
368 }
369
check_neverallows(policydb_t * policydb,char * text,char * end)370 static int check_neverallows(policydb_t *policydb, char *text, char *end)
371 {
372 const char *keyword = "neverallow";
373 size_t keyword_size = strlen(keyword), len;
374 struct avrule *neverallows = NULL, *avrule;
375 char *p, *start;
376
377 p = text;
378 while (p < end) {
379 while (p < end && isspace(*p))
380 p++;
381
382 if (*p == '#') {
383 while (p < end && *p != '\n')
384 p++;
385 continue;
386 }
387
388 start = p;
389 while (p < end && !isspace(*p))
390 p++;
391
392 len = p - start;
393 if (len != keyword_size || strncmp(start, keyword, keyword_size))
394 continue;
395
396 if (debug)
397 printf("neverallow");
398
399 avrule = calloc(1, sizeof *avrule);
400 if (!avrule)
401 goto err;
402
403 avrule->specified = AVRULE_NEVERALLOW;
404
405 if (read_typeset(policydb, &p, end, &avrule->stypes, &avrule->flags))
406 goto err;
407
408 if (read_typeset(policydb, &p, end, &avrule->ttypes, &avrule->flags))
409 goto err;
410
411 if (read_classperms(policydb, &p, end, &avrule->perms))
412 goto err;
413
414 while (p < end && *p != ';')
415 p++;
416
417 if (p == end || *p != ';')
418 goto err;
419
420 if (debug)
421 printf(";\n");
422
423 avrule->next = neverallows;
424 neverallows = avrule;
425 }
426
427 if (!neverallows)
428 goto err;
429
430 return check_assertions(NULL, policydb, neverallows);
431 err:
432 if (errno == ENOMEM) {
433 fprintf(stderr, "Out of memory while parsing neverallow rules\n");
434 } else
435 fprintf(stderr, "Error while parsing neverallow rules\n");
436 return -1;
437 }
438
check_neverallows_file(policydb_t * policydb,const char * filename)439 static int check_neverallows_file(policydb_t *policydb, const char *filename)
440 {
441 int fd;
442 struct stat sb;
443 char *text, *end;
444
445 fd = open(filename, O_RDONLY);
446 if (fd < 0) {
447 fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
448 return -1;
449 }
450 if (fstat(fd, &sb) < 0) {
451 fprintf(stderr, "Can't stat '%s': %s\n", filename, strerror(errno));
452 close(fd);
453 return -1;
454 }
455 text = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
456 end = text + sb.st_size;
457 if (text == MAP_FAILED) {
458 fprintf(stderr, "Can't mmap '%s': %s\n", filename, strerror(errno));
459 close(fd);
460 return -1;
461 }
462 close(fd);
463 return check_neverallows(policydb, text, end);
464 }
465
check_neverallows_string(policydb_t * policydb,char * string,size_t len)466 static int check_neverallows_string(policydb_t *policydb, char *string, size_t len)
467 {
468 char *text, *end;
469 text = string;
470 end = text + len;
471 return check_neverallows(policydb, text, end);
472 }
473
neverallow_func(int argc,char ** argv,policydb_t * policydb)474 int neverallow_func (int argc, char **argv, policydb_t *policydb) {
475 char *rules = 0, *file = 0;
476 char ch;
477
478 struct option neverallow_options[] = {
479 {"debug", no_argument, NULL, 'd'},
480 {"file_input", required_argument, NULL, 'f'},
481 {"neverallow", required_argument, NULL, 'n'},
482 {"warn", no_argument, NULL, 'w'},
483 {NULL, 0, NULL, 0}
484 };
485
486 while ((ch = getopt_long(argc, argv, "df:n:w", neverallow_options, NULL)) != -1) {
487 switch (ch) {
488 case 'd':
489 debug = 1;
490 break;
491 case 'f':
492 file = optarg;
493 break;
494 case 'n':
495 rules = optarg;
496 break;
497 case 'w':
498 warn = 1;
499 break;
500 default:
501 USAGE_ERROR = true;
502 return -1;
503 }
504 }
505
506 if (!(rules || file) || (rules && file)){
507 USAGE_ERROR = true;
508 return -1;
509 }
510 if (file) {
511 return check_neverallows_file(policydb, file);
512 } else {
513 return check_neverallows_string(policydb, rules, strlen(rules));
514 }
515 }
516