/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 |