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