Home | History | Annotate | Download | only in src
      1 /* Author: Karl MacMillan <kmacmillan (at) tresys.com>
      2  *         Jason Tang     <jtang (at) tresys.com>
      3  *         Chris PeBenito <cpebenito (at) 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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    137 size_t sepol_module_package_get_file_contexts_len(sepol_module_package_t * p)
    138 {
    139 	return p->file_contexts_len;
    140 }
    141 
    142 char *sepol_module_package_get_seusers(sepol_module_package_t * p)
    143 {
    144 	return p->seusers;
    145 }
    146 
    147 size_t sepol_module_package_get_seusers_len(sepol_module_package_t * p)
    148 {
    149 	return p->seusers_len;
    150 }
    151 
    152 char *sepol_module_package_get_user_extra(sepol_module_package_t * p)
    153 {
    154 	return p->user_extra;
    155 }
    156 
    157 size_t sepol_module_package_get_user_extra_len(sepol_module_package_t * p)
    158 {
    159 	return p->user_extra_len;
    160 }
    161 
    162 char *sepol_module_package_get_netfilter_contexts(sepol_module_package_t * p)
    163 {
    164 	return p->netfilter_contexts;
    165 }
    166 
    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 
    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 
    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 
    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 
    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 
    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. */
    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. */
    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. */
    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
    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 */
    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 
    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 
    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 
    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 
    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 
    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 
    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