1 /* Author: Karl MacMillan <[email protected]>
2 * Jason Tang <[email protected]>
3 * Chris PeBenito <[email protected]>
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
135
136 /* Deallocates all memory associated with a module package, including
137 * the pointer itself. Does nothing if p is NULL.
138 */
sepol_module_package_free(sepol_module_package_t * p)139 void 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
sepol_module_package_get_file_contexts(sepol_module_package_t * p)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 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. */
sepol_link_packages(sepol_handle_t * handle,sepol_module_package_t * base,sepol_module_package_t ** modules,int num_modules,int verbose)310 int 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
read_helper(char * buf,struct policy_file * file,uint32_t bytes)350 static 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 */
module_package_read_offsets(sepol_module_package_t * mod,struct policy_file * file,size_t ** offsets,uint32_t * sections)376 static 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
454 err:
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
sepol_module_package_read(sepol_module_package_t * mod,struct sepol_policy_file * spf,int verbose)467 int 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
sepol_module_package_info(struct sepol_policy_file * spf,int * type,char ** name,char ** version)652 int 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
write_helper(char * data,size_t len,struct policy_file * file)845 static 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
sepol_module_package_write(sepol_module_package_t * p,struct sepol_policy_file * spf)865 int 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
sepol_link_modules(sepol_handle_t * handle,sepol_policydb_t * base,sepol_policydb_t ** modules,size_t len,int verbose)987 int 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
sepol_expand_module(sepol_handle_t * handle,sepol_policydb_t * base,sepol_policydb_t * out,int verbose,int check)995 int 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