split up constants.h some
[trinity.git] / generic-sanitise.c
blob16c07ed1549040dbc346dc175bad85ee73f2c990
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <string.h>
6 #include "arch.h"
7 #include "files.h"
8 #include "log.h"
9 #include "maps.h"
10 #include "net.h"
11 #include "random.h"
12 #include "random.h"
13 #include "sanitise.h"
14 #include "shm.h"
15 #include "syscall.h"
16 #include "tables.h"
17 #include "trinity.h" // num_online_cpus
19 static unsigned int get_cpu(void)
21 int i;
22 i = rand() % 100;
24 switch (i) {
25 case 0: return -1;
26 case 1: return rand() % 4095;
27 case 2: return rand() % 15;
29 case 3 ... 99:
30 return rand() % num_online_cpus;
32 return 0;
35 static unsigned long handle_arg_address(int childno, int call, int argnum)
37 unsigned long addr = 0;
39 if (rand_bool())
40 return (unsigned long) get_address();
42 /* Half the time, we look to see if earlier args were also ARG_ADDRESS,
43 * and munge that instead of returning a new one from get_address() */
45 addr = find_previous_arg_address(argnum, call, childno);
47 switch (rand() % 4) {
48 case 0: break; /* return unmodified */
49 case 1: addr++;
50 break;
51 case 2: addr+= sizeof(int);
52 break;
53 case 3: addr+= sizeof(long);
54 break;
57 return addr;
60 static unsigned long handle_arg_range(unsigned int call, unsigned int argnum)
62 struct syscallentry *entry;
63 unsigned long i;
64 unsigned long low = 0, high = 0;
66 entry = syscalls[call].entry;
68 switch (argnum) {
69 case 1: low = entry->low1range;
70 high = entry->hi1range;
71 break;
72 case 2: low = entry->low2range;
73 high = entry->hi2range;
74 break;
75 case 3: low = entry->low3range;
76 high = entry->hi3range;
77 break;
78 case 4: low = entry->low4range;
79 high = entry->hi4range;
80 break;
81 case 5: low = entry->low5range;
82 high = entry->hi5range;
83 break;
84 case 6: low = entry->low6range;
85 high = entry->hi6range;
86 break;
89 if (high == 0) {
90 outputerr("%s forgets to set hirange!\n", entry->name);
91 BUG("Fix syscall definition!\n");
94 i = (unsigned long) rand64() % high;
95 if (i < low) {
96 i += low;
97 i &= high;
99 return i;
102 static unsigned long handle_arg_op(unsigned long call, unsigned long argnum)
104 struct syscallentry *entry;
105 const unsigned long *values = NULL;
106 unsigned int num = 0;
107 unsigned long mask = 0;
109 entry = syscalls[call].entry;
111 switch (argnum) {
112 case 1: num = entry->arg1list.num;
113 values = entry->arg1list.values;
114 break;
115 case 2: num = entry->arg2list.num;
116 values = entry->arg2list.values;
117 break;
118 case 3: num = entry->arg3list.num;
119 values = entry->arg3list.values;
120 break;
121 case 4: num = entry->arg4list.num;
122 values = entry->arg4list.values;
123 break;
124 case 5: num = entry->arg5list.num;
125 values = entry->arg5list.values;
126 break;
127 case 6: num = entry->arg6list.num;
128 values = entry->arg6list.values;
129 break;
132 if (num == 0)
133 BUG("ARG_OP with 0 args. What?\n");
135 if (values == NULL)
136 BUG("ARG_OP with no values.\n");
138 mask |= values[rand() % num];
139 return mask;
142 unsigned long set_rand_bitmask(unsigned int num, const unsigned long *values)
144 unsigned long i;
145 unsigned long mask = 0;
146 unsigned int bits;
148 bits = (rand() % num) + 1; /* num of bits to OR */
149 for (i = 0; i < bits; i++)
150 mask |= values[rand() % num];
152 return mask;
155 static unsigned long handle_arg_list(unsigned long call, unsigned long argnum)
157 struct syscallentry *entry;
158 unsigned long mask = 0;
159 unsigned int num = 0;
160 const unsigned long *values = NULL;
162 entry = syscalls[call].entry;
164 switch (argnum) {
165 case 1: num = entry->arg1list.num;
166 values = entry->arg1list.values;
167 break;
168 case 2: num = entry->arg2list.num;
169 values = entry->arg2list.values;
170 break;
171 case 3: num = entry->arg3list.num;
172 values = entry->arg3list.values;
173 break;
174 case 4: num = entry->arg4list.num;
175 values = entry->arg4list.values;
176 break;
177 case 5: num = entry->arg5list.num;
178 values = entry->arg5list.values;
179 break;
180 case 6: num = entry->arg6list.num;
181 values = entry->arg6list.values;
182 break;
185 if (num == 0)
186 BUG("ARG_LIST with 0 args. What?\n");
188 if (values == NULL)
189 BUG("ARG_LIST with no values.\n");
191 mask = set_rand_bitmask(num, values);
192 return mask;
195 static unsigned long handle_arg_randpage(void)
197 /* Because we pass this to something that might overwrite it,
198 * and we want page_allocs to remain unmodified, we copy it to page rand instead.
200 if (rand_bool())
201 memcpy(page_rand, page_allocs, page_size);
203 return (unsigned long) page_rand;
206 static unsigned long handle_arg_iovec(int childno, unsigned long call, unsigned long argnum)
208 struct syscallentry *entry;
209 unsigned long num_entries;
211 entry = syscalls[call].entry;
213 num_entries = (rand() % 256) +1;
215 switch (argnum) {
216 case 1: if (entry->arg2type == ARG_IOVECLEN)
217 shm->syscall[childno].a2 = num_entries;
218 break;
219 case 2: if (entry->arg3type == ARG_IOVECLEN)
220 shm->syscall[childno].a3 = num_entries;
221 break;
222 case 3: if (entry->arg4type == ARG_IOVECLEN)
223 shm->syscall[childno].a4 = num_entries;
224 break;
225 case 4: if (entry->arg5type == ARG_IOVECLEN)
226 shm->syscall[childno].a5 = num_entries;
227 break;
228 case 5: if (entry->arg6type == ARG_IOVECLEN)
229 shm->syscall[childno].a6 = num_entries;
230 break;
232 return (unsigned long) alloc_iovec(num_entries);
235 static unsigned long get_argval(int childno, unsigned int argnum)
237 unsigned long val = 0;
239 switch (argnum) {
240 case 1: val = shm->syscall[childno].a1;
241 break;
242 case 2: val = shm->syscall[childno].a2;
243 break;
244 case 3: val = shm->syscall[childno].a3;
245 break;
246 case 4: val = shm->syscall[childno].a4;
247 break;
248 case 5: val = shm->syscall[childno].a5;
249 break;
250 case 6: val = shm->syscall[childno].a6;
251 break;
253 return val;
257 static unsigned long handle_arg_sockaddr(int childno, unsigned long call, unsigned long argnum)
259 struct syscallentry *entry;
260 struct sockaddr *sockaddr = NULL;
261 socklen_t sockaddrlen = 0;
263 entry = syscalls[call].entry;
265 generate_sockaddr((struct sockaddr **)&sockaddr, &sockaddrlen, PF_NOHINT);
267 switch (argnum) {
268 case 1: if (entry->arg2type == ARG_SOCKADDRLEN)
269 shm->syscall[childno].a2 = sockaddrlen;
270 break;
271 case 2: if (entry->arg3type == ARG_SOCKADDRLEN)
272 shm->syscall[childno].a3 = sockaddrlen;
273 break;
274 case 3: if (entry->arg4type == ARG_SOCKADDRLEN)
275 shm->syscall[childno].a4 = sockaddrlen;
276 break;
277 case 4: if (entry->arg5type == ARG_SOCKADDRLEN)
278 shm->syscall[childno].a5 = sockaddrlen;
279 break;
280 case 5: if (entry->arg6type == ARG_SOCKADDRLEN)
281 shm->syscall[childno].a6 = sockaddrlen;
282 break;
283 case 6:
284 break;
286 return (unsigned long) sockaddr;
289 static unsigned long handle_arg_mode_t(void)
291 unsigned int i, count;
292 mode_t mode = 0;
294 count = rand() % 9;
296 for (i = 0; i < count; i++) {
297 unsigned int j, bit;
299 bit = rand() % 3;
300 mode |= 1 << bit;
301 j = rand() % 12;
302 switch (j) {
303 case 0: mode |= S_IRUSR; break;
304 case 1: mode |= S_IWUSR; break;
305 case 2: mode |= S_IXUSR; break;
306 case 3: mode |= S_IRGRP; break;
307 case 4: mode |= S_IWGRP; break;
308 case 5: mode |= S_IXGRP; break;
309 case 6: mode |= S_IROTH; break;
310 case 7: mode |= S_IWOTH; break;
311 case 8: mode |= S_IXOTH; break;
312 case 9: mode |= S_ISUID; break;
313 case 10: mode|= S_ISGID; break;
314 case 11: mode|= S_ISVTX; break;
317 return mode;
320 static enum argtype get_argtype(struct syscallentry *entry, unsigned int argnum)
322 enum argtype argtype = 0;
324 switch (argnum) {
325 case 1: argtype = entry->arg1type;
326 break;
327 case 2: argtype = entry->arg2type;
328 break;
329 case 3: argtype = entry->arg3type;
330 break;
331 case 4: argtype = entry->arg4type;
332 break;
333 case 5: argtype = entry->arg5type;
334 break;
335 case 6: argtype = entry->arg6type;
336 break;
339 return argtype;
342 static unsigned long fill_arg(int childno, int call, unsigned int argnum)
344 struct syscallentry *entry;
345 enum argtype argtype;
347 entry = syscalls[call].entry;
349 if (argnum > entry->num_args)
350 return 0;
352 argtype = get_argtype(entry, argnum);
354 switch (argtype) {
355 case ARG_UNDEFINED:
356 case ARG_RANDOM_LONG:
357 return (unsigned long) rand64();
359 case ARG_FD:
360 return get_random_fd();
362 case ARG_LEN:
363 return (unsigned long) get_len();
365 case ARG_ADDRESS:
366 return handle_arg_address(childno, call, argnum);
368 case ARG_NON_NULL_ADDRESS:
369 return (unsigned long) get_non_null_address();
371 case ARG_MMAP:
372 return (unsigned long) get_map();
374 case ARG_PID:
375 return (unsigned long) get_pid();
377 case ARG_RANGE:
378 return handle_arg_range(call, argnum);
380 case ARG_OP: /* Like ARG_LIST, but just a single value. */
381 return handle_arg_op(call, argnum);
383 case ARG_LIST:
384 return handle_arg_list(call, argnum);
386 case ARG_RANDPAGE:
387 return handle_arg_randpage();
389 case ARG_CPU:
390 return (unsigned long) get_cpu();
392 case ARG_PATHNAME:
393 return (unsigned long) generate_pathname();
395 case ARG_IOVEC:
396 return handle_arg_iovec(childno, call, argnum);
398 case ARG_IOVECLEN:
399 case ARG_SOCKADDRLEN:
400 /* We already set the len in the ARG_IOVEC/ARG_SOCKADDR case
401 * So here we just return what we had set there. */
402 return get_argval(childno, argnum);
404 case ARG_SOCKADDR:
405 return handle_arg_sockaddr(childno, call, argnum);
407 case ARG_MODE_T:
408 return handle_arg_mode_t();
411 BUG("unreachable!\n");
414 void generic_sanitise(int childno)
416 struct syscallentry *entry;
417 unsigned int call = shm->syscall[childno].nr;
419 entry = syscalls[call].entry;
421 if (entry->arg1type != 0)
422 shm->syscall[childno].a1 = fill_arg(childno, call, 1);
423 if (entry->arg2type != 0)
424 shm->syscall[childno].a2 = fill_arg(childno, call, 2);
425 if (entry->arg3type != 0)
426 shm->syscall[childno].a3 = fill_arg(childno, call, 3);
427 if (entry->arg4type != 0)
428 shm->syscall[childno].a4 = fill_arg(childno, call, 4);
429 if (entry->arg5type != 0)
430 shm->syscall[childno].a5 = fill_arg(childno, call, 5);
431 if (entry->arg6type != 0)
432 shm->syscall[childno].a6 = fill_arg(childno, call, 6);
435 void generic_free_arg(int childno)
437 struct syscallentry *entry;
438 unsigned int call = shm->syscall[childno].nr;
439 enum argtype argtype;
440 unsigned int i;
442 entry = syscalls[call].entry;
444 for (i = 1; i <= entry->num_args; i++) {
445 argtype = get_argtype(entry, i);
447 if (argtype == ARG_IOVEC)
448 free((void *) get_argval(childno, i));