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