xref: /aosp_15_r20/external/selinux/libsepol/src/module.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1 /* Author: Karl MacMillan <[email protected]>
2  *         Jason Tang     <[email protected]>
3  *         Chris PeBenito <[email protected]>
4  *
5  * Copyright (C) 2004-2005 Tresys Technology, LLC
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2.1 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #include "policydb_internal.h"
23 #include "module_internal.h"
24 #include <sepol/policydb/link.h>
25 #include <sepol/policydb/expand.h>
26 #include <sepol/policydb/module.h>
27 #include "debug.h"
28 #include "private.h"
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <limits.h>
33 #include <inttypes.h>
34 
35 #define SEPOL_PACKAGE_SECTION_FC 0xf97cff90
36 #define SEPOL_PACKAGE_SECTION_SEUSER 0x97cff91
37 #define SEPOL_PACKAGE_SECTION_USER_EXTRA 0x97cff92
38 #define SEPOL_PACKAGE_SECTION_NETFILTER 0x97cff93
39 
policy_file_seek(struct policy_file * fp,size_t offset)40 static int policy_file_seek(struct policy_file *fp, size_t offset)
41 {
42 	switch (fp->type) {
43 	case PF_USE_STDIO:
44 		if (offset > LONG_MAX) {
45 			errno = EFAULT;
46 			return -1;
47 		}
48 		return fseek(fp->fp, (long)offset, SEEK_SET);
49 	case PF_USE_MEMORY:
50 		if (offset > fp->size) {
51 			errno = EFAULT;
52 			return -1;
53 		}
54 		fp->data -= fp->size - fp->len;
55 		fp->data += offset;
56 		fp->len = fp->size - offset;
57 		return 0;
58 	default:
59 		return 0;
60 	}
61 }
62 
policy_file_length(struct policy_file * fp,size_t * out)63 static int policy_file_length(struct policy_file *fp, size_t *out)
64 {
65 	long prev_offset, end_offset;
66 	int rc;
67 	switch (fp->type) {
68 	case PF_USE_STDIO:
69 		prev_offset = ftell(fp->fp);
70 		if (prev_offset < 0)
71 			return prev_offset;
72 		rc = fseek(fp->fp, 0L, SEEK_END);
73 		if (rc < 0)
74 			return rc;
75 		end_offset = ftell(fp->fp);
76 		if (end_offset < 0)
77 			return end_offset;
78 		rc = fseek(fp->fp, prev_offset, SEEK_SET);
79 		if (rc < 0)
80 			return rc;
81 		*out = end_offset;
82 		break;
83 	case PF_USE_MEMORY:
84 		*out = fp->size;
85 		break;
86 	default:
87 		*out = 0;
88 		break;
89 	}
90 	return 0;
91 }
92 
module_package_init(sepol_module_package_t * p)93 static int module_package_init(sepol_module_package_t * p)
94 {
95 	memset(p, 0, sizeof(sepol_module_package_t));
96 	if (sepol_policydb_create(&p->policy))
97 		return -1;
98 
99 	p->version = 1;
100 	return 0;
101 }
102 
set_char(char ** field,char * data,size_t len)103 static int set_char(char **field, char *data, size_t len)
104 {
105 	if (*field) {
106 		free(*field);
107 		*field = NULL;
108 	}
109 	if (len) {
110 		*field = malloc(len);
111 		if (!*field)
112 			return -1;
113 		memcpy(*field, data, len);
114 	}
115 	return 0;
116 }
117 
sepol_module_package_create(sepol_module_package_t ** p)118 int sepol_module_package_create(sepol_module_package_t ** p)
119 {
120 	int rc;
121 
122 	*p = calloc(1, sizeof(sepol_module_package_t));
123 	if (!(*p))
124 		return -1;
125 
126 	rc = module_package_init(*p);
127 	if (rc < 0) {
128 		free(*p);
129 		*p = NULL;
130 	}
131 
132 	return rc;
133 }
134 
135 
136 /* Deallocates all memory associated with a module package, including
137  * the pointer itself.  Does nothing if p is NULL.
138  */
sepol_module_package_free(sepol_module_package_t * p)139 void sepol_module_package_free(sepol_module_package_t * p)
140 {
141 	if (p == NULL)
142 		return;
143 
144 	sepol_policydb_free(p->policy);
145 	free(p->file_contexts);
146 	free(p->seusers);
147 	free(p->user_extra);
148 	free(p->netfilter_contexts);
149 	free(p);
150 }
151 
152 
sepol_module_package_get_file_contexts(sepol_module_package_t * p)153 char *sepol_module_package_get_file_contexts(sepol_module_package_t * p)
154 {
155 	return p->file_contexts;
156 }
157 
sepol_module_package_get_file_contexts_len(sepol_module_package_t * p)158 size_t sepol_module_package_get_file_contexts_len(sepol_module_package_t * p)
159 {
160 	return p->file_contexts_len;
161 }
162 
sepol_module_package_get_seusers(sepol_module_package_t * p)163 char *sepol_module_package_get_seusers(sepol_module_package_t * p)
164 {
165 	return p->seusers;
166 }
167 
sepol_module_package_get_seusers_len(sepol_module_package_t * p)168 size_t sepol_module_package_get_seusers_len(sepol_module_package_t * p)
169 {
170 	return p->seusers_len;
171 }
172 
sepol_module_package_get_user_extra(sepol_module_package_t * p)173 char *sepol_module_package_get_user_extra(sepol_module_package_t * p)
174 {
175 	return p->user_extra;
176 }
177 
sepol_module_package_get_user_extra_len(sepol_module_package_t * p)178 size_t sepol_module_package_get_user_extra_len(sepol_module_package_t * p)
179 {
180 	return p->user_extra_len;
181 }
182 
sepol_module_package_get_netfilter_contexts(sepol_module_package_t * p)183 char *sepol_module_package_get_netfilter_contexts(sepol_module_package_t * p)
184 {
185 	return p->netfilter_contexts;
186 }
187 
sepol_module_package_get_netfilter_contexts_len(sepol_module_package_t * p)188 size_t sepol_module_package_get_netfilter_contexts_len(sepol_module_package_t *
189 						       p)
190 {
191 	return p->netfilter_contexts_len;
192 }
193 
sepol_module_package_set_file_contexts(sepol_module_package_t * p,char * data,size_t len)194 int sepol_module_package_set_file_contexts(sepol_module_package_t * p,
195 					   char *data, size_t len)
196 {
197 	if (set_char(&p->file_contexts, data, len))
198 		return -1;
199 
200 	p->file_contexts_len = len;
201 	return 0;
202 }
203 
sepol_module_package_set_seusers(sepol_module_package_t * p,char * data,size_t len)204 int sepol_module_package_set_seusers(sepol_module_package_t * p,
205 				     char *data, size_t len)
206 {
207 	if (set_char(&p->seusers, data, len))
208 		return -1;
209 
210 	p->seusers_len = len;
211 	return 0;
212 }
213 
sepol_module_package_set_user_extra(sepol_module_package_t * p,char * data,size_t len)214 int sepol_module_package_set_user_extra(sepol_module_package_t * p,
215 					char *data, size_t len)
216 {
217 	if (set_char(&p->user_extra, data, len))
218 		return -1;
219 
220 	p->user_extra_len = len;
221 	return 0;
222 }
223 
sepol_module_package_set_netfilter_contexts(sepol_module_package_t * p,char * data,size_t len)224 int sepol_module_package_set_netfilter_contexts(sepol_module_package_t * p,
225 						char *data, size_t len)
226 {
227 	if (set_char(&p->netfilter_contexts, data, len))
228 		return -1;
229 
230 	p->netfilter_contexts_len = len;
231 	return 0;
232 }
233 
sepol_module_package_get_policy(sepol_module_package_t * p)234 sepol_policydb_t *sepol_module_package_get_policy(sepol_module_package_t * p)
235 {
236 	return p->policy;
237 }
238 
239 /* Append each of the file contexts from each module to the base
240  * policy's file context.  'base_context' will be reallocated to a
241  * larger size (and thus it is an in/out reference
242  * variable). 'base_fc_len' is the length of base's file context; it
243  * too is a reference variable.  Return 0 on success, -1 if out of
244  * memory. */
link_file_contexts(sepol_module_package_t * base,sepol_module_package_t ** modules,int num_modules)245 static int link_file_contexts(sepol_module_package_t * base,
246 			      sepol_module_package_t ** modules,
247 			      int num_modules)
248 {
249 	size_t fc_len;
250 	int i;
251 	char *s;
252 
253 	fc_len = base->file_contexts_len;
254 	for (i = 0; i < num_modules; i++) {
255 		fc_len += modules[i]->file_contexts_len;
256 	}
257 
258 	if ((s = (char *)realloc(base->file_contexts, fc_len)) == NULL) {
259 		return -1;
260 	}
261 	base->file_contexts = s;
262 	for (i = 0; i < num_modules; i++) {
263 		memcpy(base->file_contexts + base->file_contexts_len,
264 		       modules[i]->file_contexts,
265 		       modules[i]->file_contexts_len);
266 		base->file_contexts_len += modules[i]->file_contexts_len;
267 	}
268 	return 0;
269 }
270 
271 /* Append each of the netfilter contexts from each module to the base
272  * policy's netfilter context.  'base_context' will be reallocated to a
273  * larger size (and thus it is an in/out reference
274  * variable). 'base_nc_len' is the length of base's netfilter contexts; it
275  * too is a reference variable.  Return 0 on success, -1 if out of
276  * memory. */
link_netfilter_contexts(sepol_module_package_t * base,sepol_module_package_t ** modules,int num_modules)277 static int link_netfilter_contexts(sepol_module_package_t * base,
278 				   sepol_module_package_t ** modules,
279 				   int num_modules)
280 {
281 	size_t base_nc_len;
282 	int i;
283 	char *base_context;
284 
285 	base_nc_len = base->netfilter_contexts_len;
286 	for (i = 0; i < num_modules; i++) {
287 		base_nc_len += modules[i]->netfilter_contexts_len;
288 	}
289 
290 	if ((base_context =
291 	     (char *)realloc(base->netfilter_contexts, base_nc_len)) == NULL) {
292 		return -1;
293 	}
294 	base->netfilter_contexts = base_context;
295 	for (i = 0; i < num_modules; i++) {
296 		if (modules[i]->netfilter_contexts_len > 0) {
297 			memcpy(base->netfilter_contexts + base->netfilter_contexts_len,
298 			       modules[i]->netfilter_contexts,
299 			       modules[i]->netfilter_contexts_len);
300 			base->netfilter_contexts_len +=
301 			    modules[i]->netfilter_contexts_len;
302 		}
303 
304 	}
305 	return 0;
306 }
307 
308 /* Links the module packages into the base.  Returns 0 on success, -1
309  * if a requirement was not met, or -2 for all other errors. */
sepol_link_packages(sepol_handle_t * handle,sepol_module_package_t * base,sepol_module_package_t ** modules,int num_modules,int verbose)310 int sepol_link_packages(sepol_handle_t * handle,
311 			sepol_module_package_t * base,
312 			sepol_module_package_t ** modules, int num_modules,
313 			int verbose)
314 {
315 	policydb_t **mod_pols = NULL;
316 	int i, retval;
317 
318 	if ((mod_pols = calloc(num_modules, sizeof(*mod_pols))) == NULL) {
319 		ERR(handle, "Out of memory!");
320 		return -2;
321 	}
322 	for (i = 0; i < num_modules; i++) {
323 		mod_pols[i] = &modules[i]->policy->p;
324 	}
325 
326 	retval = link_modules(handle, &base->policy->p, mod_pols, num_modules,
327 			      verbose);
328 	free(mod_pols);
329 	if (retval == -3) {
330 		return -1;
331 	} else if (retval < 0) {
332 		return -2;
333 	}
334 
335 	if (link_file_contexts(base, modules, num_modules) == -1) {
336 		ERR(handle, "Out of memory!");
337 		return -2;
338 	}
339 
340 	if (link_netfilter_contexts(base, modules, num_modules) == -1) {
341 		ERR(handle, "Out of memory!");
342 		return -2;
343 	}
344 
345 	return 0;
346 }
347 
348 /* buf must be large enough - no checks are performed */
349 #define _read_helper_bufsize BUFSIZ
read_helper(char * buf,struct policy_file * file,uint32_t bytes)350 static int read_helper(char *buf, struct policy_file *file, uint32_t bytes)
351 {
352 	uint32_t offset, nel, read_len;
353 	int rc;
354 
355 	offset = 0;
356 	nel = bytes;
357 
358 	while (nel) {
359 		if (nel < _read_helper_bufsize)
360 			read_len = nel;
361 		else
362 			read_len = _read_helper_bufsize;
363 		rc = next_entry(&buf[offset], file, read_len);
364 		if (rc < 0)
365 			return -1;
366 		offset += read_len;
367 		nel -= read_len;
368 	}
369 	return 0;
370 }
371 
372 #define MAXSECTIONS 100
373 
374 /* Get the section offsets from a package file, offsets will be malloc'd to
375  * the appropriate size and the caller must free() them */
module_package_read_offsets(sepol_module_package_t * mod,struct policy_file * file,size_t ** offsets,uint32_t * sections)376 static int module_package_read_offsets(sepol_module_package_t * mod,
377 				       struct policy_file *file,
378 				       size_t ** offsets, uint32_t * sections)
379 {
380 	uint32_t *buf = NULL, nsec;
381 	unsigned i;
382 	size_t *off = NULL;
383 	int rc;
384 
385 	buf = malloc(sizeof(uint32_t)*3);
386 	if (!buf) {
387 		ERR(file->handle, "out of memory");
388 		goto err;
389 	}
390 
391 	rc = next_entry(buf, file, sizeof(uint32_t) * 3);
392 	if (rc < 0) {
393 		ERR(file->handle, "module package header truncated");
394 		goto err;
395 	}
396 	if (le32_to_cpu(buf[0]) != SEPOL_MODULE_PACKAGE_MAGIC) {
397 		ERR(file->handle,
398 		    "wrong magic number for module package:  expected %#08x, got %#08x",
399 		    SEPOL_MODULE_PACKAGE_MAGIC, le32_to_cpu(buf[0]));
400 		goto err;
401 	}
402 
403 	mod->version = le32_to_cpu(buf[1]);
404 	nsec = *sections = le32_to_cpu(buf[2]);
405 
406 	if (nsec > MAXSECTIONS) {
407 		ERR(file->handle, "too many sections (%u) in module package",
408 		    nsec);
409 		goto err;
410 	}
411 
412 	off = (size_t *) calloc(nsec + 1, sizeof(size_t));
413 	if (!off) {
414 		ERR(file->handle, "out of memory");
415 		goto err;
416 	}
417 
418 	free(buf);
419 	buf = calloc(nsec, sizeof(uint32_t));
420 	if (!buf) {
421 		ERR(file->handle, "out of memory");
422 		goto err;
423 	}
424 	rc = next_entry(buf, file, sizeof(uint32_t) * nsec);
425 	if (rc < 0) {
426 		ERR(file->handle, "module package offset array truncated");
427 		goto err;
428 	}
429 
430 	for (i = 0; i < nsec; i++) {
431 		off[i] = le32_to_cpu(buf[i]);
432 		if (i && off[i] < off[i - 1]) {
433 			ERR(file->handle, "offsets are not increasing (at %u, "
434 			    "offset %zu -> %zu", i, off[i - 1],
435 			    off[i]);
436 			goto err;
437 		}
438 	}
439 
440 	rc = policy_file_length(file, &off[nsec]);
441 	if (rc < 0)
442 		goto err;
443 
444 	if (nsec && off[nsec] < off[nsec-1]) {
445 		ERR(file->handle, "offset greater than file size (at %u, "
446 		    "offset %zu -> %zu", nsec, off[nsec - 1],
447 		    off[nsec]);
448 		goto err;
449 	}
450 	*offsets = off;
451 	free(buf);
452 	return 0;
453 
454 err:
455 	free(buf);
456 	free(off);
457 	return -1;
458 }
459 
460 /* Flags for which sections have been seen during parsing of module package. */
461 #define SEEN_MOD 1
462 #define SEEN_FC  2
463 #define SEEN_SEUSER 4
464 #define SEEN_USER_EXTRA 8
465 #define SEEN_NETFILTER 16
466 
sepol_module_package_read(sepol_module_package_t * mod,struct sepol_policy_file * spf,int verbose)467 int sepol_module_package_read(sepol_module_package_t * mod,
468 			      struct sepol_policy_file *spf, int verbose)
469 {
470 	struct policy_file *file = &spf->pf;
471 	uint32_t buf[1], nsec;
472 	size_t *offsets, len;
473 	int rc;
474 	unsigned i, seen = 0;
475 
476 	if (module_package_read_offsets(mod, file, &offsets, &nsec))
477 		return -1;
478 
479 	/* we know the section offsets, seek to them and read in the data */
480 
481 	for (i = 0; i < nsec; i++) {
482 
483 		if (policy_file_seek(file, offsets[i])) {
484 			ERR(file->handle, "error seeking to offset %zu for "
485 			    "module package section %u", offsets[i], i);
486 			goto cleanup;
487 		}
488 
489 		len = offsets[i + 1] - offsets[i];
490 
491 		if (len < sizeof(uint32_t)) {
492 			ERR(file->handle, "module package section %u "
493 			    "has too small length %zu", i, len);
494 			goto cleanup;
495 		}
496 
497 		/* read the magic number, so that we know which function to call */
498 		rc = next_entry(buf, file, sizeof(uint32_t));
499 		if (rc < 0) {
500 			ERR(file->handle,
501 			    "module package section %u truncated, lacks magic number",
502 			    i);
503 			goto cleanup;
504 		}
505 
506 		switch (le32_to_cpu(buf[0])) {
507 		case SEPOL_PACKAGE_SECTION_FC:
508 			if (seen & SEEN_FC) {
509 				ERR(file->handle,
510 				    "found multiple file contexts sections in module package (at section %u)",
511 				    i);
512 				goto cleanup;
513 			}
514 
515 			mod->file_contexts_len = len - sizeof(uint32_t);
516 			mod->file_contexts =
517 			    (char *)malloc(mod->file_contexts_len);
518 			if (!mod->file_contexts) {
519 				ERR(file->handle, "out of memory");
520 				goto cleanup;
521 			}
522 			if (read_helper
523 			    (mod->file_contexts, file,
524 			     mod->file_contexts_len)) {
525 				ERR(file->handle,
526 				    "invalid file contexts section at section %u",
527 				    i);
528 				free(mod->file_contexts);
529 				mod->file_contexts = NULL;
530 				goto cleanup;
531 			}
532 			seen |= SEEN_FC;
533 			break;
534 		case SEPOL_PACKAGE_SECTION_SEUSER:
535 			if (seen & SEEN_SEUSER) {
536 				ERR(file->handle,
537 				    "found multiple seuser sections in module package (at section %u)",
538 				    i);
539 				goto cleanup;
540 			}
541 
542 			mod->seusers_len = len - sizeof(uint32_t);
543 			mod->seusers = (char *)malloc(mod->seusers_len);
544 			if (!mod->seusers) {
545 				ERR(file->handle, "out of memory");
546 				goto cleanup;
547 			}
548 			if (read_helper(mod->seusers, file, mod->seusers_len)) {
549 				ERR(file->handle,
550 				    "invalid seuser section at section %u", i);
551 				free(mod->seusers);
552 				mod->seusers = NULL;
553 				goto cleanup;
554 			}
555 			seen |= SEEN_SEUSER;
556 			break;
557 		case SEPOL_PACKAGE_SECTION_USER_EXTRA:
558 			if (seen & SEEN_USER_EXTRA) {
559 				ERR(file->handle,
560 				    "found multiple user_extra sections in module package (at section %u)",
561 				    i);
562 				goto cleanup;
563 			}
564 
565 			mod->user_extra_len = len - sizeof(uint32_t);
566 			mod->user_extra = (char *)malloc(mod->user_extra_len);
567 			if (!mod->user_extra) {
568 				ERR(file->handle, "out of memory");
569 				goto cleanup;
570 			}
571 			if (read_helper
572 			    (mod->user_extra, file, mod->user_extra_len)) {
573 				ERR(file->handle,
574 				    "invalid user_extra section at section %u",
575 				    i);
576 				free(mod->user_extra);
577 				mod->user_extra = NULL;
578 				goto cleanup;
579 			}
580 			seen |= SEEN_USER_EXTRA;
581 			break;
582 		case SEPOL_PACKAGE_SECTION_NETFILTER:
583 			if (seen & SEEN_NETFILTER) {
584 				ERR(file->handle,
585 				    "found multiple netfilter contexts sections in module package (at section %u)",
586 				    i);
587 				goto cleanup;
588 			}
589 
590 			mod->netfilter_contexts_len = len - sizeof(uint32_t);
591 			mod->netfilter_contexts =
592 			    (char *)malloc(mod->netfilter_contexts_len);
593 			if (!mod->netfilter_contexts) {
594 				ERR(file->handle, "out of memory");
595 				goto cleanup;
596 			}
597 			if (read_helper
598 			    (mod->netfilter_contexts, file,
599 			     mod->netfilter_contexts_len)) {
600 				ERR(file->handle,
601 				    "invalid netfilter contexts section at section %u",
602 				    i);
603 				free(mod->netfilter_contexts);
604 				mod->netfilter_contexts = NULL;
605 				goto cleanup;
606 			}
607 			seen |= SEEN_NETFILTER;
608 			break;
609 		case POLICYDB_MOD_MAGIC:
610 			if (seen & SEEN_MOD) {
611 				ERR(file->handle,
612 				    "found multiple module sections in module package (at section %u)",
613 				    i);
614 				goto cleanup;
615 			}
616 
617 			/* seek back to where the magic number was */
618 			if (policy_file_seek(file, offsets[i]))
619 				goto cleanup;
620 
621 			rc = policydb_read(&mod->policy->p, file, verbose);
622 			if (rc < 0) {
623 				ERR(file->handle,
624 				    "invalid module in module package (at section %u)",
625 				    i);
626 				goto cleanup;
627 			}
628 			seen |= SEEN_MOD;
629 			break;
630 		default:
631 			/* unknown section, ignore */
632 			ERR(file->handle,
633 			    "unknown magic number at section %u, offset: %zx, number: %x ",
634 			    i, offsets[i], le32_to_cpu(buf[0]));
635 			break;
636 		}
637 	}
638 
639 	if ((seen & SEEN_MOD) == 0) {
640 		ERR(file->handle, "missing module in module package");
641 		goto cleanup;
642 	}
643 
644 	free(offsets);
645 	return 0;
646 
647       cleanup:
648 	free(offsets);
649 	return -1;
650 }
651 
sepol_module_package_info(struct sepol_policy_file * spf,int * type,char ** name,char ** version)652 int sepol_module_package_info(struct sepol_policy_file *spf, int *type,
653 			      char **name, char **version)
654 {
655 	struct policy_file *file = &spf->pf;
656 	sepol_module_package_t *mod = NULL;
657 	uint32_t buf[5], len, nsec;
658 	size_t *offsets = NULL;
659 	unsigned i, seen = 0;
660 	char *id;
661 	int rc;
662 
663 	if (sepol_module_package_create(&mod))
664 		return -1;
665 
666 	if (module_package_read_offsets(mod, file, &offsets, &nsec)) {
667 		goto cleanup;
668 	}
669 
670 	for (i = 0; i < nsec; i++) {
671 
672 		if (policy_file_seek(file, offsets[i])) {
673 			ERR(file->handle, "error seeking to offset "
674 			    "%zu for module package section %u", offsets[i], i);
675 			goto cleanup;
676 		}
677 
678 		len = offsets[i + 1] - offsets[i];
679 
680 		if (len < sizeof(uint32_t)) {
681 			ERR(file->handle,
682 			    "module package section %u has too small length %u",
683 			    i, len);
684 			goto cleanup;
685 		}
686 
687 		/* read the magic number, so that we know which function to call */
688 		rc = next_entry(buf, file, sizeof(uint32_t) * 2);
689 		if (rc < 0) {
690 			ERR(file->handle,
691 			    "module package section %u truncated, lacks magic number",
692 			    i);
693 			goto cleanup;
694 		}
695 
696 		switch (le32_to_cpu(buf[0])) {
697 		case SEPOL_PACKAGE_SECTION_FC:
698 			/* skip file contexts */
699 			if (seen & SEEN_FC) {
700 				ERR(file->handle,
701 				    "found multiple file contexts sections in module package (at section %u)",
702 				    i);
703 				goto cleanup;
704 			}
705 			seen |= SEEN_FC;
706 			break;
707 		case SEPOL_PACKAGE_SECTION_SEUSER:
708 			/* skip seuser */
709 			if (seen & SEEN_SEUSER) {
710 				ERR(file->handle,
711 				    "found seuser sections in module package (at section %u)",
712 				    i);
713 				goto cleanup;
714 			}
715 			seen |= SEEN_SEUSER;
716 			break;
717 		case SEPOL_PACKAGE_SECTION_USER_EXTRA:
718 			/* skip user_extra */
719 			if (seen & SEEN_USER_EXTRA) {
720 				ERR(file->handle,
721 				    "found user_extra sections in module package (at section %u)",
722 				    i);
723 				goto cleanup;
724 			}
725 			seen |= SEEN_USER_EXTRA;
726 			break;
727 		case SEPOL_PACKAGE_SECTION_NETFILTER:
728 			/* skip netfilter contexts */
729 			if (seen & SEEN_NETFILTER) {
730 				ERR(file->handle,
731 				    "found multiple netfilter contexts sections in module package (at section %u)",
732 				    i);
733 				goto cleanup;
734 			}
735 			seen |= SEEN_NETFILTER;
736 			break;
737 		case POLICYDB_MOD_MAGIC:
738 			if (seen & SEEN_MOD) {
739 				ERR(file->handle,
740 				    "found multiple module sections in module package (at section %u)",
741 				    i);
742 				goto cleanup;
743 			}
744 			len = le32_to_cpu(buf[1]);
745 			if (len != strlen(POLICYDB_MOD_STRING)) {
746 				ERR(file->handle,
747 				    "module string length is wrong (at section %u)",
748 				    i);
749 				goto cleanup;
750 			}
751 
752 			/* skip id */
753 			id = malloc(len + 1);
754 			if (!id) {
755 				ERR(file->handle,
756 				    "out of memory (at section %u)",
757 				    i);
758 				goto cleanup;
759 			}
760 			rc = next_entry(id, file, len);
761 			free(id);
762 			if (rc < 0) {
763 				ERR(file->handle,
764 				    "cannot get module string (at section %u)",
765 				    i);
766 				goto cleanup;
767 			}
768 
769 			rc = next_entry(buf, file, sizeof(uint32_t) * 5);
770 			if (rc < 0) {
771 				ERR(file->handle,
772 				    "cannot get module header (at section %u)",
773 				    i);
774 				goto cleanup;
775 			}
776 
777 			*type = le32_to_cpu(buf[0]);
778 			/* if base - we're done */
779 			if (*type == POLICY_BASE) {
780 				*name = NULL;
781 				*version = NULL;
782 				seen |= SEEN_MOD;
783 				break;
784 			} else if (*type != POLICY_MOD) {
785 				ERR(file->handle,
786 				    "module has invalid type %d (at section %u)",
787 				    *type, i);
788 				goto cleanup;
789 			}
790 
791 			/* read the name and version */
792 			rc = next_entry(buf, file, sizeof(uint32_t));
793 			if (rc < 0) {
794 				ERR(file->handle,
795 				    "cannot get module name len (at section %u)",
796 				    i);
797 				goto cleanup;
798 			}
799 
800 			len = le32_to_cpu(buf[0]);
801 			if (str_read(name, file, len)) {
802 				ERR(file->handle,
803 				    "cannot read module name (at section %u): %m",
804 				    i);
805 				goto cleanup;
806 			}
807 
808 			rc = next_entry(buf, file, sizeof(uint32_t));
809 			if (rc < 0) {
810 				ERR(file->handle,
811 				    "cannot get module version len (at section %u)",
812 				    i);
813 				goto cleanup;
814 			}
815 			len = le32_to_cpu(buf[0]);
816 			if (str_read(version, file, len)) {
817 				ERR(file->handle,
818 				    "cannot read module version (at section %u): %m",
819 				i);
820 				goto cleanup;
821 			}
822 			seen |= SEEN_MOD;
823 			break;
824 		default:
825 			break;
826 		}
827 
828 	}
829 
830 	if ((seen & SEEN_MOD) == 0) {
831 		ERR(file->handle, "missing module in module package");
832 		goto cleanup;
833 	}
834 
835 	sepol_module_package_free(mod);
836 	free(offsets);
837 	return 0;
838 
839       cleanup:
840 	sepol_module_package_free(mod);
841 	free(offsets);
842 	return -1;
843 }
844 
write_helper(char * data,size_t len,struct policy_file * file)845 static int write_helper(char *data, size_t len, struct policy_file *file)
846 {
847 	int idx = 0;
848 	size_t len2;
849 
850 	while (len) {
851 		if (len > BUFSIZ)
852 			len2 = BUFSIZ;
853 		else
854 			len2 = len;
855 
856 		if (put_entry(&data[idx], 1, len2, file) != len2) {
857 			return -1;
858 		}
859 		len -= len2;
860 		idx += len2;
861 	}
862 	return 0;
863 }
864 
sepol_module_package_write(sepol_module_package_t * p,struct sepol_policy_file * spf)865 int sepol_module_package_write(sepol_module_package_t * p,
866 			       struct sepol_policy_file *spf)
867 {
868 	struct policy_file *file = &spf->pf;
869 	policy_file_t polfile;
870 	uint32_t buf[5], offsets[5], len, nsec = 0;
871 	int i;
872 
873 	if (p->policy) {
874 		/* compute policy length */
875 		policy_file_init(&polfile);
876 		polfile.type = PF_LEN;
877 		polfile.handle = file->handle;
878 		if (policydb_write(&p->policy->p, &polfile))
879 			return -1;
880 		len = polfile.len;
881 		if (!polfile.len)
882 			return -1;
883 		nsec++;
884 
885 	} else {
886 		/* We don't support writing a package without a module at this point */
887 		return -1;
888 	}
889 
890 	/* seusers and user_extra only supported in base at the moment */
891 	if ((p->seusers || p->user_extra)
892 	    && (p->policy->p.policy_type != SEPOL_POLICY_BASE)) {
893 		ERR(file->handle,
894 		    "seuser and user_extra sections only supported in base");
895 		return -1;
896 	}
897 
898 	if (p->file_contexts)
899 		nsec++;
900 
901 	if (p->seusers)
902 		nsec++;
903 
904 	if (p->user_extra)
905 		nsec++;
906 
907 	if (p->netfilter_contexts)
908 		nsec++;
909 
910 	buf[0] = cpu_to_le32(SEPOL_MODULE_PACKAGE_MAGIC);
911 	buf[1] = cpu_to_le32(p->version);
912 	buf[2] = cpu_to_le32(nsec);
913 	if (put_entry(buf, sizeof(uint32_t), 3, file) != 3)
914 		return -1;
915 
916 	/* calculate offsets */
917 	offsets[0] = (nsec + 3) * sizeof(uint32_t);
918 	buf[0] = cpu_to_le32(offsets[0]);
919 
920 	i = 1;
921 	if (p->file_contexts) {
922 		offsets[i] = offsets[i - 1] + len;
923 		buf[i] = cpu_to_le32(offsets[i]);
924 		/* add a uint32_t to compensate for the magic number */
925 		len = p->file_contexts_len + sizeof(uint32_t);
926 		i++;
927 	}
928 	if (p->seusers) {
929 		offsets[i] = offsets[i - 1] + len;
930 		buf[i] = cpu_to_le32(offsets[i]);
931 		len = p->seusers_len + sizeof(uint32_t);
932 		i++;
933 	}
934 	if (p->user_extra) {
935 		offsets[i] = offsets[i - 1] + len;
936 		buf[i] = cpu_to_le32(offsets[i]);
937 		len = p->user_extra_len + sizeof(uint32_t);
938 		i++;
939 	}
940 	if (p->netfilter_contexts) {
941 		offsets[i] = offsets[i - 1] + len;
942 		buf[i] = cpu_to_le32(offsets[i]);
943 		len = p->netfilter_contexts_len + sizeof(uint32_t);
944 		i++;
945 	}
946 	if (put_entry(buf, sizeof(uint32_t), nsec, file) != nsec)
947 		return -1;
948 
949 	/* write sections */
950 
951 	if (policydb_write(&p->policy->p, file))
952 		return -1;
953 
954 	if (p->file_contexts) {
955 		buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_FC);
956 		if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
957 			return -1;
958 		if (write_helper(p->file_contexts, p->file_contexts_len, file))
959 			return -1;
960 	}
961 	if (p->seusers) {
962 		buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_SEUSER);
963 		if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
964 			return -1;
965 		if (write_helper(p->seusers, p->seusers_len, file))
966 			return -1;
967 
968 	}
969 	if (p->user_extra) {
970 		buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_USER_EXTRA);
971 		if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
972 			return -1;
973 		if (write_helper(p->user_extra, p->user_extra_len, file))
974 			return -1;
975 	}
976 	if (p->netfilter_contexts) {
977 		buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_NETFILTER);
978 		if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
979 			return -1;
980 		if (write_helper
981 		    (p->netfilter_contexts, p->netfilter_contexts_len, file))
982 			return -1;
983 	}
984 	return 0;
985 }
986 
sepol_link_modules(sepol_handle_t * handle,sepol_policydb_t * base,sepol_policydb_t ** modules,size_t len,int verbose)987 int sepol_link_modules(sepol_handle_t * handle,
988 		       sepol_policydb_t * base,
989 		       sepol_policydb_t ** modules, size_t len, int verbose)
990 {
991 	return link_modules(handle, &base->p, (policydb_t **) modules, len,
992 			    verbose);
993 }
994 
sepol_expand_module(sepol_handle_t * handle,sepol_policydb_t * base,sepol_policydb_t * out,int verbose,int check)995 int sepol_expand_module(sepol_handle_t * handle,
996 			sepol_policydb_t * base,
997 			sepol_policydb_t * out, int verbose, int check)
998 {
999 	return expand_module(handle, &base->p, &out->p, verbose, check);
1000 }
1001