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