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