int start_fork_tramp(void *thread_arg, unsigned long temp_stack, int clone_flags, int (*tramp)(void *)) { struct tramp arg; unsigned long sp; int new_pid, status, err; /* The trampoline will run on the temporary stack */ sp = stack_sp(temp_stack); clone_flags |= CLONE_FILES | SIGCHLD; arg.tramp = tramp; arg.tramp_data = thread_arg; arg.temp_stack = temp_stack; arg.flags = clone_flags; /* Start the process and wait for it to kill itself */ new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg); if(new_pid < 0) return(new_pid); CATCH_EINTR(err = waitpid(new_pid, &status, 0)); if(err < 0) panic("Waiting for outer trampoline failed - errno = %d", errno); if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL)) panic("outer trampoline didn't exit with SIGKILL, " "status = %d", status); return(arg.pid); }
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 os_kill_process(int pid, int reap_child) { kill(pid, SIGKILL); if(reap_child) CATCH_EINTR(waitpid(pid, NULL, 0)); }
static void slirp_close(int fd, void *data) { struct slirp_data *pri = data; int status,err; os_close_file(fd); os_close_file(pri->slave); pri->slave = -1; if(pri->pid<1) { printk("slirp_close: no child process to shut down\n"); return; } #if 0 if(kill(pri->pid, SIGHUP)<0) { printk("slirp_close: sending hangup to %d failed (%d)\n", pri->pid, errno); } #endif CATCH_EINTR(err = waitpid(pri->pid, &status, WNOHANG)); if(err < 0) { printk("slirp_close: waitpid returned %d\n", errno); return; } if(err == 0) { printk("slirp_close: process %d has not exited\n", pri->pid); return; } pri->pid = -1; }
unsigned long os_process_pc(int pid) { char proc_stat[STAT_PATH_LEN], buf[256]; unsigned long pc = ARBITRARY_ADDR; int fd, err; sprintf(proc_stat, "/proc/%d/stat", pid); fd = open(proc_stat, O_RDONLY, 0); if (fd < 0) { printk(UM_KERN_ERR "os_process_pc - couldn't open '%s', " "errno = %d\n", proc_stat, errno); goto out; } CATCH_EINTR(err = read(fd, buf, sizeof(buf))); if (err < 0) { printk(UM_KERN_ERR "os_process_pc - couldn't read '%s', " "err = %d\n", proc_stat, errno); goto out_close; } os_close_file(fd); pc = ARBITRARY_ADDR; if (sscanf(buf, "%*d " COMM_SCANF " %*c %*d %*d %*d %*d %*d %*d %*d " "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " "%*d %*d %*d %*d %*d %lu", &pc) != 1) printk(UM_KERN_ERR "os_process_pc - couldn't find pc in '%s'\n", buf); out_close: close(fd); out: return pc; }
int os_process_parent(int pid) { char stat[STAT_PATH_LEN]; char data[256]; int parent, n, fd; if(pid == -1) return -1; snprintf(stat, sizeof(stat), "/proc/%d/stat", pid); fd = os_open_file(stat, of_read(OPENFLAGS()), 0); if(fd < 0){ printk("Couldn't open '%s', err = %d\n", stat, -fd); return FAILURE_PID; } CATCH_EINTR(n = read(fd, data, sizeof(data))); os_close_file(fd); if(n < 0){ printk("Couldn't read '%s', err = %d\n", stat, errno); return FAILURE_PID; } parent = FAILURE_PID; n = sscanf(data, "%*d " COMM_SCANF " %*c %d", &parent); if(n != 1) printk("Failed to scan '%s'\n", data); return parent; }
unsigned long os_process_pc(int pid) { char proc_stat[STAT_PATH_LEN], buf[256]; unsigned long pc; int fd, err; sprintf(proc_stat, "/proc/%d/stat", pid); fd = os_open_file(proc_stat, of_read(OPENFLAGS()), 0); if(fd < 0){ printk("os_process_pc - couldn't open '%s', err = %d\n", proc_stat, -fd); return ARBITRARY_ADDR; } CATCH_EINTR(err = read(fd, buf, sizeof(buf))); if(err < 0){ printk("os_process_pc - couldn't read '%s', err = %d\n", proc_stat, errno); os_close_file(fd); return ARBITRARY_ADDR; } os_close_file(fd); pc = ARBITRARY_ADDR; if(sscanf(buf, "%*d " COMM_SCANF " %*c %*d %*d %*d %*d %*d %*d %*d " "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " "%*d %*d %*d %*d %*d %lu", &pc) != 1){ printk("os_process_pc - couldn't find pc in '%s'\n", buf); } return pc; }
int os_process_parent(int pid) { char stat[STAT_PATH_LEN]; char data[256]; int parent = FAILURE_PID, n, fd; if (pid == -1) return parent; snprintf(stat, sizeof(stat), "/proc/%d/stat", pid); fd = open(stat, O_RDONLY, 0); if (fd < 0) { printk(UM_KERN_ERR "Couldn't open '%s', errno = %d\n", stat, errno); return parent; } CATCH_EINTR(n = read(fd, data, sizeof(data))); close(fd); if (n < 0) { printk(UM_KERN_ERR "Couldn't read '%s', errno = %d\n", stat, errno); return parent; } parent = FAILURE_PID; n = sscanf(data, "%*d " COMM_SCANF " %*c %d", &parent); if (n != 1) printk(UM_KERN_ERR "Failed to scan '%s'\n", data); return parent; }
int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, unsigned long *stack_out, int stack_order) { unsigned long stack, sp; int pid, status; stack = alloc_stack(stack_order, um_in_interrupt()); if(stack == 0) return(-ENOMEM); sp = stack + (page_size() << stack_order) - sizeof(void *); pid = clone(proc, (void *) sp, flags | SIGCHLD, arg); if(pid < 0){ printk("run_helper_thread : clone failed, errno = %d\n", errno); return(-errno); } if(stack_out == NULL){ CATCH_EINTR(pid = waitpid(pid, &status, 0)); if(pid < 0){ printk("run_helper_thread - wait failed, errno = %d\n", errno); pid = -errno; } if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) printk("run_helper_thread - thread returned status " "0x%x\n", status); free_stack(stack, stack_order); } else *stack_out = stack; return(pid); }
void start_userspace(int cpu) { void *stack; unsigned long sp; int pid, status, n; stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if(stack == MAP_FAILED) panic("start_userspace : mmap failed, errno = %d", errno); sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); pid = clone(userspace_tramp, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD, NULL); if(pid < 0) panic("start_userspace : clone failed, errno = %d", errno); do { CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0) panic("start_userspace : wait failed, errno = %d", errno); } while(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM)); if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) panic("start_userspace : expected SIGSTOP, got status = %d", status); if(munmap(stack, PAGE_SIZE) < 0) panic("start_userspace : munmap failed, errno = %d\n", errno); userspace_pid[cpu] = pid; }
int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, unsigned long *stack_out) { unsigned long stack, sp; int pid, status, err; stack = alloc_stack(0, __cant_sleep()); if (stack == 0) return -ENOMEM; sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *); pid = clone(proc, (void *) sp, flags, arg); if (pid < 0) { err = -errno; printk(UM_KERN_ERR "run_helper_thread : clone failed, " "errno = %d\n", errno); return err; } if (stack_out == NULL) { CATCH_EINTR(pid = waitpid(pid, &status, __WCLONE)); if (pid < 0) { err = -errno; printk(UM_KERN_ERR "run_helper_thread - wait failed, " "errno = %d\n", errno); pid = err; } if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) printk(UM_KERN_ERR "run_helper_thread - thread " "returned status 0x%x\n", status); free_stack(stack, 0); } else *stack_out = stack; return pid; }
/* When testing for SYSEMU support, if it is one of the broken versions, we must * just avoid using sysemu, not panic, but only if SYSEMU features are broken. * So only for SYSEMU features we test mustpanic, while normal host features * must work anyway!*/ static int stop_ptraced_child(int pid, void *stack, int exitcode, int mustpanic) { int status, n, ret = 0; if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) panic("check_ptrace : ptrace failed, errno = %d", errno); CATCH_EINTR(n = waitpid(pid, &status, 0)); if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) { int exit_with = WEXITSTATUS(status); if (exit_with == 2) printk("check_ptrace : child exited with status 2. " "Serious trouble happening! Try updating your " "host skas patch!\nDisabling SYSEMU support."); printk("check_ptrace : child exited with exitcode %d, while " "expecting %d; status 0x%x", exit_with, exitcode, status); if (mustpanic) panic("\n"); else printk("\n"); ret = -1; } if(munmap(stack, PAGE_SIZE) < 0) panic("check_ptrace : munmap failed, errno = %d", errno); return ret; }
void do_exec(int old_pid, int new_pid) { unsigned long regs[FRAME_SIZE]; int err; if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) || (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0)) tracer_panic("do_exec failed to attach proc - errno = %d", errno); CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED)); if (err < 0) tracer_panic("do_exec failed to attach proc in waitpid - errno = %d", errno); if(ptrace_getregs(old_pid, regs) < 0) tracer_panic("do_exec failed to get registers - errno = %d", errno); kill(old_pid, SIGKILL); if(ptrace_setregs(new_pid, regs) < 0) tracer_panic("do_exec failed to start new proc - errno = %d", errno); }
static void etap_change(int op, unsigned char *addr, unsigned char *netmask, int fd) { struct addr_change change; char *output; int n; change.what = op; memcpy(change.addr, addr, sizeof(change.addr)); memcpy(change.netmask, netmask, sizeof(change.netmask)); CATCH_EINTR(n = write(fd, &change, sizeof(change))); if (n != sizeof(change)) { printk(UM_KERN_ERR "etap_change - request failed, err = %d\n", errno); return; } output = uml_kmalloc(UM_KERN_PAGE_SIZE, UM_GFP_KERNEL); if (output == NULL) printk(UM_KERN_ERR "etap_change : Failed to allocate output " "buffer\n"); read_output(fd, output, UM_KERN_PAGE_SIZE); if (output != NULL) { printk("%s", output); kfree(output); } }
void __init check_ptrace(void) { void *stack; int pid, syscall, n, status; printk("Checking that ptrace can change system call numbers..."); pid = start_ptraced_child(&stack); while(1){ if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) panic("check_ptrace : ptrace failed, errno = %d", errno); CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0) panic("check_ptrace : wait failed, errno = %d", errno); if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) panic("check_ptrace : expected SIGTRAP, " "got status = %d", status); syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET, 0); if(syscall == __NR_getpid){ n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getppid); if(n < 0) panic("check_ptrace : failed to modify system " "call, errno = %d", errno); break; } } stop_ptraced_child(pid, stack, 0, 1); printk("OK\n"); check_sysemu(); }
/*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); }
void do_exec(int old_pid, int new_pid) { unsigned long regs[FRAME_SIZE]; int err; if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) || (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0)) tracer_panic("do_exec failed to attach proc - errno = %d", errno); CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED)); if (err < 0) tracer_panic("do_exec failed to attach proc in waitpid - errno = %d", errno); if(ptrace_getregs(old_pid, regs) < 0) tracer_panic("do_exec failed to get registers - errno = %d", errno); os_kill_ptraced_process(old_pid, 0); if (ptrace(PTRACE_OLDSETOPTIONS, new_pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) tracer_panic("do_exec: PTRACE_SETOPTIONS failed, errno = %d", errno); if(ptrace_setregs(new_pid, regs) < 0) tracer_panic("do_exec failed to start new proc - errno = %d", errno); }
void os_kill_ptraced_process(int pid, int reap_child) { kill(pid, SIGKILL); ptrace(PTRACE_KILL, pid); ptrace(PTRACE_CONT, pid); if (reap_child) CATCH_EINTR(waitpid(pid, NULL, __WALL)); }
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; } } }
int raw(int fd) { struct termios tt; int err; CATCH_EINTR(err = tcgetattr(fd, &tt)); if(err < 0) return -errno; cfmakeraw(&tt); CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt)); if(err < 0) return -errno; /* XXX tcsetattr could have applied only some changes * (and cfmakeraw() is a set of changes) */ return 0; }
static int slip_tramp(char **argv, int fd) { struct slip_pre_exec_data pe_data; char *output; int status, pid, fds[2], err, output_len; err = os_pipe(fds, 1, 0); if(err < 0){ printk("slip_tramp : pipe failed, err = %d\n", -err); goto out; } err = 0; pe_data.stdin = fd; pe_data.stdout = fds[1]; pe_data.close_me = fds[0]; err = run_helper(slip_pre_exec, &pe_data, argv, NULL); if(err < 0) goto out_close; pid = err; output_len = page_size(); output = um_kmalloc(output_len); if(output == NULL){ printk("slip_tramp : failed to allocate output buffer\n"); os_kill_process(pid, 1); err = -ENOMEM; goto out_free; } os_close_file(fds[1]); read_output(fds[0], output, output_len); printk("%s", output); CATCH_EINTR(err = waitpid(pid, &status, 0)); if(err < 0) err = errno; else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){ printk("'%s' didn't exit with status 0\n", argv[0]); err = -EINVAL; } else err = 0; os_close_file(fds[0]); out_free: kfree(output); return err; out_close: os_close_file(fds[0]); os_close_file(fds[1]); out: return err; }
int helper_wait(int pid, int block) { int ret; CATCH_EINTR(ret = waitpid(pid, NULL, WNOHANG)); if(ret < 0){ printk("helper_wait : waitpid failed, errno = %d\n", errno); return(-errno); } return(ret); }
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 kill_child_dead(int pid) { kill(pid, SIGKILL); kill(pid, SIGCONT); do { int n; CATCH_EINTR(n = waitpid(pid, NULL, 0)); if (n > 0) kill(pid, SIGCONT); else break; } while(1); }
int net_recvfrom(int fd, void *buf, int len) { int n; CATCH_EINTR(n = recvfrom(fd, buf, len, 0, NULL, NULL)); if (n < 0) { if (errno == EAGAIN) return 0; return -errno; } else if (n == 0) return -ENOTCONN; return n; }
int net_send(int fd, void *buf, int len) { int n; CATCH_EINTR(n = send(fd, buf, len, 0)); if (n < 0) { if (errno == EAGAIN) return 0; return -errno; } else if (n == 0) return -ENOTCONN; return n; }
static int helper_child(void *arg) { struct helper_data *data = arg; char **argv = data->argv; int err, ret; if (data->pre_exec != NULL) (*data->pre_exec)(data->pre_data); err = execvp_noalloc(data->buf, argv[0], argv); /* If the exec succeeds, we don't get here */ CATCH_EINTR(ret = write(data->fd, &err, sizeof(err))); return 0; }
int net_sendto(int fd, void *buf, int len, void *to, int sock_len) { int n; CATCH_EINTR(n = sendto(fd, buf, len, 0, (struct sockaddr *) to, sock_len)); if (n < 0) { if (errno == EAGAIN) return 0; return -errno; } else if (n == 0) return -ENOTCONN; return n; }
static int etap_tramp(char *dev, char *gate, int control_me, int control_remote, int data_me, int data_remote) { struct etap_pre_exec_data pe_data; int pid, status, err, n; char version_buf[sizeof("nnnnn\0")]; char data_fd_buf[sizeof("nnnnnn\0")]; char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; char *setup_args[] = { "uml_net", version_buf, "ethertap", dev, data_fd_buf, gate_buf, NULL }; char *nosetup_args[] = { "uml_net", version_buf, "ethertap", dev, data_fd_buf, NULL }; char **args, c; sprintf(data_fd_buf, "%d", data_remote); sprintf(version_buf, "%d", UML_NET_VERSION); if(gate != NULL){ strcpy(gate_buf, gate); args = setup_args; } else args = nosetup_args; err = 0; pe_data.control_remote = control_remote; pe_data.control_me = control_me; pe_data.data_me = data_me; pid = run_helper(etap_pre_exec, &pe_data, args, NULL); if(pid < 0) err = pid; os_close_file(data_remote); os_close_file(control_remote); n = os_read_file(control_me, &c, sizeof(c)); if(n != sizeof(c)){ printk("etap_tramp : read of status failed, err = %d\n", -n); return(-EINVAL); } if(c != 1){ printk("etap_tramp : uml_net failed\n"); err = -EINVAL; CATCH_EINTR(n = waitpid(pid, &status, 0)); if(n < 0) err = -errno; else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)) printk("uml_net didn't exit with status 1\n"); } return(err); }
int helper_wait(int pid) { int ret, status; int wflags = __WCLONE; CATCH_EINTR(ret = waitpid(pid, &status, wflags)); if (ret < 0) { printk(UM_KERN_ERR "helper_wait : waitpid process %d failed, " "errno = %d\n", pid, errno); return -errno; } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { printk(UM_KERN_ERR "helper_wait : process %d exited with " "status 0x%x\n", pid, status); return -ECHILD; } else return 0; }