Coverage Report

Created: 2026-10-17 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/selinux/libsepol/fuzz/binpolicy-fuzzer.c
Line
Count
Source
1
#include <sepol/debug.h>
2
#include <sepol/kernel_to_cil.h>
3
#include <sepol/kernel_to_conf.h>
4
#include <sepol/module_to_cil.h>
5
#include <sepol/policydb/expand.h>
6
#include <sepol/policydb/hierarchy.h>
7
#include <sepol/policydb/link.h>
8
#include <sepol/policydb/policydb.h>
9
10
extern int policydb_validate(sepol_handle_t *handle, const policydb_t *p);
11
12
extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
13
14
// set to 1 to enable more verbose libsepol logging
15
#ifndef VERBOSE
16
30.5k
#define VERBOSE 0
17
#endif
18
19
static int write_binary_policy(policydb_t *p, FILE *outfp)
20
2.43k
{
21
2.43k
  struct policy_file pf;
22
23
2.43k
  policy_file_init(&pf);
24
2.43k
  pf.type = PF_USE_STDIO;
25
2.43k
  pf.fp = outfp;
26
2.43k
  return policydb_write(p, &pf);
27
2.43k
}
28
29
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
30
13.6k
{
31
13.6k
  policydb_t policydb = {}, out = {}, modpol = {};
32
13.6k
  policydb_t *mods[] = { &modpol };
33
13.6k
  int nmods = 0;
34
13.6k
  sidtab_t sidtab = {};
35
13.6k
  struct policy_file pf;
36
13.6k
  FILE *devnull = NULL;
37
38
13.6k
  sepol_debug(VERBOSE);
39
40
13.6k
  policy_file_init(&pf);
41
13.6k
  pf.type = PF_USE_MEMORY;
42
13.6k
  pf.data = (char *)data;
43
13.6k
  pf.len = size;
44
45
13.6k
  if (policydb_init(&policydb))
46
0
    goto exit;
47
48
13.6k
  if (policydb_read(&policydb, &pf, VERBOSE))
49
11.6k
    goto exit;
50
51
2.09k
  if (policydb_load_isids(&policydb, &sidtab))
52
4
    goto exit;
53
54
2.08k
  if (policydb.policy_type == POLICY_KERN) {
55
822
    (void)policydb_optimize(&policydb);
56
57
822
    if (policydb_validate(NULL, &policydb) == -1)
58
0
      abort();
59
822
  }
60
61
2.08k
  if (policydb.global->branch_list)
62
2.06k
    (void)check_assertions(NULL, &policydb,
63
2.06k
               policydb.global->branch_list->avrules);
64
65
2.08k
  (void)hierarchy_check_constraints(NULL, &policydb);
66
67
2.08k
  devnull = fopen("/dev/null", "we");
68
2.08k
  if (!devnull)
69
0
    goto exit;
70
71
2.08k
  if (write_binary_policy(&policydb, devnull))
72
0
    abort();
73
74
2.08k
  if (policydb.policy_type == POLICY_KERN) {
75
822
    if (sepol_kernel_policydb_to_conf(devnull, &policydb))
76
0
      abort();
77
78
822
    if (sepol_kernel_policydb_to_cil(devnull, &policydb))
79
0
      abort();
80
1.26k
  } else {
81
1.26k
    if (sepol_module_policydb_to_cil(devnull, &policydb, 0))
82
0
      abort();
83
84
1.26k
    if (policydb.policy_type == POLICY_BASE) {
85
      /*
86
       * If the input carries a second concatenated policydb after
87
       * the base and it is a POLICY_MOD, feed it to link_modules()
88
       * so that link.c's per-module remapping and copy paths are
89
       * exercised (with mods=NULL that whole subtree is dead).
90
       * Trailing junk that fails to read/validate is ignored.
91
       */
92
1.13k
      if (pf.len > 0 && policydb_init(&modpol) == 0) {
93
965
        if (policydb_read(&modpol, &pf, VERBOSE) == 0 &&
94
232
            modpol.policy_type == POLICY_MOD &&
95
208
            modpol.mls == policydb.mls) {
96
207
          nmods = 1;
97
758
        } else {
98
758
          policydb_destroy(&modpol);
99
758
          memset(&modpol, 0, sizeof(modpol));
100
758
        }
101
965
      }
102
103
1.13k
      if (link_modules(NULL, &policydb, nmods ? mods : NULL,
104
1.13k
           nmods, VERBOSE))
105
110
        goto exit;
106
107
1.02k
      if (policydb_init(&out))
108
0
        goto exit;
109
110
1.02k
      if (expand_module(NULL, &policydb, &out, VERBOSE,
111
1.02k
            /*check_assertions=*/0))
112
625
        goto exit;
113
114
398
      if (policydb_validate(NULL, &out))
115
55
        goto exit;
116
117
343
      (void)check_assertions(
118
343
        NULL, &out, out.global->branch_list->avrules);
119
343
      (void)hierarchy_check_constraints(NULL, &out);
120
121
343
      if (write_binary_policy(&out, devnull))
122
0
        abort();
123
124
343
      if (sepol_kernel_policydb_to_conf(devnull, &out))
125
0
        abort();
126
127
343
      if (sepol_kernel_policydb_to_cil(devnull, &out))
128
0
        abort();
129
343
    }
130
1.26k
  }
131
132
13.6k
exit:
133
13.6k
  if (devnull != NULL)
134
2.08k
    fclose(devnull);
135
136
13.6k
  policydb_destroy(&out);
137
13.6k
  policydb_destroy(&modpol);
138
13.6k
  policydb_destroy(&policydb);
139
13.6k
  sepol_sidtab_destroy(&sidtab);
140
141
  /* Non-zero return values are reserved for future use. */
142
13.6k
  return 0;
143
2.08k
}
144
145
#ifdef DEFINEMAIN
146
#include <sys/stat.h>
147
#include <sys/mman.h>
148
149
int main(int argc, char **argv)
150
{
151
  if (argc < 2) {
152
    fprintf(stderr, "usage: %s fuzzer-input-file\n", argv[0]);
153
    exit(1);
154
  }
155
156
  FILE *fp = fopen(argv[1], "rb");
157
  if (!fp) {
158
    perror(argv[1]);
159
    exit(1);
160
  }
161
162
  struct stat sb;
163
  int rc;
164
165
  rc = fstat(fileno(fp), &sb);
166
  if (rc < 0) {
167
    perror("fstat");
168
    exit(1);
169
  }
170
171
  void *address = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE,
172
           MAP_PRIVATE, fileno(fp), 0);
173
  if (address == MAP_FAILED) {
174
    perror("mmap");
175
    exit(1);
176
  }
177
178
  return LLVMFuzzerTestOneInput(address, sb.st_size);
179
}
180
#endif