mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-23 03:19:51 +00:00
executor: make exit code during fail() depend on fault injection
fail()'s are often used during the validation of kernel reactions to queries that were issued by pseudo syscalls implementations. As fault injection may cause the kernel not to succeed in handling these queries (e.g. socket writes or reads may fail), this could ultimately lead to unwanted "lost connection to test machine" crashes. In order to avoid this and, on the other hand, to still have the ability to signal a disastrous situation, the exit code of this function now depends on the current context. All fail() invocations during system call execution with enabled fault injection lead to termination with zero exit code. In all other cases, the exit code is kFailStatus. This is achieved by introduction of a special thread-specific variable `current_thread` that allows to access information about the thread in which the current code is executing. Also, this commit eliminates current_cover as it is no longer needed.
This commit is contained in:
parent
2450c42f1b
commit
3e8f6c2755
@ -215,10 +215,13 @@ struct thread_t {
|
||||
uint32 reserrno;
|
||||
bool fault_injected;
|
||||
cover_t cov;
|
||||
bool soft_fail_state;
|
||||
};
|
||||
|
||||
static thread_t threads[kMaxThreads];
|
||||
static thread_t* last_scheduled;
|
||||
// Threads use this variable to access information about themselves.
|
||||
static __thread struct thread_t* current_thread;
|
||||
|
||||
static cover_t extra_cov;
|
||||
|
||||
@ -375,6 +378,7 @@ int main(int argc, char** argv)
|
||||
start_time_ms = current_time_ms();
|
||||
|
||||
os_init(argc, argv, (char*)SYZ_DATA_OFFSET, SYZ_NUM_PAGES * SYZ_PAGE_SIZE);
|
||||
current_thread = &threads[0];
|
||||
|
||||
#if SYZ_EXECUTOR_USES_SHMEM
|
||||
if (mmap(&input_data[0], kMaxInput, PROT_READ, MAP_PRIVATE | MAP_FIXED, kInFd, 0) != &input_data[0])
|
||||
@ -1059,7 +1063,7 @@ void thread_create(thread_t* th, int id)
|
||||
void* worker_thread(void* arg)
|
||||
{
|
||||
thread_t* th = (thread_t*)arg;
|
||||
|
||||
current_thread = th;
|
||||
if (flag_coverage)
|
||||
cover_enable(&th->cov, flag_comparisons, false);
|
||||
for (;;) {
|
||||
@ -1084,10 +1088,12 @@ void execute_call(thread_t* th)
|
||||
debug(")\n");
|
||||
|
||||
int fail_fd = -1;
|
||||
th->soft_fail_state = false;
|
||||
if (flag_fault && th->call_index == flag_fault_call) {
|
||||
if (collide)
|
||||
fail("both collide and fault injection are enabled");
|
||||
fail_fd = inject_fault(flag_fault_nth);
|
||||
th->soft_fail_state = true;
|
||||
}
|
||||
|
||||
if (flag_coverage)
|
||||
@ -1104,6 +1110,9 @@ void execute_call(thread_t* th)
|
||||
th->res = 0;
|
||||
th->reserrno = 0;
|
||||
}
|
||||
// Reset the flag before the first possible fail().
|
||||
th->soft_fail_state = false;
|
||||
|
||||
if (flag_coverage) {
|
||||
cover_collect(&th->cov);
|
||||
if (th->cov.size >= kCoverSize)
|
||||
@ -1477,6 +1486,20 @@ void fail(const char* msg, ...)
|
||||
vfprintf(stderr, msg, args);
|
||||
va_end(args);
|
||||
fprintf(stderr, " (errno %d)\n", e);
|
||||
|
||||
// fail()'s are often used during the validation of kernel reactions to queries
|
||||
// that were issued by pseudo syscalls implementations. As fault injection may
|
||||
// cause the kernel not to succeed in handling these queries (e.g. socket writes
|
||||
// or reads may fail), this could ultimately lead to unwanted "lost connection to
|
||||
// test machine" crashes.
|
||||
// In order to avoid this and, on the other hand, to still have the ability to
|
||||
// signal a disastrous situation, the exit code of this function depends on the
|
||||
// current context.
|
||||
// All fail() invocations during system call execution with enabled fault injection
|
||||
// lead to termination with zero exit code. In all other cases, the exit code is
|
||||
// kFailStatus.
|
||||
if (current_thread && current_thread->soft_fail_state)
|
||||
doexit(0);
|
||||
doexit(kFailStatus);
|
||||
}
|
||||
|
||||
|
@ -80,8 +80,6 @@ static void os_init(int argc, char** argv, char* data, size_t data_size)
|
||||
fail("mmap of right data PROT_NONE page failed");
|
||||
}
|
||||
|
||||
static __thread cover_t* current_cover;
|
||||
|
||||
static intptr_t execute_syscall(const call_t* c, intptr_t a[kMaxArgs])
|
||||
{
|
||||
if (c->call)
|
||||
@ -186,7 +184,6 @@ static void cover_enable(cover_t* cov, bool collect_comps, bool extra)
|
||||
if (!extra) {
|
||||
if (ioctl(cov->fd, KCOV_ENABLE, kcov_mode))
|
||||
exitf("cover enable write trace failed, mode=%d", kcov_mode);
|
||||
current_cover = cov;
|
||||
return;
|
||||
}
|
||||
if (is_kernel_64_bit)
|
||||
@ -201,9 +198,9 @@ static void cover_reset(cover_t* cov)
|
||||
if (!flag_coverage)
|
||||
return;
|
||||
if (cov == 0) {
|
||||
if (current_cover == 0)
|
||||
fail("cover_reset: current_cover == 0");
|
||||
cov = current_cover;
|
||||
if (current_thread == 0)
|
||||
fail("cover_reset: current_thread == 0");
|
||||
cov = ¤t_thread->cov;
|
||||
}
|
||||
*(uint64*)cov->data = 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user