void userspace(union uml_pt_regs *regs) { int err, status, op, pid = userspace_pid[0]; int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/ while(1){ restore_registers(pid, regs); /* Now we set local_using_sysemu to be used for one loop */ local_using_sysemu = get_using_sysemu(); op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL)); err = ptrace(op, pid, 0, 0); if(err) panic("userspace - could not resume userspace process, " "pid=%d, ptrace operation = %d, errno = %d\n", op, errno); CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); if(err < 0) panic("userspace - waitpid failed, errno = %d\n", errno); regs->skas.is_user = 1; save_registers(pid, regs); UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ if(WIFSTOPPED(status)){ switch(WSTOPSIG(status)){ case SIGSEGV: handle_segv(pid, regs); break; case SIGTRAP + 0x80: handle_trap(pid, regs, local_using_sysemu); break; case SIGTRAP: relay_signal(SIGTRAP, regs); break; case SIGIO: case SIGVTALRM: case SIGILL: case SIGBUS: case SIGFPE: case SIGWINCH: user_signal(WSTOPSIG(status), regs, pid); break; default: printk("userspace - child stopped with signal " "%d\n", WSTOPSIG(status)); } interrupt_end(); /* Avoid -ERESTARTSYS handling in host */ PT_SYSCALL_NR(regs->skas.regs) = -1; } } }
void userspace(union uml_pt_regs *regs) { int err, status, op, pid = userspace_pid[0]; restore_registers(regs); err = ptrace(PTRACE_SYSCALL, pid, 0, 0); if(err) panic("userspace - PTRACE_SYSCALL failed, errno = %d\n", errno); while(1){ CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); if(err < 0) panic("userspace - waitpid failed, errno = %d\n", errno); regs->skas.is_user = 1; save_registers(regs); if(WIFSTOPPED(status)){ switch(WSTOPSIG(status)){ case SIGSEGV: handle_segv(pid); break; case SIGTRAP: handle_trap(pid, regs); break; case SIGIO: case SIGVTALRM: case SIGILL: case SIGBUS: case SIGFPE: case SIGWINCH: user_signal(WSTOPSIG(status), regs); break; default: printk("userspace - child stopped with signal " "%d\n", WSTOPSIG(status)); } interrupt_end(); } restore_registers(regs); op = singlestepping_skas() ? PTRACE_SINGLESTEP : PTRACE_SYSCALL; err = ptrace(op, pid, 0, 0); if(err) panic("userspace - PTRACE_SYSCALL failed, " "errno = %d\n", errno); } }
void userspace(union uml_pt_regs *regs) { int err, status, op, pt_syscall_parm, pid = userspace_pid[0]; int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/ restore_registers(regs); local_using_sysemu = get_using_sysemu(); pt_syscall_parm = local_using_sysemu ? PTRACE_SYSEMU : PTRACE_SYSCALL; err = ptrace(pt_syscall_parm, pid, 0, 0); if(err) panic("userspace - PTRACE_%s failed, errno = %d\n", local_using_sysemu ? "SYSEMU" : "SYSCALL", errno); while(1){ CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); if(err < 0) panic("userspace - waitpid failed, errno = %d\n", errno); regs->skas.is_user = 1; save_registers(regs); if(WIFSTOPPED(status)){ switch(WSTOPSIG(status)){ case SIGSEGV: handle_segv(pid); break; case SIGTRAP: handle_trap(pid, regs, local_using_sysemu); break; case SIGIO: case SIGVTALRM: case SIGILL: case SIGBUS: case SIGFPE: case SIGWINCH: user_signal(WSTOPSIG(status), regs); break; default: printk("userspace - child stopped with signal " "%d\n", WSTOPSIG(status)); } interrupt_end(); } restore_registers(regs); /*Now we ended the syscall, so re-read local_using_sysemu.*/ local_using_sysemu = get_using_sysemu(); pt_syscall_parm = local_using_sysemu ? PTRACE_SYSEMU : PTRACE_SYSCALL; op = singlestepping(NULL) ? PTRACE_SINGLESTEP : pt_syscall_parm; err = ptrace(op, pid, 0, 0); if(err) panic("userspace - PTRACE_%s failed, " "errno = %d\n", local_using_sysemu ? "SYSEMU" : "SYSCALL", errno); } }
long syscall_emu(long call, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { long ret; switch (call) { case __NR_brk: case __NR_mmap2: case __NR_mmap: case __NR_mremap: case __NR_mprotect: case __NR_madvise: case __NR_sigaltstack: case __NR_signal: case __NR_sigaction: case __NR_sigreturn: case __NR_rt_sigaction: case __NR_rt_sigreturn: case __NR_fork: case __NR_vfork: case __NR_clone: case __NR_exit: case __NR_execve: case __NR_exit_group: break; case __NR_read: case __NR_readv: case __NR_open: case __NR_creat: case __NR_dup: case __NR_dup2: case __NR_openat: case __NR_pipe: case __NR_socketcall: ret = syscall_intr(call,arg1,arg2,arg3,arg4,arg5,arg6); if ( taint_flag == TAINT_ON ) do_taint(ret,call,arg1,arg2,arg3,arg4,arg5,arg6); return ret; case __NR_ipc: if ( arg1 == SHMAT ) break; /* fall through */ default: return syscall_intr(call,arg1,arg2,arg3,arg4,arg5,arg6); } ret = call; if (!try_block_signals()) return ret; /* we have a signal in progress, revert to pre-syscall state */ switch (call) { /* these calls are all non-blocking right? * blocked signals during blocking calls is a bad thing */ case __NR_brk: ret = user_brk(arg1); break; case __NR_mmap2: ret = user_mmap2(arg1,arg2,arg3,arg4,arg5,arg6); break; case __NR_mmap: ret = user_old_mmap((struct kernel_mmap_args *)arg1); break; case __NR_mremap: ret = user_mremap(arg1,arg2,arg3,arg4,arg5); break; case __NR_mprotect: ret = user_mprotect(arg1,arg2,arg3); break; case __NR_madvise: ret = user_madvise(arg1,arg2,arg3); break; case __NR_ipc: if (arg1 == SHMAT) ret = user_shmat(arg2,(char *)arg5,arg3,(unsigned long *)arg4); else die("should not have caught IPC call: %d", arg1); break; case __NR_sigaltstack: ret = user_sigaltstack((stack_t *)arg1, (stack_t *)arg2); break; case __NR_signal: { ret = (long)user_signal(arg1, (kernel_sighandler_t)arg2); break; } case __NR_sigaction: ret = user_sigaction(arg1, (struct kernel_old_sigaction *)arg2, (struct kernel_old_sigaction *)arg3); break; case __NR_rt_sigaction: ret = user_rt_sigaction(arg1, (struct kernel_sigaction *)arg2, (struct kernel_sigaction *)arg3, arg4); break; case __NR_sigreturn: user_sigreturn(); break; case __NR_rt_sigreturn: user_rt_sigreturn(); break; case __NR_vfork: ret = user_clone(SIGCHLD, 0, NULL, NULL, NULL); // ret = user_clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, NULL, NULL); break; case __NR_fork: ret = user_clone(SIGCHLD, 0, NULL, NULL, NULL); break; case __NR_clone: ret = user_clone(arg1, arg2, (void *)arg3, (void *)arg4, (void*)arg5); break; case __NR_exit: user_exit(arg1); break; case __NR_execve: ret = user_execve((char *)arg1, (char **)arg2, (char **)arg3); break; case __NR_exit_group: if (dump_on_exit) { long regs[] = { call, arg2, arg3, arg1, get_thread_ctx()->user_esp, arg6, arg4, arg5 }; do_taint_dump(regs); } sys_exit_group(arg1); default: die("unimplemented syscall"); break; } unblock_signals(); return ret; }