forked from kernelslacker/trinity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrandom-syscall.c
142 lines (112 loc) · 3.01 KB
/
random-syscall.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
* Call a single random syscall with random args.
*/
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "arch.h" // biarch
#include "arg-decoder.h"
#include "child.h"
#include "debug.h"
#include "locks.h"
#include "pids.h"
#include "random.h"
#include "shm.h"
#include "signals.h"
#include "sanitise.h"
#include "syscall.h"
#include "tables.h"
#include "trinity.h"
/*
* This function decides if we're going to be doing a 32bit or 64bit syscall.
* There are various factors involved here, from whether we're on a 32-bit only arch
* to 'we asked to do a 32bit only syscall' and more.. Hairy.
*/
static int *active_syscalls;
static bool choose_syscall_table(void)
{
bool do32 = FALSE;
if (biarch == FALSE) {
active_syscalls = shm->active_syscalls;
} else {
/* First, check that we have syscalls enabled in either table. */
if (validate_syscall_table_64() == FALSE) {
use_64bit = FALSE;
/* If no 64bit syscalls enabled, force 32bit. */
do32 = TRUE;
}
if (validate_syscall_table_32() == FALSE)
use_32bit = FALSE;
/* If both tables enabled, pick randomly. */
if ((use_64bit == TRUE) && (use_32bit == TRUE)) {
/* 10% possibility of a 32bit syscall */
if (ONE_IN(10))
do32 = TRUE;
}
if (do32 == FALSE) {
syscalls = syscalls_64bit;
active_syscalls = shm->active_syscalls64;
max_nr_syscalls = max_nr_64bit_syscalls;
} else {
syscalls = syscalls_32bit;
active_syscalls = shm->active_syscalls32;
max_nr_syscalls = max_nr_32bit_syscalls;
}
}
return do32;
}
static bool set_syscall_nr(struct syscallrecord *rec)
{
struct syscallentry *entry;
unsigned int syscallnr;
bool do32;
retry:
if (no_syscalls_enabled() == TRUE) {
output(0, "[%d] No more syscalls enabled. Exiting\n", getpid());
shm->exit_reason = EXIT_NO_SYSCALLS_ENABLED;
return FAIL;
}
/* Ok, we're doing another syscall, let's pick one. */
do32 = choose_syscall_table();
syscallnr = rnd() % max_nr_syscalls;
/* If we got a syscallnr which is not active repeat the attempt,
* since another child has switched that syscall off already.*/
if (active_syscalls[syscallnr] == 0)
goto retry;
syscallnr = active_syscalls[syscallnr] - 1;
if (validate_specific_syscall_silent(syscalls, syscallnr) == FALSE) {
deactivate_syscall(syscallnr, do32);
goto retry;
}
entry = get_syscall_entry(syscallnr, do32);
if (entry->flags & EXPENSIVE) {
if (!ONE_IN(1000))
goto retry;
}
/* critical section for shm updates. */
lock(&rec->lock);
rec->do32bit = do32;
rec->nr = syscallnr;
unlock(&rec->lock);
return TRUE;
}
bool random_syscall(struct childdata *child)
{
struct syscallrecord *rec;
int ret = FALSE;
rec = &child->syscall;
if (set_syscall_nr(rec) == FAIL)
return FAIL;
memset(rec->postbuffer, 0, POSTBUFFER_LEN);
/* Generate arguments, print them out */
generate_syscall_args(rec);
output_syscall_prefix(rec);
do_syscall(rec);
output_syscall_postfix(rec);
handle_syscall_ret(rec);
ret = TRUE;
return ret;
}