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