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