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