merge send* syscall variants
[trinity.git] / generic-sanitise.c
bloba7050d4bcaa394d51fe680ddd9dde601f92bc524
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 int *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 static unsigned long handle_arg_list(unsigned long call, unsigned long argnum)
144 struct syscallentry *entry;
145 unsigned long i;
146 unsigned long mask = 0;
147 unsigned int bits;
148 unsigned int num = 0;
149 const unsigned int *values = NULL;
151 entry = syscalls[call].entry;
153 switch (argnum) {
154 case 1: num = entry->arg1list.num;
155 values = entry->arg1list.values;
156 break;
157 case 2: num = entry->arg2list.num;
158 values = entry->arg2list.values;
159 break;
160 case 3: num = entry->arg3list.num;
161 values = entry->arg3list.values;
162 break;
163 case 4: num = entry->arg4list.num;
164 values = entry->arg4list.values;
165 break;
166 case 5: num = entry->arg5list.num;
167 values = entry->arg5list.values;
168 break;
169 case 6: num = entry->arg6list.num;
170 values = entry->arg6list.values;
171 break;
174 if (num == 0)
175 BUG("ARG_LIST with 0 args. What?\n");
177 if (values == NULL)
178 BUG("ARG_LIST with no values.\n");
180 bits = rand() % (num + 1); /* num of bits to OR */
181 for (i = 0; i < bits; i++)
182 mask |= values[rand() % num];
183 return mask;
186 static unsigned long handle_arg_randpage(void)
188 /* Because we pass this to something that might overwrite it,
189 * and we want page_allocs to remain unmodified, we copy it to page rand instead.
191 if (rand_bool())
192 memcpy(page_rand, page_allocs, page_size);
194 return (unsigned long) page_rand;
197 static unsigned long handle_arg_iovec(int childno, unsigned long call, unsigned long argnum)
199 struct syscallentry *entry;
200 unsigned long num_entries;
202 entry = syscalls[call].entry;
204 num_entries = 1 << (rand() % 11);
206 switch (argnum) {
207 case 1: if (entry->arg2type == ARG_IOVECLEN)
208 shm->syscall[childno].a2 = num_entries;
209 break;
210 case 2: if (entry->arg3type == ARG_IOVECLEN)
211 shm->syscall[childno].a3 = num_entries;
212 break;
213 case 3: if (entry->arg4type == ARG_IOVECLEN)
214 shm->syscall[childno].a4 = num_entries;
215 break;
216 case 4: if (entry->arg5type == ARG_IOVECLEN)
217 shm->syscall[childno].a5 = num_entries;
218 break;
219 case 5: if (entry->arg6type == ARG_IOVECLEN)
220 shm->syscall[childno].a6 = num_entries;
221 break;
223 return (unsigned long) alloc_iovec(num_entries);
226 static unsigned long handle_arg_len_already_set(int childno, unsigned long argnum)
228 unsigned long r = 0;
231 * We already set the len in the ARG_IOVEC/ARG_SOCKADDR case
232 * So here we just return what we had set there.
234 switch (argnum) {
235 case 1: r = shm->syscall[childno].a1; break;
236 case 2: r = shm->syscall[childno].a2; break;
237 case 3: r = shm->syscall[childno].a3; break;
238 case 4: r = shm->syscall[childno].a4; break;
239 case 5: r = shm->syscall[childno].a5; break;
240 case 6: r = shm->syscall[childno].a6; break;
242 return r;
245 static unsigned long handle_arg_sockaddr(int childno, unsigned long call, unsigned long argnum)
247 struct syscallentry *entry;
248 struct sockaddr *sockaddr = NULL;
249 socklen_t sockaddrlen = 0;
251 entry = syscalls[call].entry;
253 generate_sockaddr((struct sockaddr **)&sockaddr, &sockaddrlen, PF_NOHINT);
255 switch (argnum) {
256 case 1: if (entry->arg2type == ARG_SOCKADDRLEN)
257 shm->syscall[childno].a2 = sockaddrlen;
258 break;
259 case 2: if (entry->arg3type == ARG_SOCKADDRLEN)
260 shm->syscall[childno].a3 = sockaddrlen;
261 break;
262 case 3: if (entry->arg4type == ARG_SOCKADDRLEN)
263 shm->syscall[childno].a4 = sockaddrlen;
264 break;
265 case 4: if (entry->arg5type == ARG_SOCKADDRLEN)
266 shm->syscall[childno].a5 = sockaddrlen;
267 break;
268 case 5: if (entry->arg6type == ARG_SOCKADDRLEN)
269 shm->syscall[childno].a6 = sockaddrlen;
270 break;
271 case 6:
272 break;
274 return (unsigned long) sockaddr;
277 static unsigned long handle_arg_mode_t(void)
279 unsigned int i, count;
280 mode_t mode = 0;
282 count = rand() % 9;
284 for (i = 0; i < count; i++) {
285 unsigned int j, bit;
287 bit = rand() % 3;
288 mode |= 1 << bit;
289 j = rand() % 12;
290 switch (j) {
291 case 0: mode |= S_IRUSR; break;
292 case 1: mode |= S_IWUSR; break;
293 case 2: mode |= S_IXUSR; break;
294 case 3: mode |= S_IRGRP; break;
295 case 4: mode |= S_IWGRP; break;
296 case 5: mode |= S_IXGRP; break;
297 case 6: mode |= S_IROTH; break;
298 case 7: mode |= S_IWOTH; break;
299 case 8: mode |= S_IXOTH; break;
300 case 9: mode |= S_ISUID; break;
301 case 10: mode|= S_ISGID; break;
302 case 11: mode|= S_ISVTX; break;
305 return mode;
309 static unsigned long fill_arg(int childno, int call, unsigned int argnum)
311 struct syscallentry *entry;
312 enum argtype argtype = 0;
314 entry = syscalls[call].entry;
316 if (argnum > entry->num_args)
317 return 0;
319 switch (argnum) {
320 case 1: argtype = entry->arg1type;
321 break;
322 case 2: argtype = entry->arg2type;
323 break;
324 case 3: argtype = entry->arg3type;
325 break;
326 case 4: argtype = entry->arg4type;
327 break;
328 case 5: argtype = entry->arg5type;
329 break;
330 case 6: argtype = entry->arg6type;
331 break;
334 switch (argtype) {
335 case ARG_UNDEFINED:
336 case ARG_RANDOM_LONG:
337 return (unsigned long) rand64();
339 case ARG_FD:
340 return get_random_fd();
342 case ARG_LEN:
343 return (unsigned long) get_len();
345 case ARG_ADDRESS:
346 return handle_arg_address(childno, call, argnum);
348 case ARG_NON_NULL_ADDRESS:
349 return (unsigned long) get_non_null_address();
351 case ARG_MMAP:
352 return (unsigned long) get_map();
354 case ARG_PID:
355 return (unsigned long) get_pid();
357 case ARG_RANGE:
358 return handle_arg_range(call, argnum);
360 case ARG_OP: /* Like ARG_LIST, but just a single value. */
361 return handle_arg_op(call, argnum);
363 case ARG_LIST:
364 return handle_arg_list(call, argnum);
366 case ARG_RANDPAGE:
367 return handle_arg_randpage();
369 case ARG_CPU:
370 return (unsigned long) get_cpu();
372 case ARG_PATHNAME:
373 return (unsigned long) generate_pathname();
375 case ARG_IOVEC:
376 return handle_arg_iovec(childno, call, argnum);
378 case ARG_IOVECLEN:
379 case ARG_SOCKADDRLEN:
380 return handle_arg_len_already_set(childno, argnum);
382 case ARG_SOCKADDR:
383 return handle_arg_sockaddr(childno, call, argnum);
385 case ARG_MODE_T:
386 return handle_arg_mode_t();
389 BUG("unreachable!\n");
392 void generic_sanitise(int childno)
394 struct syscallentry *entry;
395 unsigned int call = shm->syscall[childno].nr;
397 entry = syscalls[call].entry;
399 if (entry->arg1type != 0)
400 shm->syscall[childno].a1 = fill_arg(childno, call, 1);
401 if (entry->arg2type != 0)
402 shm->syscall[childno].a2 = fill_arg(childno, call, 2);
403 if (entry->arg3type != 0)
404 shm->syscall[childno].a3 = fill_arg(childno, call, 3);
405 if (entry->arg4type != 0)
406 shm->syscall[childno].a4 = fill_arg(childno, call, 4);
407 if (entry->arg5type != 0)
408 shm->syscall[childno].a5 = fill_arg(childno, call, 5);
409 if (entry->arg6type != 0)
410 shm->syscall[childno].a6 = fill_arg(childno, call, 6);