diff --git a/include/parasite-syscall.h b/include/parasite-syscall.h index 3babeb8f6..bb88fa8e9 100644 --- a/include/parasite-syscall.h +++ b/include/parasite-syscall.h @@ -10,8 +10,6 @@ struct parasite_thread_ctl pid_t tid; user_regs_struct_t regs_orig; /* original registers */ - bool daemonized; - k_rtsigset_t sig_blocked; bool use_sig_blocked; @@ -27,6 +25,8 @@ struct parasite_ctl { void *local_map; unsigned long map_length; + bool daemonized; + unsigned long parasite_ip; /* service routine start ip */ unsigned long syscall_ip; /* entry point of infection */ u8 code_orig[BUILTIN_SYSCALL_SIZE]; @@ -52,11 +52,10 @@ extern int parasite_dump_itimers_seized(struct parasite_ctl *ctl, struct cr_fdse void *parasite_args_s(struct parasite_ctl *ctl, int args_size); int parasite_execute_daemon(unsigned int cmd, struct parasite_ctl *ctl); int parasite_send_fd(struct parasite_ctl *ctl, int fd); -int __parasite_execute_daemon_by_id(unsigned int cmd, - struct parasite_ctl *ctl, - int id, bool wait_ack); +int __parasite_execute_daemon(unsigned int cmd, + struct parasite_ctl *ctl, bool wait_ack); int __parasite_execute_daemon_wait_ack(unsigned int cmd, - struct parasite_ctl *ctl, int id); + struct parasite_ctl *ctl); struct parasite_dump_misc; struct vm_area_list; diff --git a/include/parasite.h b/include/parasite.h index d26b1308c..8fae002b9 100644 --- a/include/parasite.h +++ b/include/parasite.h @@ -51,17 +51,16 @@ enum { }; struct ctl_msg { - unsigned int id; /* command recipient */ unsigned int cmd; /* command itself */ unsigned int ack; /* ack on command */ int err; /* error code on reply */ }; -#define ctl_msg_cmd(_id, _cmd) \ - (struct ctl_msg){ .id = _id, .cmd = _cmd, } +#define ctl_msg_cmd(_cmd) \ + (struct ctl_msg){.cmd = _cmd, } -#define ctl_msg_ack(_id, _cmd, _err) \ - (struct ctl_msg){ .id = _id, .cmd = _cmd, .ack = _cmd, .err = _err, } +#define ctl_msg_ack(_cmd, _err) \ + (struct ctl_msg){.cmd = _cmd, .ack = _cmd, .err = _err, } struct parasite_init_args { int id; diff --git a/mem.c b/mem.c index fd9bd8486..0b81dd0d4 100644 --- a/mem.c +++ b/mem.c @@ -373,14 +373,14 @@ static int __parasite_dump_pages_seized(struct parasite_ctl *ctl, pr_debug("PPB: %d pages %d segs %u pipe %d off\n", args->nr_pages, args->nr_segs, ppb->pipe_size, args->off); - ret = __parasite_execute_daemon_by_id(PARASITE_CMD_DUMPPAGES, ctl, 0, false); + ret = __parasite_execute_daemon(PARASITE_CMD_DUMPPAGES, ctl, false); if (ret < 0) goto out_pp; ret = parasite_send_fd(ctl, ppb->p[1]); if (ret) goto out_pp; - ret = __parasite_execute_daemon_wait_ack(PARASITE_CMD_DUMPPAGES, ctl, 0); + ret = __parasite_execute_daemon_wait_ack(PARASITE_CMD_DUMPPAGES, ctl); if (ret < 0) goto out_pp; diff --git a/parasite-syscall.c b/parasite-syscall.c index 63e8815f9..639739489 100644 --- a/parasite-syscall.c +++ b/parasite-syscall.c @@ -253,7 +253,7 @@ static int __parasite_send_cmd(int sockfd, struct ctl_msg *m) ret = send(sockfd, m, sizeof(*m), 0); if (ret == -1) { - pr_perror("Failed to send command %d to daemon %d\n", m->cmd, m->id); + pr_perror("Failed to send command %d to daemon\n", m->cmd); return -1; } else if (ret != sizeof(*m)) { pr_err("Message to daemon is trimmed (%d/%d)\n", @@ -261,32 +261,32 @@ static int __parasite_send_cmd(int sockfd, struct ctl_msg *m) return -1; } - pr_debug("Sent msg to daemon %d %d %d %d\n", m->id, m->cmd, m->ack, m->err); + pr_debug("Sent msg to daemon %d %d %d\n", m->cmd, m->ack, m->err); return 0; } -static int parasite_wait_ack(int sockfd, int id, unsigned int cmd, struct ctl_msg *m) +static int parasite_wait_ack(int sockfd, unsigned int cmd, struct ctl_msg *m) { int ret; - pr_debug("Wait for ack %d-%d on daemon socket\n", id, cmd); + pr_debug("Wait for ack %d on daemon socket\n", cmd); while (1) { memzero(m, sizeof(*m)); ret = recv(sockfd, m, sizeof(*m), MSG_WAITALL); if (ret == -1) { - pr_perror("Failed to read ack from %d", id); + pr_perror("Failed to read ack"); return -1; } else if (ret != sizeof(*m)) { pr_err("Message reply from daemon is trimmed (%d/%d)\n", (int)sizeof(*m), ret); return -1; } - pr_debug("Fetched ack: %d %d %d %d\n", - m->id, m->cmd, m->ack, m->err); + pr_debug("Fetched ack: %d %d %d\n", + m->cmd, m->ack, m->err); - if (m->id != id || m->cmd != cmd || m->ack != cmd) { + if (m->cmd != cmd || m->ack != cmd) { pr_err("Communication error, this is not " "the ack we expected\n"); return -1; @@ -298,46 +298,41 @@ static int parasite_wait_ack(int sockfd, int id, unsigned int cmd, struct ctl_ms } int __parasite_execute_daemon_wait_ack(unsigned int cmd, - struct parasite_ctl *ctl, int id) + struct parasite_ctl *ctl) { struct ctl_msg m; - if (parasite_wait_ack(ctl->tsock, id, cmd, &m)) + if (parasite_wait_ack(ctl->tsock, cmd, &m)) return -1; if (m.err != 0) { - pr_err("Command %d for daemon %d failed with %d\n", - cmd, id, m.err); + pr_err("Command %d for daemon failed with %d\n", + cmd, m.err); return -1; } return 0; } -int __parasite_execute_daemon_by_id(unsigned int cmd, - struct parasite_ctl *ctl, int id, bool wait_ack) +int __parasite_execute_daemon(unsigned int cmd, + struct parasite_ctl *ctl, bool wait_ack) { struct ctl_msg m; - m = ctl_msg_cmd(id, cmd); + m = ctl_msg_cmd(cmd); if (__parasite_send_cmd(ctl->tsock, &m)) return -1; if (wait_ack) - return __parasite_execute_daemon_wait_ack(cmd, ctl, id); + return __parasite_execute_daemon_wait_ack(cmd, ctl); return 0; } -static int parasite_execute_daemon_by_id(unsigned int cmd, - struct parasite_ctl *ctl, int id) +int parasite_execute_daemon(unsigned int cmd, + struct parasite_ctl *ctl) { - return __parasite_execute_daemon_by_id(cmd, ctl, id, true); -} - -int parasite_execute_daemon(unsigned int cmd, struct parasite_ctl *ctl) -{ - return parasite_execute_daemon_by_id(cmd, ctl, 0); + return __parasite_execute_daemon(cmd, ctl, true); } static int munmap_seized(struct parasite_ctl *ctl, void *addr, size_t length) @@ -493,13 +488,13 @@ static int parasite_daemonize(struct parasite_ctl *ctl, int id) pr_info("Wait for parasite being daemonized...\n"); - if (parasite_wait_ack(ctl->tsock, id, PARASITE_CMD_DAEMONIZE, &m)) { + if (parasite_wait_ack(ctl->tsock, PARASITE_CMD_DAEMONIZE, &m)) { pr_err("Can't switch parasite %d to daemon mode %d\n", pid, m.err); goto err; } - thread->daemonized = true; + ctl->daemonized = true; pr_info("Parasite %d has been switched to daemon mode\n", pid); return 0; @@ -684,8 +679,7 @@ int parasite_drain_fds_seized(struct parasite_ctl *ctl, args = parasite_args_s(ctl, size); memcpy(args, dfds, size); - ret = __parasite_execute_daemon_by_id(PARASITE_CMD_DRAIN_FDS, ctl, - 0, false); + ret = __parasite_execute_daemon(PARASITE_CMD_DRAIN_FDS, ctl, false); if (ret) { pr_err("Parasite failed to drain descriptors\n"); goto err; @@ -695,7 +689,7 @@ int parasite_drain_fds_seized(struct parasite_ctl *ctl, if (ret) pr_err("Can't retrieve FDs from socket\n"); - ret |= __parasite_execute_daemon_wait_ack(PARASITE_CMD_DRAIN_FDS, ctl, 0); + ret |= __parasite_execute_daemon_wait_ack(PARASITE_CMD_DRAIN_FDS, ctl); err: return ret; } @@ -823,8 +817,7 @@ int parasite_get_proc_fd_seized(struct parasite_ctl *ctl) { int ret = -1, fd; - ret = __parasite_execute_daemon_by_id(PARASITE_CMD_GET_PROC_FD, ctl, - 0, false); + ret = __parasite_execute_daemon(PARASITE_CMD_GET_PROC_FD, ctl, false); if (ret) { pr_err("Parasite failed to get proc fd\n"); return ret; @@ -833,7 +826,7 @@ int parasite_get_proc_fd_seized(struct parasite_ctl *ctl) fd = recv_fd(ctl->tsock); if (fd < 0) pr_err("Can't retrieve FD from socket\n"); - if (__parasite_execute_daemon_wait_ack(PARASITE_CMD_GET_PROC_FD, ctl, 0)) { + if (__parasite_execute_daemon_wait_ack(PARASITE_CMD_GET_PROC_FD, ctl)) { close(fd); return -1; } @@ -890,39 +883,34 @@ err: static int parasite_fini_seized(struct parasite_ctl *ctl) { - int status, ret = 0, i, nr = 0, nr_dmnz = 0; + pid_t pid = ctl->pid.real; + int status, ret = 0;; + + if (!ctl->daemonized) + return 0; /* Start to trace syscalls for each thread */ - for (i = 0; i < ctl->nr_threads; i++) { - pid_t pid = ctl->threads[i].tid; + ptrace(PTRACE_INTERRUPT, pid, NULL, NULL); - if (!ctl->threads[i].daemonized) - break; - - ptrace(PTRACE_INTERRUPT, pid, NULL, NULL); - - pr_debug("Waiting for %d to trap\n", pid); - if (wait4(pid, &status, __WALL, NULL) != pid) { - pr_perror("Waited pid mismatch (pid: %d)", pid); - return -1; - } - - pr_debug("Daemon %d exited trapping\n", pid); - if (!WIFSTOPPED(status)) { - pr_err("Task is still running (pid: %d)\n", pid); - return -1; - } - - ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL); - if (ret) { - pr_perror("ptrace"); - return -1; - } - - nr_dmnz++; + pr_debug("Waiting for %d to trap\n", pid); + if (wait4(pid, &status, __WALL, NULL) != pid) { + pr_perror("Waited pid mismatch (pid: %d)", pid); + return -1; } - ret = __parasite_execute_daemon_by_id(PARASITE_CMD_FINI, ctl, 0, false); + pr_debug("Daemon %d exited trapping\n", pid); + if (!WIFSTOPPED(status)) { + pr_err("Task is still running (pid: %d)\n", pid); + return -1; + } + + ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL); + if (ret) { + pr_perror("ptrace"); + return -1; + } + + ret = __parasite_execute_daemon(PARASITE_CMD_FINI, ctl, false); if (ret) return -1; @@ -950,11 +938,8 @@ static int parasite_fini_seized(struct parasite_ctl *ctl) pr_debug("%d is going to execute the syscall %lx\n", pid, regs.orig_ax); if (regs.orig_ax == __NR_rt_sigreturn) { - nr++; pr_debug("%d was stopped\n", pid); - if (nr == nr_dmnz) - break; - continue; + break; } ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL); @@ -964,31 +949,23 @@ static int parasite_fini_seized(struct parasite_ctl *ctl) } } - /* Stop all threads on the exit point from sys_rt_sigreturn */ - for (i = 0; i < ctl->nr_threads; i++) { - pid_t pid = ctl->threads[i].tid; + ctl->threads[0].use_sig_blocked = false; - if (!ctl->threads[i].daemonized) - break; + ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL); + if (ret) { + pr_perror("ptrace"); + return -1; + } - ctl->threads[i].use_sig_blocked = false; + if (wait4(pid, &status, __WALL, NULL) != pid) { + pr_perror("wait4 failed"); + return -1; + } - ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL); - if (ret) { - pr_perror("ptrace"); - return -1; - } - - if (wait4(pid, &status, __WALL, NULL) != pid) { - pr_perror("wait4 failed"); - return -1; - } - - pr_debug("Trap %d\n", pid); - if (!WIFSTOPPED(status)) { - pr_err("%d\n", status); - return -1; - } + pr_debug("Trap %d\n", pid); + if (!WIFSTOPPED(status)) { + pr_err("%d\n", status); + return -1; } return ret; diff --git a/pie/parasite.c b/pie/parasite.c index 3dc8e7300..e6ee8a2f6 100644 --- a/pie/parasite.c +++ b/pie/parasite.c @@ -20,22 +20,7 @@ static int tsock = -1; -static struct tid_state_s { - int id; - - futex_t cmd; - int ret; - - struct rt_sigframe *sigframe; -} *tid_state; - -static unsigned int nr_tid_state; -static unsigned int next_tid_state; - -#define TID_STATE_SIZE(n) \ - (ALIGN(sizeof(struct tid_state_s) * n, PAGE_SIZE)) - -#define thread_leader (&tid_state[0]) +static struct rt_sigframe *sigframe; #ifndef SPLICE_F_GIFT #define SPLICE_F_GIFT 0x08 @@ -197,12 +182,6 @@ static int init_daemon_thread(struct parasite_init_args *args) k_rtsigset_t to_block; int ret; - if (args->id != next_tid_state) - return -EINVAL; - - if (next_tid_state >= nr_tid_state) - return -ENOMEM; - ksigfillset(&to_block); ret = sys_sigprocmask(SIG_SETMASK, &to_block, &args->sig_blocked, @@ -210,12 +189,7 @@ static int init_daemon_thread(struct parasite_init_args *args) if (ret) return -1; - tid_state[next_tid_state].id = next_tid_state; - tid_state[next_tid_state].sigframe = args->sigframe; - - futex_set(&tid_state[next_tid_state].cmd, PARASITE_CMD_IDLE); - - next_tid_state++; + sigframe = args->sigframe; return ret; } @@ -254,45 +228,10 @@ static int fini_thread(struct parasite_dump_thread *args) NULL, sizeof(k_rtsigset_t)); } -static void __parasite_daemon_thread_ack(struct tid_state_s *s, int ret) -{ - s->ret = ret; - futex_set_and_wake(&s->cmd, PARASITE_CMD_IDLE); -} - -static int fini_daemon_thread(struct tid_state_s *s) -{ - unsigned long new_sp; - - new_sp = (long)s->sigframe + SIGFRAME_OFFSET; - pr_debug("%ld: new_sp=%lx ip %lx\n", sys_gettid(), - new_sp, s->sigframe->uc.uc_mcontext.rip); - - __parasite_daemon_thread_ack(s, 0); - - ARCH_RT_SIGRETURN(new_sp); - - BUG(); - - return 0; -} - static int init(struct parasite_init_args *args) { int ret; - if (!args->nr_threads) - return -EINVAL; - - tid_state = (void *)sys_mmap(NULL, TID_STATE_SIZE(args->nr_threads), - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, - -1, 0); - if ((unsigned long)tid_state > TASK_SIZE) - return -ENOMEM; - - nr_tid_state = args->nr_threads; - ret = init_daemon_thread(args); if (ret < 0) return ret; @@ -459,12 +398,12 @@ static int parasite_check_vdso_mark(struct parasite_vdso_vma_entry *args) return 0; } -static int __parasite_daemon_reply_ack(unsigned int id, unsigned int cmd, int err) +static int __parasite_daemon_reply_ack(unsigned int cmd, int err) { struct ctl_msg m; int ret; - m = ctl_msg_ack(id, cmd, err); + m = ctl_msg_ack(cmd, err); ret = sys_sendto(tsock, &m, sizeof(m), 0, NULL, 0); if (ret != sizeof(m)) { pr_err("Sent only %d bytes while %d expected\n", @@ -472,8 +411,8 @@ static int __parasite_daemon_reply_ack(unsigned int id, unsigned int cmd, int er return -1; } - pr_debug("__sent ack msg: %d %d %d %d\n", - m.id, m.cmd, m.ack, m.err); + pr_debug("__sent ack msg: %d %d %d\n", + m.cmd, m.ack, m.err); return 0; } @@ -493,88 +432,25 @@ static int __parasite_daemon_wait_msg(struct ctl_msg *m) return 0; } - pr_debug("__fetched msg: %d %d %d %d\n", - m->id, m->cmd, m->ack, m->err); + pr_debug("__fetched msg: %d %d %d\n", + m->cmd, m->ack, m->err); return 0; } return -1; } -static int __parasite_daemon_thread_wait_cmd(struct tid_state_s *s) -{ - futex_wait_while_eq(&s->cmd, PARASITE_CMD_IDLE); - return futex_get(&s->cmd); -} - -static void noinline __used -__parasite_daemon_thread(void *args, struct tid_state_s *s) -{ - pr_debug("Running daemon thread %d\n", s->id); - - /* Reply we're alive */ - if (__parasite_daemon_reply_ack(s->id, PARASITE_CMD_DAEMONIZE, 0)) - return; - - while (1) { - int ret, cmd; - - cmd = __parasite_daemon_thread_wait_cmd(s); - - pr_debug("Command %d in daemon thread %d\n", cmd, s->id); - - switch (cmd) { - case PARASITE_CMD_DUMP_THREAD: - ret = dump_thread(args); - break; - case PARASITE_CMD_FINI_THREAD: - fini_daemon_thread(s); - return; - default: - pr_err("Unknown command in parasite daemon thread: %d\n", cmd); - ret = -1; - break; - } - __parasite_daemon_thread_ack(s, ret); - } - - pr_err("The thread %d trys to escape!!!", s->id); - BUG(); - return; -} - -static int __parasite_execute_thread(struct ctl_msg *m) -{ - struct tid_state_s *s = &tid_state[m->id]; - - pr_debug("Wake thread %d daemon with command %d\n", s->id, m->cmd); - futex_set_and_wake(&s->cmd, m->cmd); - - pr_debug("Wait thread %d for PARASITE_CMD_IDLE\n", s->id); - futex_wait_until(&s->cmd, PARASITE_CMD_IDLE); - - return s->ret; -} - -static int fini(struct tid_state_s *s) +static int fini() { unsigned long new_sp; - int i; - for (i = 1; i < next_tid_state; i++) { - struct ctl_msg m = {.cmd = PARASITE_CMD_FINI_THREAD, .id = i}; - __parasite_execute_thread(&m); - } - - new_sp = (long)s->sigframe + SIGFRAME_OFFSET; + new_sp = (long)sigframe + SIGFRAME_OFFSET; pr_debug("%ld: new_sp=%lx ip %lx\n", sys_gettid(), - new_sp, s->sigframe->uc.uc_mcontext.rip); + new_sp, sigframe->uc.uc_mcontext.rip); sys_close(tsock); log_set_fd(-1); - sys_munmap(tid_state, TID_STATE_SIZE(nr_tid_state)); - ARCH_RT_SIGRETURN(new_sp); BUG(); @@ -582,8 +458,7 @@ static int fini(struct tid_state_s *s) return -1; } -static void noinline __used -__parasite_daemon_thread_leader(void *args, struct tid_state_s *s) +static noinline __used int noinline parasite_daemon(void *args) { struct ctl_msg m = { }; int ret = -1; @@ -591,7 +466,7 @@ __parasite_daemon_thread_leader(void *args, struct tid_state_s *s) pr_debug("Running daemon thread leader\n"); /* Reply we're alive */ - if (__parasite_daemon_reply_ack(0, PARASITE_CMD_DAEMONIZE, 0)) + if (__parasite_daemon_reply_ack(PARASITE_CMD_DAEMONIZE, 0)) goto out; while (1) { @@ -600,17 +475,14 @@ __parasite_daemon_thread_leader(void *args, struct tid_state_s *s) switch (m.cmd) { case PARASITE_CMD_FINI: - ret = fini(s); + ret = fini(); sys_close(tsock); /* * No ACK here since we're getting out. */ break; - case PARASITE_CMD_FINI_THREAD: - ret = __parasite_execute_thread(&m); - break; case PARASITE_CMD_DUMP_THREAD: - ret = __parasite_execute_thread(&m); + ret = dump_thread(args); break; case PARASITE_CMD_DUMPPAGES: ret = dump_pages(args); @@ -648,31 +520,12 @@ __parasite_daemon_thread_leader(void *args, struct tid_state_s *s) break; } - if (__parasite_daemon_reply_ack(m.id, m.cmd, ret)) + if (__parasite_daemon_reply_ack(m.cmd, ret)) break; } out: - fini(&tid_state[0]); - - return; -} - -static int noinline parasite_daemon(struct parasite_init_args *args) -{ - struct tid_state_s *s; - bool is_leader = (args->id == 0); - - s = &tid_state[args->id]; - - pr_info("Parasite entering daemon mode for %d\n", s->id); - - if (is_leader) - __parasite_daemon_thread_leader(args, s); - else - __parasite_daemon_thread(args, s); - - pr_info("Parasite leaving daemon mode for %d\n", s->id); + fini(); return 0; }