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
40static 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
63static 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
93static 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
103static 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
118int 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
133hidden_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 */
138void 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
151hidden_def(sepol_module_package_free)
152
153char *sepol_module_package_get_file_contexts(sepol_module_package_t * p)
154{
155	return p->file_contexts;
156}
157
158size_t sepol_module_package_get_file_contexts_len(sepol_module_package_t * p)
159{
160	return p->file_contexts_len;
161}
162
163char *sepol_module_package_get_seusers(sepol_module_package_t * p)
164{
165	return p->seusers;
166}
167
168size_t sepol_module_package_get_seusers_len(sepol_module_package_t * p)
169{
170	return p->seusers_len;
171}
172
173char *sepol_module_package_get_user_extra(sepol_module_package_t * p)
174{
175	return p->user_extra;
176}
177
178size_t sepol_module_package_get_user_extra_len(sepol_module_package_t * p)
179{
180	return p->user_extra_len;
181}
182
183char *sepol_module_package_get_netfilter_contexts(sepol_module_package_t * p)
184{
185	return p->netfilter_contexts;
186}
187
188size_t sepol_module_package_get_netfilter_contexts_len(sepol_module_package_t *
189						       p)
190{
191	return p->netfilter_contexts_len;
192}
193
194int 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
204int 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
214int 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
224int 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
234sepol_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. */
245static 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. */
277static 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. */
307int 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
347static 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 */
373static 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
451err:
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
464int 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
649int 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
838static 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
858int 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
980int 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
988int 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