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