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;
}
|