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