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