Coverage Report

Created: 2024-07-27 06:18

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