1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include <string.h>
5 #include <sys/types.h>
6 #include <unistd.h>
7
8 #include <arpa/inet.h>
9 #include <netinet/in.h>
10 #ifndef IPPROTO_DCCP
11 #define IPPROTO_DCCP 33
12 #endif
13 #ifndef IPPROTO_SCTP
14 #define IPPROTO_SCTP 132
15 #endif
16
17 #include <sepol/policydb/ebitmap.h>
18 #include <sepol/policydb/hashtab.h>
19 #include <sepol/policydb/symtab.h>
20
21 #include "kernel_to_common.h"
22
23
sepol_log_err(const char * fmt,...)24 void sepol_log_err(const char *fmt, ...)
25 {
26 va_list argptr;
27 va_start(argptr, fmt);
28 if (vfprintf(stderr, fmt, argptr) < 0) {
29 _exit(EXIT_FAILURE);
30 }
31 va_end(argptr);
32 if (fprintf(stderr, "\n") < 0) {
33 _exit(EXIT_FAILURE);
34 }
35 }
36
sepol_indent(FILE * out,int indent)37 void sepol_indent(FILE *out, int indent)
38 {
39 if (fprintf(out, "%*s", indent * 4, "") < 0) {
40 sepol_log_err("Failed to write to output");
41 }
42 }
43
sepol_printf(FILE * out,const char * fmt,...)44 void sepol_printf(FILE *out, const char *fmt, ...)
45 {
46 va_list argptr;
47 va_start(argptr, fmt);
48 if (vfprintf(out, fmt, argptr) < 0) {
49 sepol_log_err("Failed to write to output");
50 }
51 va_end(argptr);
52 }
53
54 __attribute__ ((format(printf, 1, 0)))
create_str_helper(const char * fmt,int num,va_list vargs)55 static char *create_str_helper(const char *fmt, int num, va_list vargs)
56 {
57 va_list vargs2;
58 char *str = NULL;
59 char *s;
60 size_t len;
61 int i, rc;
62
63 va_copy(vargs2, vargs);
64
65 len = strlen(fmt) + 1; /* +1 for '\0' */
66
67 for (i=0; i<num; i++) {
68 s = va_arg(vargs, char *);
69 len += strlen(s) - 2; /* -2 for each %s in fmt */
70 }
71
72 str = malloc(len);
73 if (!str) {
74 sepol_log_err("Out of memory");
75 goto exit;
76 }
77
78 rc = vsnprintf(str, len, fmt, vargs2);
79 if (rc < 0 || rc >= (int)len) {
80 goto exit;
81 }
82
83 va_end(vargs2);
84
85 return str;
86
87 exit:
88 free(str);
89 va_end(vargs2);
90 return NULL;
91 }
92
create_str(const char * fmt,int num,...)93 char *create_str(const char *fmt, int num, ...)
94 {
95 char *str = NULL;
96 va_list vargs;
97
98 va_start(vargs, num);
99 str = create_str_helper(fmt, num, vargs);
100 va_end(vargs);
101
102 return str;
103 }
104
strs_init(struct strs ** strs,size_t size)105 int strs_init(struct strs **strs, size_t size)
106 {
107 struct strs *new;
108
109 *strs = NULL;
110
111 new = malloc(sizeof(struct strs));
112 if (!new) {
113 sepol_log_err("Out of memory");
114 return -1;
115 }
116
117 new->list = calloc(sizeof(char *), size);
118 if (!new->list) {
119 sepol_log_err("Out of memory");
120 free(new);
121 return -1;
122 }
123
124 new->num = 0;
125 new->size = size;
126
127 *strs = new;
128
129 return 0;
130 }
131
strs_destroy(struct strs ** strs)132 void strs_destroy(struct strs **strs)
133 {
134 if (!strs || !*strs) {
135 return;
136 }
137
138 free((*strs)->list);
139 (*strs)->list = NULL;
140 (*strs)->num = 0;
141 (*strs)->size = 0;
142 free(*strs);
143 *strs = NULL;
144 }
145
strs_free_all(struct strs * strs)146 void strs_free_all(struct strs *strs)
147 {
148 if (!strs) {
149 return;
150 }
151
152 while (strs->num > 0) {
153 strs->num--;
154 free(strs->list[strs->num]);
155 }
156 }
157
strs_add(struct strs * strs,char * s)158 int strs_add(struct strs *strs, char *s)
159 {
160 if (strs->num + 1 > strs->size) {
161 char **new;
162 unsigned i = strs->size;
163 strs->size *= 2;
164 new = realloc(strs->list, sizeof(char *)*strs->size);
165 if (!new) {
166 sepol_log_err("Out of memory");
167 return -1;
168 }
169 strs->list = new;
170 memset(&strs->list[i], 0, sizeof(char *)*(strs->size-i));
171 }
172
173 strs->list[strs->num] = s;
174 strs->num++;
175
176 return 0;
177 }
178
strs_create_and_add(struct strs * strs,const char * fmt,int num,...)179 int strs_create_and_add(struct strs *strs, const char *fmt, int num, ...)
180 {
181 char *str;
182 va_list vargs;
183 int rc;
184
185 va_start(vargs, num);
186 str = create_str_helper(fmt, num, vargs);
187 va_end(vargs);
188
189 if (!str) {
190 rc = -1;
191 goto exit;
192 }
193
194 rc = strs_add(strs, str);
195 if (rc != 0) {
196 free(str);
197 goto exit;
198 }
199
200 return 0;
201
202 exit:
203 return rc;
204 }
205
strs_remove_last(struct strs * strs)206 char *strs_remove_last(struct strs *strs)
207 {
208 if (strs->num == 0) {
209 return NULL;
210 }
211 strs->num--;
212 return strs->list[strs->num];
213 }
214
strs_add_at_index(struct strs * strs,char * s,unsigned index)215 int strs_add_at_index(struct strs *strs, char *s, unsigned index)
216 {
217 if (index >= strs->size) {
218 char **new;
219 unsigned i = strs->size;
220 while (index >= strs->size) {
221 strs->size *= 2;
222 }
223 new = realloc(strs->list, sizeof(char *)*strs->size);
224 if (!new) {
225 sepol_log_err("Out of memory");
226 return -1;
227 }
228 strs->list = new;
229 memset(&strs->list[i], 0, sizeof(char *)*(strs->size - i));
230 }
231
232 strs->list[index] = s;
233 if (index >= strs->num) {
234 strs->num = index+1;
235 }
236
237 return 0;
238 }
239
strs_read_at_index(struct strs * strs,unsigned index)240 char *strs_read_at_index(struct strs *strs, unsigned index)
241 {
242 if (index >= strs->num) {
243 return NULL;
244 }
245
246 return strs->list[index];
247 }
248
strs_cmp(const void * a,const void * b)249 static int strs_cmp(const void *a, const void *b)
250 {
251 char *const *aa = a;
252 char *const *bb = b;
253 return strcmp(*aa,*bb);
254 }
255
strs_sort(struct strs * strs)256 void strs_sort(struct strs *strs)
257 {
258 if (strs->num == 0) {
259 return;
260 }
261 qsort(strs->list, strs->num, sizeof(char *), strs_cmp);
262 }
263
strs_num_items(struct strs * strs)264 unsigned strs_num_items(struct strs *strs)
265 {
266 return strs->num;
267 }
268
strs_len_items(struct strs * strs)269 size_t strs_len_items(struct strs *strs)
270 {
271 unsigned i;
272 size_t len = 0;
273
274 for (i=0; i<strs->num; i++) {
275 if (!strs->list[i]) continue;
276 len += strlen(strs->list[i]);
277 }
278
279 return len;
280 }
281
strs_to_str(struct strs * strs)282 char *strs_to_str(struct strs *strs)
283 {
284 char *str = NULL;
285 size_t len = 0;
286 char *p;
287 unsigned i;
288 int rc;
289
290 if (strs->num == 0) {
291 goto exit;
292 }
293
294 /* strs->num added because either ' ' or '\0' follows each item */
295 len = strs_len_items(strs) + strs->num;
296 str = malloc(len);
297 if (!str) {
298 sepol_log_err("Out of memory");
299 goto exit;
300 }
301
302 p = str;
303 for (i=0; i<strs->num; i++) {
304 if (!strs->list[i]) continue;
305 len = strlen(strs->list[i]);
306 rc = snprintf(p, len+1, "%s", strs->list[i]);
307 if (rc < 0 || rc > (int)len) {
308 free(str);
309 str = NULL;
310 goto exit;
311 }
312 p += len;
313 if (i < strs->num - 1) {
314 *p++ = ' ';
315 }
316 }
317
318 *p = '\0';
319
320 exit:
321 return str;
322 }
323
strs_write_each(struct strs * strs,FILE * out)324 void strs_write_each(struct strs *strs, FILE *out)
325 {
326 unsigned i;
327
328 for (i=0; i<strs->num; i++) {
329 if (!strs->list[i]) {
330 continue;
331 }
332 sepol_printf(out, "%s\n",strs->list[i]);
333 }
334 }
335
strs_write_each_indented(struct strs * strs,FILE * out,int indent)336 void strs_write_each_indented(struct strs *strs, FILE *out, int indent)
337 {
338 unsigned i;
339
340 for (i=0; i<strs->num; i++) {
341 if (!strs->list[i]) {
342 continue;
343 }
344 sepol_indent(out, indent);
345 sepol_printf(out, "%s\n",strs->list[i]);
346 }
347 }
348
hashtab_ordered_to_strs(char * key,void * data,void * args)349 int hashtab_ordered_to_strs(char *key, void *data, void *args)
350 {
351 struct strs *strs = (struct strs *)args;
352 symtab_datum_t *datum = data;
353
354 return strs_add_at_index(strs, key, datum->value-1);
355 }
356
ebitmap_to_strs(struct ebitmap * map,struct strs * strs,char ** val_to_name)357 int ebitmap_to_strs(struct ebitmap *map, struct strs *strs, char **val_to_name)
358 {
359 struct ebitmap_node *node;
360 uint32_t i;
361 int rc;
362
363 ebitmap_for_each_bit(map, node, i) {
364 if (!ebitmap_get_bit(map, i)) continue;
365
366 rc = strs_add(strs, val_to_name[i]);
367 if (rc != 0) {
368 return -1;
369 }
370 }
371
372 return 0;
373 }
374
ebitmap_to_str(struct ebitmap * map,char ** val_to_name,int sort)375 char *ebitmap_to_str(struct ebitmap *map, char **val_to_name, int sort)
376 {
377 struct strs *strs;
378 char *str = NULL;
379 int rc;
380
381 rc = strs_init(&strs, 32);
382 if (rc != 0) {
383 goto exit;
384 }
385
386 rc = ebitmap_to_strs(map, strs, val_to_name);
387 if (rc != 0) {
388 goto exit;
389 }
390
391 if (sort) {
392 strs_sort(strs);
393 }
394
395 str = strs_to_str(strs);
396
397 exit:
398 strs_destroy(&strs);
399
400 return str;
401 }
402
strs_stack_init(struct strs ** stack)403 int strs_stack_init(struct strs **stack)
404 {
405 return strs_init(stack, STACK_SIZE);
406 }
407
strs_stack_destroy(struct strs ** stack)408 void strs_stack_destroy(struct strs **stack)
409 {
410 return strs_destroy(stack);
411 }
412
strs_stack_push(struct strs * stack,char * s)413 int strs_stack_push(struct strs *stack, char *s)
414 {
415 return strs_add(stack, s);
416 }
417
strs_stack_pop(struct strs * stack)418 char *strs_stack_pop(struct strs *stack)
419 {
420 return strs_remove_last(stack);
421 }
422
strs_stack_empty(struct strs * stack)423 int strs_stack_empty(struct strs *stack)
424 {
425 return strs_num_items(stack) == 0;
426 }
427
compare_ranges(uint64_t l1,uint64_t h1,uint64_t l2,uint64_t h2)428 static int compare_ranges(uint64_t l1, uint64_t h1, uint64_t l2, uint64_t h2)
429 {
430 uint64_t d1, d2;
431
432 d1 = h1-l1;
433 d2 = h2-l2;
434
435 if (d1 < d2) {
436 return -1;
437 } else if (d1 > d2) {
438 return 1;
439 } else {
440 if (l1 < l2) {
441 return -1;
442 } else if (l1 > l2) {
443 return 1;
444 }
445 }
446
447 return 0;
448 }
449
fsuse_data_cmp(const void * a,const void * b)450 static int fsuse_data_cmp(const void *a, const void *b)
451 {
452 struct ocontext *const *aa = a;
453 struct ocontext *const *bb = b;
454
455 if ((*aa)->v.behavior != (*bb)->v.behavior) {
456 if ((*aa)->v.behavior < (*bb)->v.behavior) {
457 return -1;
458 } else {
459 return 1;
460 }
461 }
462
463 return strcmp((*aa)->u.name, (*bb)->u.name);
464 }
465
portcon_data_cmp(const void * a,const void * b)466 static int portcon_data_cmp(const void *a, const void *b)
467 {
468 struct ocontext *const *aa = a;
469 struct ocontext *const *bb = b;
470 int rc;
471
472 rc = compare_ranges((*aa)->u.port.low_port, (*aa)->u.port.high_port,
473 (*bb)->u.port.low_port, (*bb)->u.port.high_port);
474 if (rc == 0) {
475 if ((*aa)->u.port.protocol == (*bb)->u.port.protocol) {
476 rc = 0;
477 } else if ((*aa)->u.port.protocol == IPPROTO_TCP) {
478 rc = -1;
479 } else {
480 rc = 1;
481 }
482 }
483
484 return rc;
485 }
486
netif_data_cmp(const void * a,const void * b)487 static int netif_data_cmp(const void *a, const void *b)
488 {
489 struct ocontext *const *aa = a;
490 struct ocontext *const *bb = b;
491
492 return strcmp((*aa)->u.name, (*bb)->u.name);
493 }
494
node_data_cmp(const void * a,const void * b)495 static int node_data_cmp(const void *a, const void *b)
496 {
497 struct ocontext *const *aa = a;
498 struct ocontext *const *bb = b;
499 int rc;
500
501 rc = memcmp(&(*aa)->u.node.mask, &(*bb)->u.node.mask, sizeof((*aa)->u.node.mask));
502 if (rc > 0) {
503 return -1;
504 } else if (rc < 0) {
505 return 1;
506 }
507
508 return memcmp(&(*aa)->u.node.addr, &(*bb)->u.node.addr, sizeof((*aa)->u.node.addr));
509 }
510
node6_data_cmp(const void * a,const void * b)511 static int node6_data_cmp(const void *a, const void *b)
512 {
513 struct ocontext *const *aa = a;
514 struct ocontext *const *bb = b;
515 int rc;
516
517 rc = memcmp(&(*aa)->u.node6.mask, &(*bb)->u.node6.mask, sizeof((*aa)->u.node6.mask));
518 if (rc > 0) {
519 return -1;
520 } else if (rc < 0) {
521 return 1;
522 }
523
524 return memcmp(&(*aa)->u.node6.addr, &(*bb)->u.node6.addr, sizeof((*aa)->u.node6.addr));
525 }
526
ibpkey_data_cmp(const void * a,const void * b)527 static int ibpkey_data_cmp(const void *a, const void *b)
528 {
529 int rc;
530 struct ocontext *const *aa = a;
531 struct ocontext *const *bb = b;
532
533 rc = (*aa)->u.ibpkey.subnet_prefix - (*bb)->u.ibpkey.subnet_prefix;
534 if (rc)
535 return rc;
536
537 return compare_ranges((*aa)->u.ibpkey.low_pkey, (*aa)->u.ibpkey.high_pkey,
538 (*bb)->u.ibpkey.low_pkey, (*bb)->u.ibpkey.high_pkey);
539 }
540
ibendport_data_cmp(const void * a,const void * b)541 static int ibendport_data_cmp(const void *a, const void *b)
542 {
543 int rc;
544 struct ocontext *const *aa = a;
545 struct ocontext *const *bb = b;
546
547 rc = strcmp((*aa)->u.ibendport.dev_name, (*bb)->u.ibendport.dev_name);
548 if (rc)
549 return rc;
550
551 return (*aa)->u.ibendport.port - (*bb)->u.ibendport.port;
552 }
553
pirq_data_cmp(const void * a,const void * b)554 static int pirq_data_cmp(const void *a, const void *b)
555 {
556 struct ocontext *const *aa = a;
557 struct ocontext *const *bb = b;
558
559 if ((*aa)->u.pirq < (*bb)->u.pirq) {
560 return -1;
561 } else if ((*aa)->u.pirq > (*bb)->u.pirq) {
562 return 1;
563 }
564
565 return 0;
566 }
567
ioport_data_cmp(const void * a,const void * b)568 static int ioport_data_cmp(const void *a, const void *b)
569 {
570 struct ocontext *const *aa = a;
571 struct ocontext *const *bb = b;
572
573 return compare_ranges((*aa)->u.ioport.low_ioport, (*aa)->u.ioport.high_ioport,
574 (*bb)->u.ioport.low_ioport, (*bb)->u.ioport.high_ioport);
575 }
576
iomem_data_cmp(const void * a,const void * b)577 static int iomem_data_cmp(const void *a, const void *b)
578 {
579 struct ocontext *const *aa = a;
580 struct ocontext *const *bb = b;
581
582 return compare_ranges((*aa)->u.iomem.low_iomem, (*aa)->u.iomem.high_iomem,
583 (*bb)->u.iomem.low_iomem, (*bb)->u.iomem.high_iomem);
584 }
585
pcid_data_cmp(const void * a,const void * b)586 static int pcid_data_cmp(const void *a, const void *b)
587 {
588 struct ocontext *const *aa = a;
589 struct ocontext *const *bb = b;
590
591 if ((*aa)->u.device < (*bb)->u.device) {
592 return -1;
593 } else if ((*aa)->u.device > (*bb)->u.device) {
594 return 1;
595 }
596
597 return 0;
598 }
599
dtree_data_cmp(const void * a,const void * b)600 static int dtree_data_cmp(const void *a, const void *b)
601 {
602 struct ocontext *const *aa = a;
603 struct ocontext *const *bb = b;
604
605 return strcmp((*aa)->u.name, (*bb)->u.name);
606 }
607
sort_ocontext_data(struct ocontext ** ocons,int (* cmp)(const void *,const void *))608 static int sort_ocontext_data(struct ocontext **ocons, int (*cmp)(const void *, const void *))
609 {
610 struct ocontext *ocon;
611 struct ocontext **data;
612 unsigned i, num;
613
614 num = 0;
615 for (ocon = *ocons; ocon != NULL; ocon = ocon->next) {
616 num++;
617 }
618
619 if (num == 0) {
620 return 0;
621 }
622
623 data = calloc(sizeof(*data), num);
624 if (!data) {
625 sepol_log_err("Out of memory\n");
626 return -1;
627 }
628
629 i = 0;
630 for (ocon = *ocons; ocon != NULL; ocon = ocon->next) {
631 data[i] = ocon;
632 i++;
633 }
634
635 qsort(data, num, sizeof(*data), cmp);
636
637 *ocons = data[0];
638 for (i=1; i < num; i++) {
639 data[i-1]->next = data[i];
640 }
641 data[num-1]->next = NULL;
642
643 free(data);
644
645 return 0;
646 }
647
sort_ocontexts(struct policydb * pdb)648 int sort_ocontexts(struct policydb *pdb)
649 {
650 int rc = 0;
651
652 if (pdb->target_platform == SEPOL_TARGET_SELINUX) {
653 rc = sort_ocontext_data(&pdb->ocontexts[5], fsuse_data_cmp);
654 if (rc != 0) {
655 goto exit;
656 }
657
658 rc = sort_ocontext_data(&pdb->ocontexts[2], portcon_data_cmp);
659 if (rc != 0) {
660 goto exit;
661 }
662
663 rc = sort_ocontext_data(&pdb->ocontexts[3], netif_data_cmp);
664 if (rc != 0) {
665 goto exit;
666 }
667
668 rc = sort_ocontext_data(&pdb->ocontexts[4], node_data_cmp);
669 if (rc != 0) {
670 goto exit;
671 }
672
673 rc = sort_ocontext_data(&pdb->ocontexts[6], node6_data_cmp);
674 if (rc != 0) {
675 goto exit;
676 }
677
678 rc = sort_ocontext_data(&pdb->ocontexts[OCON_IBPKEY], ibpkey_data_cmp);
679 if (rc != 0) {
680 goto exit;
681 }
682
683 rc = sort_ocontext_data(&pdb->ocontexts[OCON_IBENDPORT], ibendport_data_cmp);
684 if (rc != 0) {
685 goto exit;
686 }
687 } else if (pdb->target_platform == SEPOL_TARGET_XEN) {
688 rc = sort_ocontext_data(&pdb->ocontexts[1], pirq_data_cmp);
689 if (rc != 0) {
690 goto exit;
691 }
692
693 rc = sort_ocontext_data(&pdb->ocontexts[2], ioport_data_cmp);
694 if (rc != 0) {
695 goto exit;
696 }
697
698 rc = sort_ocontext_data(&pdb->ocontexts[3], iomem_data_cmp);
699 if (rc != 0) {
700 goto exit;
701 }
702
703 rc = sort_ocontext_data(&pdb->ocontexts[4], pcid_data_cmp);
704 if (rc != 0) {
705 goto exit;
706 }
707
708 rc = sort_ocontext_data(&pdb->ocontexts[5], dtree_data_cmp);
709 if (rc != 0) {
710 goto exit;
711 }
712 }
713
714 exit:
715 if (rc != 0) {
716 sepol_log_err("Error sorting ocontexts\n");
717 }
718
719 return rc;
720 }
721