void main_loop() { regenerate(); if (do_specific_syscall == 1) regenerate_random_page(); while (1) { fork_children(); handle_children(); /* Only check taint if it was zero on startup */ if (do_check_tainted == 0) { if (check_tainted() != 0) { output("kernel became tainted!\n"); exit(EXIT_FAILURE); } } if (syscallcount && (shm->execcount >= syscallcount)) exit(EXIT_SUCCESS); if (shm->execcount % 1000 == 0) synclogs(); } }
bool child_random_syscalls(void) { struct syscallrecord *rec; unsigned int syscallnr; bool do32; unsigned int len; 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 = rand() % 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; } rec = &this_child->syscall; /* critical section for shm updates. */ lock(&rec->lock); rec->do32bit = do32; rec->nr = syscallnr; unlock(&rec->lock); if (syscalls_todo) { if (shm->stats.total_syscalls_done >= syscalls_todo) shm->exit_reason = EXIT_REACHED_COUNT; } /* Generate arguments, print them out */ generate_syscall_args(rec); output_syscall_prefix(rec); /* Sanity check: Make sure the length of the buffer remains * constant across the syscall. */ len = strlen(rec->prebuffer); /* If we're going to pause, might as well sync pre-syscall */ if (dopause == TRUE) synclogs(); do_syscall(rec); /* post syscall sanity checks. */ if (len != strlen(rec->prebuffer)) { output(0, "Sanity check failed: prebuffer length changed from %d to %d.\n", len, strlen(rec->prebuffer)); } /* Output the syscall result, and clean up */ output_syscall_postfix(rec); if (dopause == TRUE) sleep(1); handle_syscall_ret(rec); return TRUE; }
static void watchdog(void) { static const char watchdogname[17]="trinity-watchdog"; static unsigned long lastcount = 0; bool watchdog_exit = FALSE; int ret = 0; while (shm->ready == FALSE) { sleep(1); if (shm->exit_reason != STILL_RUNNING) return; } output(0, "Watchdog is alive. (pid:%d)\n", watchdog_pid); prctl(PR_SET_NAME, (unsigned long) &watchdogname); (void)signal(SIGSEGV, SIG_DFL); while (watchdog_exit == FALSE) { if (check_shm_sanity() == SHM_CORRUPT) goto corrupt; if (check_main_alive() == FALSE) goto main_dead; if (shm->regenerating == FALSE) { unsigned int i; reap_dead_kids(); check_children(); if (syscalls_todo && (shm->total_syscalls_done >= syscalls_todo)) { output(0, "Reached limit %d. Telling children to exit.\n", syscalls_todo); shm->exit_reason = EXIT_REACHED_COUNT; } // Periodic log syncing. FIXME: This is kinda ugly, and mostly unnecessary. if (shm->total_syscalls_done % 1000 == 0) synclogs(); for_each_pidslot(i) { if (shm->child_syscall_count[i] > hiscore) hiscore = shm->child_syscall_count[i]; } if (shm->total_syscalls_done > 1) { if (shm->total_syscalls_done - lastcount > 10000) { output(0, "%ld iterations. [F:%ld S:%ld HI:%ld]\n", shm->total_syscalls_done, shm->failures, shm->successes, hiscore); lastcount = shm->total_syscalls_done; } } } /* Only check taint if it mask allows it */ if (kernel_taint_mask != 0) { ret = check_tainted(); if (((ret & kernel_taint_mask) & (~kernel_taint_initial)) != 0) { gettimeofday(&shm->taint_tv, NULL); output(0, "kernel became tainted! (%d/%d) Last seed was %u\n", ret, kernel_taint_initial, shm->seed); shm->exit_reason = EXIT_KERNEL_TAINTED; } } main_dead: /* Are we done ? */ if (shm->exit_reason != STILL_RUNNING) { /* Give children a chance to exit. */ sleep(1); /* Are there still children running ? */ if (pidmap_empty() == TRUE) watchdog_exit = TRUE; else { output(0, "exit_reason=%d, but %d children still running.\n", shm->exit_reason, shm->running_childs); kill_all_kids(); } } sleep(1); }