Home | History | Annotate | Download | only in src
      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 
     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 
     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 
     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)))
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    264 unsigned strs_num_items(struct strs *strs)
    265 {
    266 	return strs->num;
    267 }
    268 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    403 int strs_stack_init(struct strs **stack)
    404 {
    405 	return strs_init(stack, STACK_SIZE);
    406 }
    407 
    408 void strs_stack_destroy(struct strs **stack)
    409 {
    410 	return strs_destroy(stack);
    411 }
    412 
    413 int strs_stack_push(struct strs *stack, char *s)
    414 {
    415 	return strs_add(stack, s);
    416 }
    417 
    418 char *strs_stack_pop(struct strs *stack)
    419 {
    420 	return strs_remove_last(stack);
    421 }
    422 
    423 int strs_stack_empty(struct strs *stack)
    424 {
    425 	return strs_num_items(stack) == 0;
    426 }
    427 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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