void handle_syscall(struct uml_pt_regs *r) { struct pt_regs *regs = container_of(r, struct pt_regs, regs); int syscall; /* Initialize the syscall number and default return value. */ UPT_SYSCALL_NR(r) = PT_SYSCALL_NR(r->gp); PT_REGS_SET_SYSCALL_RETURN(regs, -ENOSYS); if (syscall_trace_enter(regs)) return; /* Do the seccomp check after ptrace; failures should be fast. */ if (secure_computing(NULL) == -1) return; /* Update the syscall number after orig_ax has potentially been updated * with ptrace. */ UPT_SYSCALL_NR(r) = PT_SYSCALL_NR(r->gp); syscall = UPT_SYSCALL_NR(r); if (syscall >= 0 && syscall <= __NR_syscall_max) PT_REGS_SET_SYSCALL_RETURN(regs, EXECUTE_SYSCALL(syscall, regs)); syscall_trace_leave(regs); }
/*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu) { int err, status; /* Mark this as a syscall */ UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->skas.regs); if (!local_using_sysemu) { err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid); if(err < 0) panic("handle_trap - nullifying syscall failed errno = %d\n", errno); err = ptrace(PTRACE_SYSCALL, pid, 0, 0); if(err < 0) panic("handle_trap - continuing to end of syscall failed, " "errno = %d\n", errno); CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP + 0x80)) panic("handle_trap - failed to wait at end of syscall, " "errno = %d, status = %d\n", errno, status); } handle_syscall(regs); }
static void handle_trap(int pid, union uml_pt_regs *regs) { int err, syscall_nr, status; syscall_nr = PT_SYSCALL_NR(regs->skas.regs); UPT_SYSCALL_NR(regs) = syscall_nr; if(syscall_nr < 1){ relay_signal(SIGTRAP, regs); return; } err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid); if(err < 0) panic("handle_trap - nullifying syscall failed errno = %d\n", errno); err = ptrace(PTRACE_SYSCALL, pid, 0, 0); if(err < 0) panic("handle_trap - continuing to end of syscall failed, " "errno = %d\n", errno); CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) panic("handle_trap - failed to wait at end of syscall, " "errno = %d, status = %d\n", errno, status); handle_syscall(regs); }
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; } } }
static void __init check_sysemu(void) { unsigned long regs[MAX_REG_NR]; int pid, n, status, count=0; non_fatal("Checking syscall emulation patch for ptrace..."); sysemu_supported = 0; pid = start_ptraced_child(); if (ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0) goto fail; CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if (n < 0) fatal_perror("check_sysemu : wait failed"); if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) fatal("check_sysemu : expected SIGTRAP, got status = %d\n", status); if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) fatal_perror("check_sysemu : PTRACE_GETREGS failed"); if (PT_SYSCALL_NR(regs) != __NR_getpid) { non_fatal("check_sysemu got system call number %d, " "expected %d...", PT_SYSCALL_NR(regs), __NR_getpid); goto fail; } n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid()); if (n < 0) { non_fatal("check_sysemu : failed to modify system call " "return"); goto fail; } if (stop_ptraced_child(pid, 0, 0) < 0) goto fail_stopped; sysemu_supported = 1; non_fatal("OK\n"); set_using_sysemu(!force_sysemu_disabled); non_fatal("Checking advanced syscall emulation patch for ptrace..."); pid = start_ptraced_child(); if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *) PTRACE_O_TRACESYSGOOD) < 0)) fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed"); while (1) { count++; if (ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0) goto fail; CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if (n < 0) fatal_perror("check_sysemu: wait failed"); if (WIFSTOPPED(status) && (WSTOPSIG(status) == (SIGTRAP|0x80))) { if (!count) { non_fatal("check_sysemu: SYSEMU_SINGLESTEP " "doesn't singlestep"); goto fail; } n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid()); if (n < 0) fatal_perror("check_sysemu : failed to modify " "system call return"); break; } else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) count++; else { non_fatal("check_sysemu: expected SIGTRAP or " "(SIGTRAP | 0x80), got status = %d\n", status); goto fail; } } if (stop_ptraced_child(pid, 0, 0) < 0) goto fail_stopped; sysemu_supported = 2; non_fatal("OK\n"); if (!force_sysemu_disabled) set_using_sysemu(sysemu_supported); return; fail: stop_ptraced_child(pid, 1, 0); fail_stopped: non_fatal("missing\n"); }