void deactivate_disabled_syscalls_uniarch(void) { unsigned int i; for_each_syscall(i) { if (syscalls[i].entry->flags & TO_BE_DEACTIVATED) { syscalls[i].entry->flags &= ~(ACTIVE|TO_BE_DEACTIVATED); deactivate_syscall(i); output(0, "Marked syscall %s (%d) as deactivated.\n", syscalls[i].entry->name, syscalls[i].entry->number); } } }
/* * This routine does 32 bit syscalls on 64 bit kernel. * 32-on-32 will just use syscall() directly from do_syscall() because do32bit flag is biarch only. */ static long syscall32(unsigned int call, unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, unsigned long a6) { long __res = 0; #if defined(DO_32_SYSCALL) /* If we have CONFIG_IA32_EMULATION unset, we will segfault. * Detect this case, and force 64-bit only. */ if (shm->syscalls32_succeeded == FALSE) { if (shm->syscalls32_attempted >= (max_children * 2)) { unsigned int i; lock(&shm->syscalltable_lock); /* check another thread didn't already do this. */ if (shm->nr_active_32bit_syscalls == 0) goto already_done; output(0, "Tried %d 32-bit syscalls unsuccessfully. Disabling all 32-bit syscalls.\n", shm->syscalls32_attempted); for (i = 0; i < max_nr_32bit_syscalls; i++) { struct syscallentry *entry = syscalls[i].entry; if (entry->active_number != 0) deactivate_syscall(i, TRUE); } already_done: unlock(&shm->syscalltable_lock); } shm->syscalls32_attempted++; } DO_32_SYSCALL if ((unsigned long)(__res) >= (unsigned long)(-133)) { errno = -(__res); __res = -1; } shm->syscalls32_succeeded = TRUE; #else #error Implement 32-on-64 syscall macro for this architecture. #endif return __res; }
/* * If the syscall doesn't exist don't bother calling it next time. * Some syscalls return ENOSYS depending on their arguments, we mark * those as IGNORE_ENOSYS and keep calling them. */ static void deactivate_enosys(struct syscallrecord *rec, struct syscallentry *entry, unsigned int call) { /* some syscalls return ENOSYS instead of EINVAL etc (futex for eg) */ if (entry->flags & IGNORE_ENOSYS) return; lock(&shm->syscalltable_lock); /* check another thread didn't already do this. */ if (entry->active_number == 0) goto already_done; output(1, "%s (%d%s) returned ENOSYS, marking as inactive.\n", entry->name, call + SYSCALL_OFFSET, rec->do32bit == TRUE ? ":[32BIT]" : ""); deactivate_syscall(call, rec->do32bit); already_done: unlock(&shm->syscalltable_lock); }
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; }
int child_random_syscalls(int childno) { int ret; unsigned int syscallnr; ret = sigsetjmp(ret_jump, 1); if (ret != 0) { if (handle_sigreturn(childno) == 0) return 0; ret = 0; } while (shm->exit_reason == STILL_RUNNING) { check_parent_pid(); while (shm->regenerating == TRUE) sleep(1); /* If the parent reseeded, we should reflect the latest seed too. */ if (shm->seed != shm->seeds[childno]) set_seed(childno); choose_syscall_table(childno); if (nr_active_syscalls == 0) { shm->exit_reason = EXIT_NO_SYSCALLS_ENABLED; goto out; } if (shm->exit_reason != STILL_RUNNING) goto out; syscallnr = rand() % nr_active_syscalls; /* If we got a syscallnr which is not actvie repeat the attempt, since another child has switched that syscall off already.*/ if (active_syscalls[syscallnr] == 0) continue; syscallnr = active_syscalls[syscallnr] - 1; if (validate_specific_syscall_silent(syscalls, syscallnr) == FALSE) { if (biarch == FALSE) { deactivate_syscall(syscallnr); } else { if (shm->do32bit[childno] == TRUE) deactivate_syscall32(syscallnr); else deactivate_syscall64(syscallnr); } continue; } shm->syscallno[childno] = syscallnr; if (syscalls_todo) { if (shm->total_syscalls_done >= syscalls_todo) { output(0, "Reached maximum syscall count (todo = %d, done = %d), exiting...\n", syscalls_todo, shm->total_syscalls_done); shm->exit_reason = EXIT_REACHED_COUNT; } } ret = mkcall(childno); } out: return ret; }