1 /* Author: Karl MacMillan <kmacmillan@tresys.com>
2  *         Jason Tang     <jtang@tresys.com>
3  *         Chris PeBenito <cpebenito@tresys.com>
4  *
5  * Copyright (C) 2004-2005 Tresys Technology, LLC
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2.1 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #include "policydb_internal.h"
23 #include "module_internal.h"
24 #include <sepol/policydb/link.h>
25 #include <sepol/policydb/expand.h>
26 #include <sepol/policydb/module.h>
27 #include "debug.h"
28 #include "private.h"
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <limits.h>
33 
34 #define SEPOL_PACKAGE_SECTION_FC 0xf97cff90
35 #define SEPOL_PACKAGE_SECTION_SEUSER 0x97cff91
36 #define SEPOL_PACKAGE_SECTION_USER_EXTRA 0x97cff92
37 #define SEPOL_PACKAGE_SECTION_NETFILTER 0x97cff93
38 
policy_file_seek(struct policy_file * fp,size_t offset)39 static int policy_file_seek(struct policy_file *fp, size_t offset)
40 {
41 	switch (fp->type) {
42 	case PF_USE_STDIO:
43 		if (offset > LONG_MAX) {
44 			errno = EFAULT;
45 			return -1;
46 		}
47 		return fseek(fp->fp, (long)offset, SEEK_SET);
48 	case PF_USE_MEMORY:
49 		if (offset > fp->size) {
50 			errno = EFAULT;
51 			return -1;
52 		}
53 		fp->data -= fp->size - fp->len;
54 		fp->data += offset;
55 		fp->len = fp->size - offset;
56 		return 0;
57 	default:
58 		return 0;
59 	}
60 }
61 
policy_file_length(struct policy_file * fp,size_t * out)62 static 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 
module_package_init(sepol_module_package_t * p)92 static 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 
set_char(char ** field,char * data,size_t len)102 static 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 
sepol_module_package_create(sepol_module_package_t ** p)117 int 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 
hidden_def(sepol_module_package_create)132 hidden_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  */
137 void 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 
hidden_def(sepol_module_package_free)150 hidden_def(sepol_module_package_free)
151 
152 char *sepol_module_package_get_file_contexts(sepol_module_package_t * p)
153 {
154 	return p->file_contexts;
155 }
156 
sepol_module_package_get_file_contexts_len(sepol_module_package_t * p)157 size_t sepol_module_package_get_file_contexts_len(sepol_module_package_t * p)
158 {
159 	return p->file_contexts_len;
160 }
161 
sepol_module_package_get_seusers(sepol_module_package_t * p)162 char *sepol_module_package_get_seusers(sepol_module_package_t * p)
163 {
164 	return p->seusers;
165 }
166 
sepol_module_package_get_seusers_len(sepol_module_package_t * p)167 size_t sepol_module_package_get_seusers_len(sepol_module_package_t * p)
168 {
169 	return p->seusers_len;
170 }
171 
sepol_module_package_get_user_extra(sepol_module_package_t * p)172 char *sepol_module_package_get_user_extra(sepol_module_package_t * p)
173 {
174 	return p->user_extra;
175 }
176 
sepol_module_package_get_user_extra_len(sepol_module_package_t * p)177 size_t sepol_module_package_get_user_extra_len(sepol_module_package_t * p)
178 {
179 	return p->user_extra_len;
180 }
181 
sepol_module_package_get_netfilter_contexts(sepol_module_package_t * p)182 char *sepol_module_package_get_netfilter_contexts(sepol_module_package_t * p)
183 {
184 	return p->netfilter_contexts;
185 }
186 
sepol_module_package_get_netfilter_contexts_len(sepol_module_package_t * p)187 size_t sepol_module_package_get_netfilter_contexts_len(sepol_module_package_t *
188 						       p)
189 {
190 	return p->netfilter_contexts_len;
191 }
192 
sepol_module_package_set_file_contexts(sepol_module_package_t * p,char * data,size_t len)193 int 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 
sepol_module_package_set_seusers(sepol_module_package_t * p,char * data,size_t len)203 int 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 
sepol_module_package_set_user_extra(sepol_module_package_t * p,char * data,size_t len)213 int 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 
sepol_module_package_set_netfilter_contexts(sepol_module_package_t * p,char * data,size_t len)223 int 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 
sepol_module_package_get_policy(sepol_module_package_t * p)233 sepol_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. */
link_file_contexts(sepol_module_package_t * base,sepol_module_package_t ** modules,int num_modules)244 static 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. */
link_netfilter_contexts(sepol_module_package_t * base,sepol_module_package_t ** modules,int num_modules)276 static 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. */
sepol_link_packages(sepol_handle_t * handle,sepol_module_package_t * base,sepol_module_package_t ** modules,int num_modules,int verbose)306 int 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
read_helper(char * buf,struct policy_file * file,uint32_t bytes)346 static 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 */
module_package_read_offsets(sepol_module_package_t * mod,struct policy_file * file,size_t ** offsets,uint32_t * sections)372 static 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 
450 err:
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 
sepol_module_package_read(sepol_module_package_t * mod,struct sepol_policy_file * spf,int verbose)463 int 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 
sepol_module_package_info(struct sepol_policy_file * spf,int * type,char ** name,char ** version)648 int 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 
write_helper(char * data,size_t len,struct policy_file * file)853 static 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 
sepol_module_package_write(sepol_module_package_t * p,struct sepol_policy_file * spf)873 int 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 
sepol_link_modules(sepol_handle_t * handle,sepol_policydb_t * base,sepol_policydb_t ** modules,size_t len,int verbose)995 int 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 
sepol_expand_module(sepol_handle_t * handle,sepol_policydb_t * base,sepol_policydb_t * out,int verbose,int check)1003 int 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