move swap on/off variants into same file
[trinity.git] / generic-sanitise.c
blob8cc88ed34237559b0a4be5a9c76a5e7c826bb200
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <string.h>
6 #include "trinity.h" // page_size
7 #include "files.h"
8 #include "arch.h"
9 #include "random.h"
10 #include "sanitise.h"
11 #include "syscall.h"
12 #include "net.h"
13 #include "log.h"
14 #include "maps.h"
15 #include "shm.h"
16 #include "tables.h"
18 static unsigned int get_cpu(void)
20 int i;
21 i = rand() % 100;
23 switch (i) {
24 case 0: return -1;
25 case 1: return rand() % 4095;
26 case 2: return rand() % 15;
28 case 3 ... 99:
29 return rand() % num_online_cpus;
31 return 0;
34 static unsigned long handle_arg_address(int childno, int call, int argnum)
36 unsigned long addr = 0;
38 if (rand_bool())
39 return (unsigned long) get_address();
41 /* Half the time, we look to see if earlier args were also ARG_ADDRESS,
42 * and munge that instead of returning a new one from get_address() */
44 addr = find_previous_arg_address(argnum, call, childno);
46 switch (rand() % 4) {
47 case 0: break; /* return unmodified */
48 case 1: addr++;
49 break;
50 case 2: addr+= sizeof(int);
51 break;
52 case 3: addr+= sizeof(long);
53 break;
56 return addr;
59 static unsigned long handle_arg_range(unsigned int call, unsigned int argnum)
61 struct syscallentry *entry;
62 unsigned long i;
63 unsigned long low = 0, high = 0;
65 entry = syscalls[call].entry;
67 switch (argnum) {
68 case 1: low = entry->low1range;
69 high = entry->hi1range;
70 break;
71 case 2: low = entry->low2range;
72 high = entry->hi2range;
73 break;
74 case 3: low = entry->low3range;
75 high = entry->hi3range;
76 break;
77 case 4: low = entry->low4range;
78 high = entry->hi4range;
79 break;
80 case 5: low = entry->low5range;
81 high = entry->hi5range;
82 break;
83 case 6: low = entry->low6range;
84 high = entry->hi6range;
85 break;
88 if (high == 0) {
89 outputerr("%s forgets to set hirange!\n", entry->name);
90 BUG("Fix syscall definition!\n");
93 i = (unsigned long) rand64() % high;
94 if (i < low) {
95 i += low;
96 i &= high;
98 return i;
101 static unsigned long handle_arg_op(unsigned long call, unsigned long argnum)
103 struct syscallentry *entry;
104 const unsigned int *values = NULL;
105 unsigned int num = 0;
106 unsigned long mask = 0;
108 entry = syscalls[call].entry;
110 switch (argnum) {
111 case 1: num = entry->arg1list.num;
112 values = entry->arg1list.values;
113 break;
114 case 2: num = entry->arg2list.num;
115 values = entry->arg2list.values;
116 break;
117 case 3: num = entry->arg3list.num;
118 values = entry->arg3list.values;
119 break;
120 case 4: num = entry->arg4list.num;
121 values = entry->arg4list.values;
122 break;
123 case 5: num = entry->arg5list.num;
124 values = entry->arg5list.values;
125 break;
126 case 6: num = entry->arg6list.num;
127 values = entry->arg6list.values;
128 break;
131 if (num == 0)
132 BUG("ARG_OP with 0 args. What?\n");
134 if (values == NULL)
135 BUG("ARG_OP with no values.\n");
137 mask |= values[rand() % num];
138 return mask;
141 static unsigned long handle_arg_list(unsigned long call, unsigned long argnum)
143 struct syscallentry *entry;
144 unsigned long i;
145 unsigned long mask = 0;
146 unsigned int bits;
147 unsigned int num = 0;
148 const unsigned int *values = NULL;
150 entry = syscalls[call].entry;
152 switch (argnum) {
153 case 1: num = entry->arg1list.num;
154 values = entry->arg1list.values;
155 break;
156 case 2: num = entry->arg2list.num;
157 values = entry->arg2list.values;
158 break;
159 case 3: num = entry->arg3list.num;
160 values = entry->arg3list.values;
161 break;
162 case 4: num = entry->arg4list.num;
163 values = entry->arg4list.values;
164 break;
165 case 5: num = entry->arg5list.num;
166 values = entry->arg5list.values;
167 break;
168 case 6: num = entry->arg6list.num;
169 values = entry->arg6list.values;
170 break;
173 if (num == 0)
174 BUG("ARG_LIST with 0 args. What?\n");
176 if (values == NULL)
177 BUG("ARG_LIST with no values.\n");
179 bits = rand() % (num + 1); /* num of bits to OR */
180 for (i = 0; i < bits; i++)
181 mask |= values[rand() % num];
182 return mask;
185 static unsigned long handle_arg_randpage(void)
187 /* Because we pass this to something that might overwrite it,
188 * and we want page_allocs to remain unmodified, we copy it to page rand instead.
190 if (rand_bool())
191 memcpy(page_rand, page_allocs, page_size);
193 return (unsigned long) page_rand;
196 static unsigned long handle_arg_iovec(int childno, unsigned long call, unsigned long argnum)
198 struct syscallentry *entry;
199 unsigned long num_entries;
201 entry = syscalls[call].entry;
203 num_entries = 1 << (rand() % 11);
205 switch (argnum) {
206 case 1: if (entry->arg2type == ARG_IOVECLEN)
207 shm->a2[childno] = num_entries;
208 break;
209 case 2: if (entry->arg3type == ARG_IOVECLEN)
210 shm->a3[childno] = num_entries;
211 break;
212 case 3: if (entry->arg4type == ARG_IOVECLEN)
213 shm->a4[childno] = num_entries;
214 break;
215 case 4: if (entry->arg5type == ARG_IOVECLEN)
216 shm->a5[childno] = num_entries;
217 break;
218 case 5: if (entry->arg6type == ARG_IOVECLEN)
219 shm->a6[childno] = num_entries;
220 break;
222 return (unsigned long) alloc_iovec(num_entries);
225 static unsigned long handle_arg_len_already_set(int childno, unsigned long argnum)
227 unsigned long r = 0;
230 * We already set the len in the ARG_IOVEC/ARG_SOCKADDR case
231 * So here we just return what we had set there.
233 switch (argnum) {
234 case 1: r = shm->a1[childno]; break;
235 case 2: r = shm->a2[childno]; break;
236 case 3: r = shm->a3[childno]; break;
237 case 4: r = shm->a4[childno]; break;
238 case 5: r = shm->a5[childno]; break;
239 case 6: r = shm->a6[childno]; break;
241 return r;
244 static unsigned long handle_arg_sockaddr(int childno, unsigned long call, unsigned long argnum)
246 struct syscallentry *entry;
247 struct sockaddr *sockaddr = NULL;
248 socklen_t sockaddrlen = 0;
250 entry = syscalls[call].entry;
252 generate_sockaddr((struct sockaddr **)&sockaddr, &sockaddrlen, PF_NOHINT);
254 switch (argnum) {
255 case 1: if (entry->arg2type == ARG_SOCKADDRLEN)
256 shm->a2[childno] = sockaddrlen;
257 break;
258 case 2: if (entry->arg3type == ARG_SOCKADDRLEN)
259 shm->a3[childno] = sockaddrlen;
260 break;
261 case 3: if (entry->arg4type == ARG_SOCKADDRLEN)
262 shm->a4[childno] = sockaddrlen;
263 break;
264 case 4: if (entry->arg5type == ARG_SOCKADDRLEN)
265 shm->a5[childno] = sockaddrlen;
266 break;
267 case 5: if (entry->arg6type == ARG_SOCKADDRLEN)
268 shm->a6[childno] = sockaddrlen;
269 break;
270 case 6:
271 break;
273 return (unsigned long) sockaddr;
276 static unsigned long handle_arg_mode_t(void)
278 unsigned int i, count;
279 mode_t mode = 0;
281 count = rand() % 9;
283 for (i = 0; i < count; i++) {
284 unsigned int j, bit;
286 bit = rand() % 3;
287 mode |= 1 << bit;
288 j = rand() % 12;
289 switch (j) {
290 case 0: mode |= S_IRUSR; break;
291 case 1: mode |= S_IWUSR; break;
292 case 2: mode |= S_IXUSR; break;
293 case 3: mode |= S_IRGRP; break;
294 case 4: mode |= S_IWGRP; break;
295 case 5: mode |= S_IXGRP; break;
296 case 6: mode |= S_IROTH; break;
297 case 7: mode |= S_IWOTH; break;
298 case 8: mode |= S_IXOTH; break;
299 case 9: mode |= S_ISUID; break;
300 case 10: mode|= S_ISGID; break;
301 case 11: mode|= S_ISVTX; break;
304 return mode;
308 static unsigned long fill_arg(int childno, int call, unsigned int argnum)
310 struct syscallentry *entry;
311 enum argtype argtype = 0;
313 entry = syscalls[call].entry;
315 if (argnum > entry->num_args)
316 return 0;
318 switch (argnum) {
319 case 1: argtype = entry->arg1type;
320 break;
321 case 2: argtype = entry->arg2type;
322 break;
323 case 3: argtype = entry->arg3type;
324 break;
325 case 4: argtype = entry->arg4type;
326 break;
327 case 5: argtype = entry->arg5type;
328 break;
329 case 6: argtype = entry->arg6type;
330 break;
333 switch (argtype) {
334 case ARG_UNDEFINED:
335 case ARG_RANDOM_LONG:
336 return (unsigned long) rand64();
338 case ARG_FD:
339 return get_random_fd();
341 case ARG_LEN:
342 return (unsigned long) get_len();
344 case ARG_ADDRESS:
345 return handle_arg_address(childno, call, argnum);
347 case ARG_NON_NULL_ADDRESS:
348 return (unsigned long) get_non_null_address();
350 case ARG_MMAP:
351 return (unsigned long) get_map();
353 case ARG_PID:
354 return (unsigned long) get_pid();
356 case ARG_RANGE:
357 return handle_arg_range(call, argnum);
359 case ARG_OP: /* Like ARG_LIST, but just a single value. */
360 return handle_arg_op(call, argnum);
362 case ARG_LIST:
363 return handle_arg_list(call, argnum);
365 case ARG_RANDPAGE:
366 return handle_arg_randpage();
368 case ARG_CPU:
369 return (unsigned long) get_cpu();
371 case ARG_PATHNAME:
372 return (unsigned long) generate_pathname();
374 case ARG_IOVEC:
375 return handle_arg_iovec(childno, call, argnum);
377 case ARG_IOVECLEN:
378 case ARG_SOCKADDRLEN:
379 return handle_arg_len_already_set(childno, argnum);
381 case ARG_SOCKADDR:
382 return handle_arg_sockaddr(childno, call, argnum);
384 case ARG_MODE_T:
385 return handle_arg_mode_t();
388 BUG("unreachable!\n");
391 void generic_sanitise(int childno)
393 struct syscallentry *entry;
394 unsigned int call = shm->syscallno[childno];
396 entry = syscalls[call].entry;
398 if (entry->arg1type != 0)
399 shm->a1[childno] = fill_arg(childno, call, 1);
400 if (entry->arg2type != 0)
401 shm->a2[childno] = fill_arg(childno, call, 2);
402 if (entry->arg3type != 0)
403 shm->a3[childno] = fill_arg(childno, call, 3);
404 if (entry->arg4type != 0)
405 shm->a4[childno] = fill_arg(childno, call, 4);
406 if (entry->arg5type != 0)
407 shm->a5[childno] = fill_arg(childno, call, 5);
408 if (entry->arg6type != 0)
409 shm->a6[childno] = fill_arg(childno, call, 6);