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