Coverage Report

Created: 2025-07-11 06:24

/src/selinux/libsepol/src/kernel_to_common.c
Line
Count
Source (jump to first uncovered line)
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <stdarg.h>
4
#include <string.h>
5
#include <sys/types.h>
6
#include <unistd.h>
7
8
#include <arpa/inet.h>
9
#include <netinet/in.h>
10
#ifndef IPPROTO_DCCP
11
#define IPPROTO_DCCP 33
12
#endif
13
#ifndef IPPROTO_SCTP
14
#define IPPROTO_SCTP 132
15
#endif
16
17
#include <sepol/policydb/ebitmap.h>
18
#include <sepol/policydb/hashtab.h>
19
#include <sepol/policydb/symtab.h>
20
21
#include "debug.h"
22
#include "private.h"
23
#include "kernel_to_common.h"
24
25
26
void sepol_indent(FILE *out, int indent)
27
4.98k
{
28
4.98k
  if (fprintf(out, "%*s", indent * 4, "") < 0) {
29
0
    ERR(NULL, "Failed to write to output");
30
0
  }
31
4.98k
}
32
33
void sepol_printf(FILE *out, const char *fmt, ...)
34
124k
{
35
124k
  va_list argptr;
36
124k
  va_start(argptr, fmt);
37
124k
  if (vfprintf(out, fmt, argptr) < 0) {
38
0
    ERR(NULL, "Failed to write to output");
39
0
  }
40
124k
  va_end(argptr);
41
124k
}
42
43
char *create_str(const char *fmt, ...)
44
38.5k
{
45
38.5k
  char *str;
46
38.5k
  va_list vargs;
47
38.5k
  int rc;
48
49
38.5k
  va_start(vargs, fmt);
50
38.5k
  rc = vasprintf(&str, fmt, vargs);
51
38.5k
  va_end(vargs);
52
53
38.5k
  if (rc == -1)
54
0
    return NULL;
55
56
38.5k
  return str;
57
38.5k
}
58
59
int strs_init(struct strs **strs, size_t size)
60
103k
{
61
103k
  struct strs *new;
62
63
103k
  if (size == 0) {
64
10.9k
    size = 1;
65
10.9k
  }
66
67
103k
  *strs = NULL;
68
69
103k
  new = malloc(sizeof(struct strs));
70
103k
  if (!new) {
71
0
    ERR(NULL, "Out of memory");
72
0
    return -1;
73
0
  }
74
75
103k
  new->list = calloc(size, sizeof(char *));
76
103k
  if (!new->list) {
77
0
    ERR(NULL, "Out of memory");
78
0
    free(new);
79
0
    return -1;
80
0
  }
81
82
103k
  new->num = 0;
83
103k
  new->size = size;
84
85
103k
  *strs = new;
86
87
103k
  return 0;
88
103k
}
89
90
void strs_destroy(struct strs **strs)
91
105k
{
92
105k
  if (!strs || !*strs) {
93
1.55k
    return;
94
1.55k
  }
95
96
103k
  free((*strs)->list);
97
103k
  (*strs)->list = NULL;
98
103k
  (*strs)->num = 0;
99
103k
  (*strs)->size = 0;
100
103k
  free(*strs);
101
103k
  *strs = NULL;
102
103k
}
103
104
void strs_free_all(struct strs *strs)
105
52.3k
{
106
52.3k
  if (!strs) {
107
0
    return;
108
0
  }
109
110
82.6k
  while (strs->num > 0) {
111
30.3k
    strs->num--;
112
30.3k
    free(strs->list[strs->num]);
113
30.3k
  }
114
52.3k
}
115
116
int strs_add(struct strs *strs, char *s)
117
60.4k
{
118
60.4k
  if (strs->num + 1 > strs->size) {
119
180
    char **new;
120
180
    size_t i = strs->size;
121
180
    strs->size *= 2;
122
180
    new = reallocarray(strs->list, strs->size, sizeof(char *));
123
180
    if (!new) {
124
0
      ERR(NULL, "Out of memory");
125
0
      return -1;
126
0
    }
127
180
    strs->list = new;
128
180
    memset(&strs->list[i], 0, sizeof(char *)*(strs->size-i));
129
180
  }
130
131
60.4k
  strs->list[strs->num] = s;
132
60.4k
  strs->num++;
133
134
60.4k
  return 0;
135
60.4k
}
136
137
int strs_create_and_add(struct strs *strs, const char *fmt, ...)
138
18.9k
{
139
18.9k
  char *str;
140
18.9k
  va_list vargs;
141
18.9k
  int rc;
142
143
18.9k
  va_start(vargs, fmt);
144
18.9k
  rc = vasprintf(&str, fmt, vargs);
145
18.9k
  va_end(vargs);
146
147
18.9k
  if (rc == -1)
148
0
    goto exit;
149
150
18.9k
  rc = strs_add(strs, str);
151
18.9k
  if (rc != 0) {
152
0
    free(str);
153
0
    goto exit;
154
0
  }
155
156
18.9k
  return 0;
157
158
0
exit:
159
0
  return rc;
160
18.9k
}
161
162
char *strs_remove_last(struct strs *strs)
163
23.4k
{
164
23.4k
  if (strs->num == 0) {
165
0
    return NULL;
166
0
  }
167
23.4k
  strs->num--;
168
23.4k
  return strs->list[strs->num];
169
23.4k
}
170
171
int strs_add_at_index(struct strs *strs, char *s, size_t index)
172
7.26k
{
173
7.26k
  if (index >= strs->size) {
174
0
    char **new;
175
0
    size_t i = strs->size;
176
0
    while (index >= strs->size) {
177
0
      strs->size *= 2;
178
0
    }
179
0
    new = reallocarray(strs->list, strs->size, sizeof(char *));
180
0
    if (!new) {
181
0
      ERR(NULL, "Out of memory");
182
0
      return -1;
183
0
    }
184
0
    strs->list = new;
185
0
    memset(&strs->list[i], 0, sizeof(char *)*(strs->size - i));
186
0
  }
187
188
7.26k
  strs->list[index] = s;
189
7.26k
  if (index >= strs->num) {
190
3.52k
    strs->num = index+1;
191
3.52k
  }
192
193
7.26k
  return 0;
194
7.26k
}
195
196
char *strs_read_at_index(struct strs *strs, size_t index)
197
26.8k
{
198
26.8k
  if (index >= strs->num) {
199
0
    return NULL;
200
0
  }
201
202
26.8k
  return strs->list[index];
203
26.8k
}
204
205
static int strs_cmp(const void *a, const void *b)
206
135k
{
207
135k
  char *const *aa = a;
208
135k
  char *const *bb = b;
209
135k
  return strcmp(*aa,*bb);
210
135k
}
211
212
void strs_sort(struct strs *strs)
213
70.5k
{
214
70.5k
  if (strs->num == 0) {
215
58.6k
    return;
216
58.6k
  }
217
11.8k
  qsort(strs->list, strs->num, sizeof(char *), strs_cmp);
218
11.8k
}
219
220
unsigned strs_num_items(const struct strs *strs)
221
56.4k
{
222
56.4k
  return strs->num;
223
56.4k
}
224
225
size_t strs_len_items(const struct strs *strs)
226
2.13k
{
227
2.13k
  unsigned i;
228
2.13k
  size_t len = 0;
229
230
7.12k
  for (i=0; i<strs->num; i++) {
231
4.99k
    if (!strs->list[i]) continue;
232
4.99k
    len += strlen(strs->list[i]);
233
4.99k
  }
234
235
2.13k
  return len;
236
2.13k
}
237
238
char *strs_to_str(const struct strs *strs)
239
2.10k
{
240
2.10k
  char *str = NULL;
241
2.10k
  size_t len = 0;
242
2.10k
  char *p;
243
2.10k
  unsigned i;
244
2.10k
  int rc;
245
246
2.10k
  if (strs->num == 0) {
247
0
    goto exit;
248
0
  }
249
250
  /* strs->num added because either ' ' or '\0' follows each item */
251
2.10k
  len = strs_len_items(strs) + strs->num;
252
2.10k
  str = malloc(len);
253
2.10k
  if (!str) {
254
0
    ERR(NULL, "Out of memory");
255
0
    goto exit;
256
0
  }
257
258
2.10k
  p = str;
259
7.04k
  for (i=0; i<strs->num; i++) {
260
4.93k
    if (!strs->list[i]) continue;
261
4.93k
    len = strlen(strs->list[i]);
262
4.93k
    rc = snprintf(p, len+1, "%s", strs->list[i]);
263
4.93k
    if (rc < 0 || rc > (int)len) {
264
0
      free(str);
265
0
      str = NULL;
266
0
      goto exit;
267
0
    }
268
4.93k
    p += len;
269
4.93k
    if (i < strs->num - 1) {
270
2.83k
      *p++ = ' ';
271
2.83k
    }
272
4.93k
  }
273
274
2.10k
  *p = '\0';
275
276
2.10k
exit:
277
2.10k
  return str;
278
2.10k
}
279
280
void strs_write_each(const struct strs *strs, FILE *out)
281
27.5k
{
282
27.5k
  unsigned i;
283
284
49.8k
  for (i=0; i<strs->num; i++) {
285
22.3k
    if (!strs->list[i]) {
286
1.74k
      continue;
287
1.74k
    }
288
20.5k
    sepol_printf(out, "%s\n",strs->list[i]);
289
20.5k
  }
290
27.5k
}
291
292
void strs_write_each_indented(const struct strs *strs, FILE *out, int indent)
293
22.6k
{
294
22.6k
  unsigned i;
295
296
27.2k
  for (i=0; i<strs->num; i++) {
297
4.62k
    if (!strs->list[i]) {
298
0
      continue;
299
0
    }
300
4.62k
    sepol_indent(out, indent);
301
4.62k
    sepol_printf(out, "%s\n",strs->list[i]);
302
4.62k
  }
303
22.6k
}
304
305
int hashtab_ordered_to_strs(char *key, void *data, void *args)
306
3.93k
{
307
3.93k
  struct strs *strs = (struct strs *)args;
308
3.93k
  symtab_datum_t *datum = data;
309
310
3.93k
  return strs_add_at_index(strs, key, datum->value-1);
311
3.93k
}
312
313
int ebitmap_to_strs(const struct ebitmap *map, struct strs *strs, char **val_to_name)
314
1.86k
{
315
1.86k
  struct ebitmap_node *node;
316
1.86k
  uint32_t i;
317
1.86k
  int rc;
318
319
119k
  ebitmap_for_each_positive_bit(map, node, i) {
320
2.02k
    if (!val_to_name[i])
321
0
      continue;
322
323
2.02k
    rc = strs_add(strs, val_to_name[i]);
324
2.02k
    if (rc != 0) {
325
0
      return -1;
326
0
    }
327
2.02k
  }
328
329
1.86k
  return 0;
330
1.86k
}
331
332
char *ebitmap_to_str(const struct ebitmap *map, char **val_to_name, int sort)
333
929
{
334
929
  struct strs *strs;
335
929
  char *str = NULL;
336
929
  int rc;
337
338
929
  rc = strs_init(&strs, 32);
339
929
  if (rc != 0) {
340
0
    goto exit;
341
0
  }
342
343
929
  rc = ebitmap_to_strs(map, strs, val_to_name);
344
929
  if (rc != 0) {
345
0
    goto exit;
346
0
  }
347
348
929
  if (sort) {
349
929
    strs_sort(strs);
350
929
  }
351
352
929
  str = strs_to_str(strs);
353
354
929
exit:
355
929
  strs_destroy(&strs);
356
357
929
  return str;
358
929
}
359
360
int strs_stack_init(struct strs **stack)
361
18.5k
{
362
18.5k
  return strs_init(stack, STACK_SIZE);
363
18.5k
}
364
365
void strs_stack_destroy(struct strs **stack)
366
18.5k
{
367
18.5k
  return strs_destroy(stack);
368
18.5k
}
369
370
int strs_stack_push(struct strs *stack, char *s)
371
23.4k
{
372
23.4k
  return strs_add(stack, s);
373
23.4k
}
374
375
char *strs_stack_pop(struct strs *stack)
376
23.4k
{
377
23.4k
  return strs_remove_last(stack);
378
23.4k
}
379
380
int strs_stack_empty(const struct strs *stack)
381
18.5k
{
382
18.5k
  return strs_num_items(stack) == 0;
383
18.5k
}
384
385
static int compare_ranges(uint64_t l1, uint64_t h1, uint64_t l2, uint64_t h2)
386
0
{
387
0
  uint64_t d1, d2;
388
389
0
  d1 = h1-l1;
390
0
  d2 = h2-l2;
391
392
0
  if (d1 < d2) {
393
0
    return -1;
394
0
  } else if (d1 > d2) {
395
0
    return 1;
396
0
  } else {
397
0
    if (l1 < l2) {
398
0
      return -1;
399
0
    } else if (l1 > l2) {
400
0
      return 1;
401
0
    }
402
0
  }
403
404
0
  return 0;
405
0
}
406
407
static int fsuse_data_cmp(const void *a, const void *b)
408
44
{
409
44
  struct ocontext *const *aa = a;
410
44
  struct ocontext *const *bb = b;
411
412
44
  if ((*aa)->v.behavior != (*bb)->v.behavior) {
413
16
    if ((*aa)->v.behavior < (*bb)->v.behavior) {
414
12
      return -1;
415
12
    } else {
416
4
      return 1;
417
4
    }
418
16
  }
419
420
28
  return strcmp((*aa)->u.name, (*bb)->u.name);
421
44
}
422
423
static int portcon_data_cmp(const void *a, const void *b)
424
0
{
425
0
  struct ocontext *const *aa = a;
426
0
  struct ocontext *const *bb = b;
427
0
  int rc;
428
429
0
  rc = compare_ranges((*aa)->u.port.low_port, (*aa)->u.port.high_port,
430
0
          (*bb)->u.port.low_port, (*bb)->u.port.high_port);
431
0
  if (rc == 0) {
432
0
    if ((*aa)->u.port.protocol < (*bb)->u.port.protocol) {
433
0
      rc = -1;
434
0
    } else if ((*aa)->u.port.protocol > (*bb)->u.port.protocol) {
435
0
      rc = 1;
436
0
    }
437
0
  }
438
439
0
  return rc;
440
0
}
441
442
static int netif_data_cmp(const void *a, const void *b)
443
0
{
444
  /* keep in sync with cil_post.c:cil_post_netifcon_compare() */
445
0
  const struct ocontext *const *aa = a;
446
0
  const struct ocontext *const *bb = b;
447
0
  const char *a_name = (*aa)->u.name;
448
0
  const char *b_name = (*bb)->u.name;
449
0
  size_t a_stem = strcspn(a_name, "*?");
450
0
  size_t b_stem = strcspn(b_name, "*?");
451
0
  size_t a_len = strlen(a_name);
452
0
  size_t b_len = strlen(b_name);
453
0
  int a_iswildcard = a_stem != a_len;
454
0
  int b_iswildcard = b_stem != b_len;
455
0
  int rc;
456
457
  /* order non-wildcards first */
458
0
  rc = spaceship_cmp(a_iswildcard, b_iswildcard);
459
0
  if (rc)
460
0
    return rc;
461
462
  /* order non-wildcards alphabetically */
463
0
  if (!a_iswildcard)
464
0
    return strcmp(a_name, b_name);
465
466
  /* order by decreasing stem length */
467
0
  rc = spaceship_cmp(a_stem, b_stem);
468
0
  if (rc)
469
0
    return -rc;
470
471
  /* order '?' (0x3f) before '*' (0x2A) */
472
0
  rc = spaceship_cmp(a_name[a_stem], b_name[b_stem]);
473
0
  if (rc)
474
0
    return -rc;
475
476
  /* order alphabetically */
477
0
  return strcmp(a_name, b_name);
478
0
}
479
480
static int node_data_cmp(const void *a, const void *b)
481
0
{
482
0
  struct ocontext *const *aa = a;
483
0
  struct ocontext *const *bb = b;
484
0
  int rc;
485
486
0
  rc = memcmp(&(*aa)->u.node.mask, &(*bb)->u.node.mask, sizeof((*aa)->u.node.mask));
487
0
  if (rc > 0) {
488
0
    return -1;
489
0
  } else if (rc < 0) {
490
0
    return 1;
491
0
  }
492
493
0
  return memcmp(&(*aa)->u.node.addr, &(*bb)->u.node.addr, sizeof((*aa)->u.node.addr));
494
0
}
495
496
static int node6_data_cmp(const void *a, const void *b)
497
0
{
498
0
  struct ocontext *const *aa = a;
499
0
  struct ocontext *const *bb = b;
500
0
  int rc;
501
502
0
  rc = memcmp(&(*aa)->u.node6.mask, &(*bb)->u.node6.mask, sizeof((*aa)->u.node6.mask));
503
0
  if (rc > 0) {
504
0
    return -1;
505
0
  } else if (rc < 0) {
506
0
    return 1;
507
0
  }
508
509
0
  return memcmp(&(*aa)->u.node6.addr, &(*bb)->u.node6.addr, sizeof((*aa)->u.node6.addr));
510
0
}
511
512
static int ibpkey_data_cmp(const void *a, const void *b)
513
0
{
514
0
  int rc;
515
0
  struct ocontext *const *aa = a;
516
0
  struct ocontext *const *bb = b;
517
518
0
  rc = (*aa)->u.ibpkey.subnet_prefix - (*bb)->u.ibpkey.subnet_prefix;
519
0
  if (rc)
520
0
    return rc;
521
522
0
  return compare_ranges((*aa)->u.ibpkey.low_pkey, (*aa)->u.ibpkey.high_pkey,
523
0
            (*bb)->u.ibpkey.low_pkey, (*bb)->u.ibpkey.high_pkey);
524
0
}
525
526
static int ibendport_data_cmp(const void *a, const void *b)
527
0
{
528
0
  int rc;
529
0
  struct ocontext *const *aa = a;
530
0
  struct ocontext *const *bb = b;
531
532
0
  rc = strcmp((*aa)->u.ibendport.dev_name, (*bb)->u.ibendport.dev_name);
533
0
  if (rc)
534
0
    return rc;
535
536
0
  return spaceship_cmp((*aa)->u.ibendport.port, (*bb)->u.ibendport.port);
537
0
}
538
539
static int pirq_data_cmp(const void *a, const void *b)
540
0
{
541
0
  struct ocontext *const *aa = a;
542
0
  struct ocontext *const *bb = b;
543
544
0
  if ((*aa)->u.pirq < (*bb)->u.pirq) {
545
0
    return -1;
546
0
  } else if ((*aa)->u.pirq > (*bb)->u.pirq) {
547
0
    return 1;
548
0
  }
549
550
0
  return 0;
551
0
}
552
553
static int ioport_data_cmp(const void *a, const void *b)
554
0
{
555
0
  struct ocontext *const *aa = a;
556
0
  struct ocontext *const *bb = b;
557
558
0
  return compare_ranges((*aa)->u.ioport.low_ioport, (*aa)->u.ioport.high_ioport,
559
0
            (*bb)->u.ioport.low_ioport, (*bb)->u.ioport.high_ioport);
560
0
}
561
562
static int iomem_data_cmp(const void *a, const void *b)
563
0
{
564
0
  struct ocontext *const *aa = a;
565
0
  struct ocontext *const *bb = b;
566
567
0
  return compare_ranges((*aa)->u.iomem.low_iomem, (*aa)->u.iomem.high_iomem,
568
0
            (*bb)->u.iomem.low_iomem, (*bb)->u.iomem.high_iomem);
569
0
}
570
571
static int pcid_data_cmp(const void *a, const void *b)
572
0
{
573
0
  struct ocontext *const *aa = a;
574
0
  struct ocontext *const *bb = b;
575
576
0
  if ((*aa)->u.device < (*bb)->u.device) {
577
0
    return -1;
578
0
  } else if ((*aa)->u.device > (*bb)->u.device) {
579
0
    return 1;
580
0
  }
581
582
0
  return 0;
583
0
}
584
585
static int dtree_data_cmp(const void *a, const void *b)
586
0
{
587
0
  struct ocontext *const *aa = a;
588
0
  struct ocontext *const *bb = b;
589
590
0
  return strcmp((*aa)->u.name, (*bb)->u.name);
591
0
}
592
593
static int sort_ocontext_data(struct ocontext **ocons, int (*cmp)(const void *, const void *))
594
17.3k
{
595
17.3k
  struct ocontext *ocon;
596
17.3k
  struct ocontext **data;
597
17.3k
  unsigned i, num;
598
599
17.3k
  num = 0;
600
17.4k
  for (ocon = *ocons; ocon != NULL; ocon = ocon->next) {
601
116
    num++;
602
116
  }
603
604
17.3k
  if (num == 0) {
605
17.2k
    return 0;
606
17.2k
  }
607
608
72
  data = calloc(num, sizeof(*data));
609
72
  if (!data) {
610
0
    ERR(NULL, "Out of memory");
611
0
    return -1;
612
0
  }
613
614
72
  i = 0;
615
188
  for (ocon = *ocons; ocon != NULL; ocon = ocon->next) {
616
116
    data[i] = ocon;
617
116
    i++;
618
116
  }
619
620
72
  qsort(data, num, sizeof(*data), cmp);
621
622
72
  *ocons = data[0];
623
116
  for (i=1; i < num; i++) {
624
44
    data[i-1]->next = data[i];
625
44
  }
626
72
  data[num-1]->next = NULL;
627
628
72
  free(data);
629
630
72
  return 0;
631
72
}
632
633
int sort_ocontexts(struct policydb *pdb)
634
2.49k
{
635
2.49k
  int rc = 0;
636
637
2.49k
  if (pdb->target_platform == SEPOL_TARGET_SELINUX) {
638
2.45k
    rc = sort_ocontext_data(&pdb->ocontexts[5], fsuse_data_cmp);
639
2.45k
    if (rc != 0) {
640
0
      goto exit;
641
0
    }
642
643
2.45k
    rc = sort_ocontext_data(&pdb->ocontexts[2], portcon_data_cmp);
644
2.45k
    if (rc != 0) {
645
0
      goto exit;
646
0
    }
647
648
2.45k
    rc = sort_ocontext_data(&pdb->ocontexts[3], netif_data_cmp);
649
2.45k
    if (rc != 0) {
650
0
      goto exit;
651
0
    }
652
653
2.45k
    rc = sort_ocontext_data(&pdb->ocontexts[4], node_data_cmp);
654
2.45k
    if (rc != 0) {
655
0
      goto exit;
656
0
    }
657
658
2.45k
    rc = sort_ocontext_data(&pdb->ocontexts[6], node6_data_cmp);
659
2.45k
    if (rc != 0) {
660
0
      goto exit;
661
0
    }
662
663
2.45k
    rc = sort_ocontext_data(&pdb->ocontexts[OCON_IBPKEY], ibpkey_data_cmp);
664
2.45k
    if (rc != 0) {
665
0
      goto exit;
666
0
    }
667
668
2.45k
    rc = sort_ocontext_data(&pdb->ocontexts[OCON_IBENDPORT], ibendport_data_cmp);
669
2.45k
    if (rc != 0) {
670
0
      goto exit;
671
0
    }
672
2.45k
  } else if (pdb->target_platform == SEPOL_TARGET_XEN) {
673
38
    rc = sort_ocontext_data(&pdb->ocontexts[1], pirq_data_cmp);
674
38
    if (rc != 0) {
675
0
      goto exit;
676
0
    }
677
678
38
    rc = sort_ocontext_data(&pdb->ocontexts[2], ioport_data_cmp);
679
38
    if (rc != 0) {
680
0
      goto exit;
681
0
    }
682
683
38
    rc = sort_ocontext_data(&pdb->ocontexts[3], iomem_data_cmp);
684
38
    if (rc != 0) {
685
0
      goto exit;
686
0
    }
687
688
38
    rc = sort_ocontext_data(&pdb->ocontexts[4], pcid_data_cmp);
689
38
    if (rc != 0) {
690
0
      goto exit;
691
0
    }
692
693
38
    rc = sort_ocontext_data(&pdb->ocontexts[5], dtree_data_cmp);
694
38
    if (rc != 0) {
695
0
      goto exit;
696
0
    }
697
38
  }
698
699
2.49k
exit:
700
2.49k
  if (rc != 0) {
701
0
    ERR(NULL, "Error sorting ocontexts");
702
0
  }
703
704
2.49k
  return rc;
705
2.49k
}