2011-09-23 12:00:45 +04:00
|
|
|
#include <unistd.h>
|
2013-01-09 18:48:00 +04:00
|
|
|
#include <inttypes.h>
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/wait.h>
|
2012-05-29 20:11:00 +04:00
|
|
|
#include <sys/mman.h>
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-10-11 15:59:43 +04:00
|
|
|
#include "protobuf.h"
|
|
|
|
#include "protobuf/sa.pb-c.h"
|
2013-06-27 23:32:18 +04:00
|
|
|
#include "protobuf/timer.pb-c.h"
|
2012-10-11 15:59:43 +04:00
|
|
|
#include "protobuf/creds.pb-c.h"
|
2013-01-09 18:32:56 +03:00
|
|
|
#include "protobuf/core.pb-c.h"
|
2013-03-12 21:00:05 +04:00
|
|
|
#include "protobuf/pagemap.pb-c.h"
|
2012-10-11 15:59:43 +04:00
|
|
|
|
2014-09-29 12:47:37 +04:00
|
|
|
#include "imgset.h"
|
2011-09-23 12:00:45 +04:00
|
|
|
#include "syscall.h"
|
2011-12-19 21:57:59 +04:00
|
|
|
#include "ptrace.h"
|
2013-01-09 17:02:47 +04:00
|
|
|
#include "asm/processor-flags.h"
|
2011-09-23 12:00:45 +04:00
|
|
|
#include "parasite-syscall.h"
|
|
|
|
#include "parasite-blob.h"
|
|
|
|
#include "parasite.h"
|
2012-05-29 20:11:00 +04:00
|
|
|
#include "crtools.h"
|
2012-08-02 08:10:22 +04:00
|
|
|
#include "namespaces.h"
|
2013-05-24 01:42:18 +04:00
|
|
|
#include "kerndat.h"
|
2012-10-08 18:59:36 +04:00
|
|
|
#include "pstree.h"
|
2013-11-05 12:32:56 +04:00
|
|
|
#include "posix-timer.h"
|
2013-01-15 23:24:01 +04:00
|
|
|
#include "net.h"
|
2013-04-08 17:39:21 +04:00
|
|
|
#include "mem.h"
|
2013-11-05 12:33:03 +04:00
|
|
|
#include "vma.h"
|
2013-06-27 23:32:22 +04:00
|
|
|
#include "proc_parse.h"
|
2014-12-19 16:01:54 +03:00
|
|
|
#include "aio.h"
|
2012-05-29 20:11:00 +04:00
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
2013-10-11 10:47:58 +04:00
|
|
|
#include <elf.h>
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2013-01-09 17:26:31 +04:00
|
|
|
#include "asm/parasite-syscall.h"
|
2013-01-09 18:32:56 +03:00
|
|
|
#include "asm/dump.h"
|
2013-05-24 16:20:21 +04:00
|
|
|
#include "asm/restorer.h"
|
2015-06-05 00:04:12 +03:00
|
|
|
#include "pie/pie-relocs.h"
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
static int can_run_syscall(unsigned long ip, unsigned long start, unsigned long end)
|
|
|
|
{
|
|
|
|
return ip >= start && ip < (end - code_syscall_size);
|
|
|
|
}
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
static int syscall_fits_vma_area(struct vma_area *vma_area)
|
|
|
|
{
|
2014-02-04 00:08:16 +04:00
|
|
|
return can_run_syscall((unsigned long)vma_area->e->start,
|
|
|
|
(unsigned long)vma_area->e->start,
|
|
|
|
(unsigned long)vma_area->e->end);
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
static struct vma_area *get_vma_by_ip(struct list_head *vma_area_list, unsigned long ip)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
2012-02-15 18:00:50 +04:00
|
|
|
struct vma_area *vma_area;
|
|
|
|
|
|
|
|
list_for_each_entry(vma_area, vma_area_list, list) {
|
2015-07-31 10:36:27 -04:00
|
|
|
if (vma_area->e->start >= kdat.task_size)
|
2012-02-15 18:00:50 +04:00
|
|
|
continue;
|
2014-02-04 00:08:16 +04:00
|
|
|
if (!(vma_area->e->prot & PROT_EXEC))
|
2012-02-15 18:00:50 +04:00
|
|
|
continue;
|
|
|
|
if (syscall_fits_vma_area(vma_area))
|
|
|
|
return vma_area;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2013-11-01 14:23:32 +04:00
|
|
|
static inline int ptrace_get_regs(int pid, user_regs_struct_t *regs)
|
|
|
|
{
|
2013-10-11 10:47:58 +04:00
|
|
|
struct iovec iov;
|
|
|
|
|
|
|
|
iov.iov_base = regs;
|
|
|
|
iov.iov_len = sizeof(user_regs_struct_t);
|
|
|
|
return ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov);
|
2013-11-01 14:23:32 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline int ptrace_set_regs(int pid, user_regs_struct_t *regs)
|
|
|
|
{
|
2013-10-11 10:47:58 +04:00
|
|
|
struct iovec iov;
|
|
|
|
|
|
|
|
iov.iov_base = regs;
|
|
|
|
iov.iov_len = sizeof(user_regs_struct_t);
|
|
|
|
return ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov);
|
2013-11-01 14:23:32 +04:00
|
|
|
}
|
|
|
|
|
2013-10-30 17:48:08 +04:00
|
|
|
static int get_thread_ctx(int pid, struct thread_ctx *ctx)
|
|
|
|
{
|
|
|
|
if (ptrace(PTRACE_GETSIGMASK, pid, sizeof(k_rtsigset_t), &ctx->sigmask)) {
|
|
|
|
pr_perror("can't get signal blocking mask for %d", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-11-01 14:23:32 +04:00
|
|
|
if (ptrace_get_regs(pid, &ctx->regs)) {
|
2013-10-30 17:48:08 +04:00
|
|
|
pr_perror("Can't obtain registers (pid: %d)", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-10-30 19:46:13 +04:00
|
|
|
static int restore_thread_ctx(int pid, struct thread_ctx *ctx)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
2013-11-01 14:23:32 +04:00
|
|
|
if (ptrace_set_regs(pid, &ctx->regs)) {
|
2013-10-30 19:46:13 +04:00
|
|
|
pr_perror("Can't restore registers (pid: %d)", pid);
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), &ctx->sigmask)) {
|
|
|
|
pr_perror("Can't block signals");
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-10-30 18:26:46 +04:00
|
|
|
static int parasite_run(pid_t pid, int cmd, unsigned long ip, void *stack,
|
2013-10-30 16:59:38 +04:00
|
|
|
user_regs_struct_t *regs, struct thread_ctx *octx)
|
2013-07-16 19:02:34 +04:00
|
|
|
{
|
|
|
|
k_rtsigset_t block;
|
|
|
|
|
|
|
|
ksigfillset(&block);
|
|
|
|
if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), &block)) {
|
|
|
|
pr_perror("Can't block signals for %d", pid);
|
|
|
|
goto err_sig;
|
|
|
|
}
|
|
|
|
|
|
|
|
parasite_setup_regs(ip, stack, regs);
|
2013-11-01 14:23:32 +04:00
|
|
|
if (ptrace_set_regs(pid, regs)) {
|
2013-07-16 19:02:34 +04:00
|
|
|
pr_perror("Can't set registers for %d", pid);
|
|
|
|
goto err_regs;
|
|
|
|
}
|
|
|
|
|
2013-10-30 18:26:46 +04:00
|
|
|
if (ptrace(cmd, pid, NULL, NULL)) {
|
2013-07-16 19:02:34 +04:00
|
|
|
pr_perror("Can't run parasite at %d", pid);
|
|
|
|
goto err_cont;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_cont:
|
2013-11-01 14:23:32 +04:00
|
|
|
if (ptrace_set_regs(pid, &octx->regs))
|
2013-07-16 19:02:34 +04:00
|
|
|
pr_perror("Can't restore regs for %d", pid);
|
|
|
|
err_regs:
|
2013-10-30 16:59:38 +04:00
|
|
|
if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), &octx->sigmask))
|
2013-07-16 19:02:34 +04:00
|
|
|
pr_perror("Can't restore sigmask for %d", pid);
|
|
|
|
err_sig:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
/* we run at @regs->ip */
|
2013-07-16 19:02:34 +04:00
|
|
|
static int parasite_trap(struct parasite_ctl *ctl, pid_t pid,
|
2013-05-24 16:20:13 +04:00
|
|
|
user_regs_struct_t *regs,
|
2013-10-30 16:59:38 +04:00
|
|
|
struct thread_ctx *octx)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
siginfo_t siginfo;
|
|
|
|
int status;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Most ideas are taken from Tejun Heo's parasite thread
|
|
|
|
* https://code.google.com/p/ptrace-parasite/
|
|
|
|
*/
|
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
if (wait4(pid, &status, __WALL, NULL) != pid) {
|
2013-02-26 17:08:47 +04:00
|
|
|
pr_perror("Waited pid mismatch (pid: %d)", pid);
|
2012-02-15 18:00:50 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!WIFSTOPPED(status)) {
|
|
|
|
pr_err("Task is still running (pid: %d)\n", pid);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo)) {
|
2013-02-26 17:08:47 +04:00
|
|
|
pr_perror("Can't get siginfo (pid: %d)", pid);
|
2012-02-15 18:00:50 +04:00
|
|
|
goto err;
|
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2013-11-01 14:23:32 +04:00
|
|
|
if (ptrace_get_regs(pid, regs)) {
|
2013-02-26 17:08:47 +04:00
|
|
|
pr_perror("Can't obtain registers (pid: %d)", pid);
|
2012-02-15 18:00:50 +04:00
|
|
|
goto err;
|
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2013-01-14 11:25:45 +04:00
|
|
|
if (WSTOPSIG(status) != SIGTRAP || siginfo.si_code != ARCH_SI_TRAP) {
|
2012-02-15 18:00:50 +04:00
|
|
|
pr_debug("** delivering signal %d si_code=%d\n",
|
|
|
|
siginfo.si_signo, siginfo.si_code);
|
|
|
|
|
2013-07-11 13:46:51 +04:00
|
|
|
pr_err("Unexpected %d task interruption, aborting\n", pid);
|
|
|
|
goto err;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2013-04-12 13:00:06 -07:00
|
|
|
* We've reached this point if int3 is triggered inside our
|
2012-10-29 13:40:45 +04:00
|
|
|
* parasite code. So we're done.
|
2011-09-23 12:00:45 +04:00
|
|
|
*/
|
2012-02-15 18:00:50 +04:00
|
|
|
ret = 0;
|
2011-09-23 12:00:45 +04:00
|
|
|
err:
|
2013-10-30 19:46:13 +04:00
|
|
|
if (restore_thread_ctx(pid, octx))
|
2013-07-11 13:46:52 +04:00
|
|
|
ret = -1;
|
2013-10-30 19:46:13 +04:00
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-07-11 13:46:53 +04:00
|
|
|
int __parasite_execute_syscall(struct parasite_ctl *ctl, user_regs_struct_t *regs)
|
|
|
|
{
|
|
|
|
pid_t pid = ctl->pid.real;
|
|
|
|
int err;
|
2014-10-14 17:54:00 +04:00
|
|
|
u8 code_orig[BUILTIN_SYSCALL_SIZE];
|
2013-07-11 13:46:53 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Inject syscall instruction and remember original code,
|
|
|
|
* we will need it to restore original program content.
|
|
|
|
*/
|
2014-10-14 17:54:00 +04:00
|
|
|
memcpy(code_orig, code_syscall, sizeof(code_orig));
|
2013-07-11 13:46:53 +04:00
|
|
|
if (ptrace_swap_area(pid, (void *)ctl->syscall_ip,
|
2014-10-14 17:54:00 +04:00
|
|
|
(void *)code_orig, sizeof(code_orig))) {
|
2013-07-11 13:46:53 +04:00
|
|
|
pr_err("Can't inject syscall blob (pid: %d)\n", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-10-30 18:26:46 +04:00
|
|
|
err = parasite_run(pid, PTRACE_CONT, ctl->syscall_ip, 0, regs, &ctl->orig);
|
2013-07-16 19:02:34 +04:00
|
|
|
if (!err)
|
2013-10-30 16:59:38 +04:00
|
|
|
err = parasite_trap(ctl, pid, regs, &ctl->orig);
|
2013-07-11 13:46:53 +04:00
|
|
|
|
2014-10-14 17:54:00 +04:00
|
|
|
if (ptrace_poke_area(pid, (void *)code_orig,
|
|
|
|
(void *)ctl->syscall_ip, sizeof(code_orig))) {
|
2013-07-11 13:46:53 +04:00
|
|
|
pr_err("Can't restore syscall blob (pid: %d)\n", ctl->pid.real);
|
|
|
|
err = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2013-04-08 17:33:56 +04:00
|
|
|
void *parasite_args_s(struct parasite_ctl *ctl, int args_size)
|
2012-10-11 15:59:43 +04:00
|
|
|
{
|
2013-03-01 20:11:28 +04:00
|
|
|
BUG_ON(args_size > ctl->args_size);
|
2012-10-11 15:59:43 +04:00
|
|
|
return ctl->addr_args;
|
|
|
|
}
|
|
|
|
|
2013-05-27 16:38:49 +04:00
|
|
|
static int parasite_execute_trap_by_pid(unsigned int cmd,
|
|
|
|
struct parasite_ctl *ctl, pid_t pid,
|
2013-07-11 13:46:51 +04:00
|
|
|
void *stack,
|
2013-10-30 16:59:38 +04:00
|
|
|
struct thread_ctx *octx)
|
2012-02-12 00:32:32 +04:00
|
|
|
{
|
2013-10-30 16:59:38 +04:00
|
|
|
user_regs_struct_t regs = octx->regs;
|
2012-02-12 00:32:32 +04:00
|
|
|
int ret;
|
|
|
|
|
2012-10-11 17:59:10 +04:00
|
|
|
*ctl->addr_cmd = cmd;
|
2012-02-12 00:32:32 +04:00
|
|
|
|
2013-10-30 18:26:46 +04:00
|
|
|
ret = parasite_run(pid, PTRACE_CONT, ctl->parasite_ip, stack, ®s, octx);
|
2013-07-16 19:02:34 +04:00
|
|
|
if (ret == 0)
|
2013-10-30 16:59:38 +04:00
|
|
|
ret = parasite_trap(ctl, pid, ®s, octx);
|
2012-06-26 20:00:00 +04:00
|
|
|
if (ret == 0)
|
2013-01-14 11:25:46 +04:00
|
|
|
ret = (int)REG_RES(regs);
|
2012-02-12 00:32:32 +04:00
|
|
|
|
2012-02-16 21:54:49 +04:00
|
|
|
if (ret)
|
2012-06-26 20:01:00 +04:00
|
|
|
pr_err("Parasite exited with %d\n", ret);
|
2012-02-16 21:54:49 +04:00
|
|
|
|
2012-02-12 00:32:32 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-05-24 16:20:12 +04:00
|
|
|
static int __parasite_send_cmd(int sockfd, struct ctl_msg *m)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = send(sockfd, m, sizeof(*m), 0);
|
|
|
|
if (ret == -1) {
|
2014-08-20 14:52:00 +04:00
|
|
|
pr_perror("Failed to send command %d to daemon", m->cmd);
|
2013-05-24 16:20:12 +04:00
|
|
|
return -1;
|
|
|
|
} else if (ret != sizeof(*m)) {
|
|
|
|
pr_err("Message to daemon is trimmed (%d/%d)\n",
|
|
|
|
(int)sizeof(*m), ret);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-05-27 16:38:51 +04:00
|
|
|
pr_debug("Sent msg to daemon %d %d %d\n", m->cmd, m->ack, m->err);
|
2013-05-24 16:20:12 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-05-27 16:38:51 +04:00
|
|
|
static int parasite_wait_ack(int sockfd, unsigned int cmd, struct ctl_msg *m)
|
2013-05-24 16:20:12 +04:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2013-05-27 16:38:51 +04:00
|
|
|
pr_debug("Wait for ack %d on daemon socket\n", cmd);
|
2013-05-24 16:20:12 +04:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
memzero(m, sizeof(*m));
|
|
|
|
|
|
|
|
ret = recv(sockfd, m, sizeof(*m), MSG_WAITALL);
|
|
|
|
if (ret == -1) {
|
2013-05-27 16:38:51 +04:00
|
|
|
pr_perror("Failed to read ack");
|
2013-05-24 16:20:12 +04:00
|
|
|
return -1;
|
|
|
|
} else if (ret != sizeof(*m)) {
|
|
|
|
pr_err("Message reply from daemon is trimmed (%d/%d)\n",
|
|
|
|
(int)sizeof(*m), ret);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-05-27 16:38:51 +04:00
|
|
|
pr_debug("Fetched ack: %d %d %d\n",
|
|
|
|
m->cmd, m->ack, m->err);
|
2013-05-24 16:20:12 +04:00
|
|
|
|
2013-05-27 16:38:51 +04:00
|
|
|
if (m->cmd != cmd || m->ack != cmd) {
|
2013-05-24 16:20:12 +04:00
|
|
|
pr_err("Communication error, this is not "
|
|
|
|
"the ack we expected\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-07-17 08:56:17 +04:00
|
|
|
int __parasite_wait_daemon_ack(unsigned int cmd,
|
2013-05-27 16:38:51 +04:00
|
|
|
struct parasite_ctl *ctl)
|
2013-05-24 16:20:12 +04:00
|
|
|
{
|
|
|
|
struct ctl_msg m;
|
|
|
|
|
2013-05-27 16:38:51 +04:00
|
|
|
if (parasite_wait_ack(ctl->tsock, cmd, &m))
|
2013-05-24 16:20:12 +04:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (m.err != 0) {
|
2013-05-27 16:38:51 +04:00
|
|
|
pr_err("Command %d for daemon failed with %d\n",
|
|
|
|
cmd, m.err);
|
2013-05-24 16:20:12 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-17 08:54:24 +04:00
|
|
|
int __parasite_execute_daemon(unsigned int cmd, struct parasite_ctl *ctl)
|
2013-05-24 16:20:12 +04:00
|
|
|
{
|
|
|
|
struct ctl_msg m;
|
|
|
|
|
2013-05-27 16:38:51 +04:00
|
|
|
m = ctl_msg_cmd(cmd);
|
2013-07-17 08:54:24 +04:00
|
|
|
return __parasite_send_cmd(ctl->tsock, &m);
|
2013-05-24 16:20:12 +04:00
|
|
|
}
|
|
|
|
|
2013-07-17 08:54:24 +04:00
|
|
|
int parasite_execute_daemon(unsigned int cmd, struct parasite_ctl *ctl)
|
2013-05-24 16:20:12 +04:00
|
|
|
{
|
2013-07-17 08:54:24 +04:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = __parasite_execute_daemon(cmd, ctl);
|
|
|
|
if (!ret)
|
2013-07-17 08:56:17 +04:00
|
|
|
ret = __parasite_wait_daemon_ack(cmd, ctl);
|
2013-07-17 08:54:24 +04:00
|
|
|
|
|
|
|
return ret;
|
2013-05-24 16:20:12 +04:00
|
|
|
}
|
|
|
|
|
2012-03-21 11:47:00 +04:00
|
|
|
static int gen_parasite_saddr(struct sockaddr_un *saddr, int key)
|
2012-02-01 16:23:50 +03:00
|
|
|
{
|
|
|
|
int sun_len;
|
|
|
|
|
|
|
|
saddr->sun_family = AF_UNIX;
|
|
|
|
snprintf(saddr->sun_path, UNIX_PATH_MAX,
|
2012-03-21 11:47:00 +04:00
|
|
|
"X/crtools-pr-%d", key);
|
2012-02-01 16:23:50 +03:00
|
|
|
|
|
|
|
sun_len = SUN_LEN(saddr);
|
|
|
|
*saddr->sun_path = '\0';
|
|
|
|
|
|
|
|
return sun_len;
|
|
|
|
}
|
|
|
|
|
2013-04-08 17:33:56 +04:00
|
|
|
int parasite_send_fd(struct parasite_ctl *ctl, int fd)
|
2012-02-01 16:23:50 +03:00
|
|
|
{
|
2012-07-14 15:36:00 +04:00
|
|
|
if (send_fd(ctl->tsock, NULL, 0, fd) < 0) {
|
2012-02-01 16:23:50 +03:00
|
|
|
pr_perror("Can't send file descriptor");
|
2012-07-14 15:36:00 +04:00
|
|
|
return -1;
|
2012-02-01 16:23:50 +03:00
|
|
|
}
|
2012-07-14 15:36:00 +04:00
|
|
|
return 0;
|
2012-02-01 16:23:50 +03:00
|
|
|
}
|
|
|
|
|
2013-10-02 19:29:24 +04:00
|
|
|
/*
|
|
|
|
* We need to detect parasite crashes not to hang on socket operations.
|
|
|
|
* Since CRIU holds parasite with ptrace, it will receive SIGCHLD if the
|
|
|
|
* latter would crash.
|
|
|
|
*
|
|
|
|
* This puts a restriction on how to execute a sub-process on dump stage.
|
|
|
|
* One should use the cr_system helper, that blocks sigcild and waits
|
|
|
|
* for the spawned program to finish.
|
|
|
|
*/
|
|
|
|
static void sigchld_handler(int signal, siginfo_t *siginfo, void *data)
|
|
|
|
{
|
|
|
|
int pid, status;
|
|
|
|
|
|
|
|
pr_err("si_code=%d si_pid=%d si_status=%d\n",
|
|
|
|
siginfo->si_code, siginfo->si_pid, siginfo->si_status);
|
|
|
|
|
2013-10-28 14:56:42 +04:00
|
|
|
pid = waitpid(-1, &status, WNOHANG);
|
2013-10-02 19:29:24 +04:00
|
|
|
if (pid <= 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (WIFEXITED(status))
|
|
|
|
pr_err("%d exited with %d unexpectedly\n", pid, WEXITSTATUS(status));
|
|
|
|
else if (WIFSIGNALED(status))
|
|
|
|
pr_err("%d was killed by %d unexpectedly\n", pid, WTERMSIG(status));
|
|
|
|
else if (WIFSTOPPED(status))
|
|
|
|
pr_err("%d was stopped by %d unexpectedly\n", pid, WSTOPSIG(status));
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int setup_child_handler()
|
|
|
|
{
|
|
|
|
struct sigaction sa = {
|
|
|
|
.sa_sigaction = sigchld_handler,
|
|
|
|
.sa_flags = SA_SIGINFO | SA_RESTART,
|
|
|
|
};
|
|
|
|
|
|
|
|
sigemptyset(&sa.sa_mask);
|
|
|
|
sigaddset(&sa.sa_mask, SIGCHLD);
|
|
|
|
if (sigaction(SIGCHLD, &sa, NULL)) {
|
|
|
|
pr_perror("Unable to setup SIGCHLD handler");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int restore_child_handler()
|
|
|
|
{
|
|
|
|
struct sigaction sa = {
|
|
|
|
.sa_handler = SIG_DFL,
|
|
|
|
.sa_flags = SA_SIGINFO | SA_RESTART,
|
|
|
|
};
|
|
|
|
|
|
|
|
sigemptyset(&sa.sa_mask);
|
|
|
|
sigaddset(&sa.sa_mask, SIGCHLD);
|
|
|
|
if (sigaction(SIGCHLD, &sa, NULL)) {
|
|
|
|
pr_perror("Unable to setup SIGCHLD handler");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-11 13:46:50 +04:00
|
|
|
static int prepare_tsock(struct parasite_ctl *ctl, pid_t pid,
|
2014-09-29 22:05:43 +04:00
|
|
|
struct parasite_init_args *args, struct ns_id *net)
|
2013-07-11 13:46:50 +04:00
|
|
|
{
|
2014-09-29 22:05:31 +04:00
|
|
|
static int ssock = -1;
|
|
|
|
|
2012-08-01 10:17:14 +04:00
|
|
|
pr_info("Putting tsock into pid %d\n", pid);
|
2012-12-20 16:07:44 +04:00
|
|
|
args->h_addr_len = gen_parasite_saddr(&args->h_addr, getpid());
|
2012-07-14 15:36:00 +04:00
|
|
|
|
2013-05-30 17:59:17 +04:00
|
|
|
if (ssock == -1) {
|
2014-09-29 22:05:43 +04:00
|
|
|
ssock = net->net.seqsk;
|
|
|
|
net->net.seqsk = -1;
|
2012-07-14 15:36:00 +04:00
|
|
|
|
2013-05-30 17:59:17 +04:00
|
|
|
if (bind(ssock, (struct sockaddr *)&args->h_addr, args->h_addr_len) < 0) {
|
2012-08-01 10:17:14 +04:00
|
|
|
pr_perror("Can't bind socket");
|
|
|
|
goto err;
|
|
|
|
}
|
2012-08-02 08:10:22 +04:00
|
|
|
|
2013-05-30 17:59:17 +04:00
|
|
|
if (listen(ssock, 1)) {
|
|
|
|
pr_perror("Can't listen on transport socket");
|
2012-08-01 10:17:14 +04:00
|
|
|
goto err;
|
|
|
|
}
|
2012-07-14 15:36:00 +04:00
|
|
|
}
|
|
|
|
|
2014-09-29 22:05:31 +04:00
|
|
|
/*
|
|
|
|
* Set to -1 to prevent any accidental misuse. The
|
|
|
|
* only valid user of it is accept_tsock().
|
|
|
|
*/
|
|
|
|
ctl->tsock = -ssock;
|
2013-07-11 13:46:50 +04:00
|
|
|
return 0;
|
|
|
|
err:
|
|
|
|
close_safe(&ssock);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-09-29 22:05:31 +04:00
|
|
|
static int accept_tsock(struct parasite_ctl *ctl)
|
2013-07-11 13:46:50 +04:00
|
|
|
{
|
|
|
|
int sock;
|
2014-09-29 22:05:31 +04:00
|
|
|
int ask = -ctl->tsock; /* this '-' is explained above */
|
2013-07-11 13:46:50 +04:00
|
|
|
|
2014-09-29 22:05:31 +04:00
|
|
|
sock = accept(ask, NULL, 0);
|
2013-07-11 13:46:50 +04:00
|
|
|
if (sock < 0) {
|
|
|
|
pr_perror("Can't accept connection to the transport socket");
|
2014-09-29 22:05:31 +04:00
|
|
|
close(ask);
|
|
|
|
return -1;
|
2013-07-11 13:46:50 +04:00
|
|
|
}
|
|
|
|
|
2014-09-29 22:05:31 +04:00
|
|
|
ctl->tsock = sock;
|
|
|
|
return 0;
|
2013-07-11 13:46:50 +04:00
|
|
|
}
|
|
|
|
|
2014-09-29 22:05:43 +04:00
|
|
|
static int parasite_init_daemon(struct parasite_ctl *ctl, struct ns_id *net)
|
2013-07-11 13:46:50 +04:00
|
|
|
{
|
|
|
|
struct parasite_init_args *args;
|
2013-05-27 16:38:52 +04:00
|
|
|
pid_t pid = ctl->pid.real;
|
2013-05-24 16:20:12 +04:00
|
|
|
user_regs_struct_t regs;
|
|
|
|
struct ctl_msg m = { };
|
|
|
|
|
2013-07-11 13:46:55 +04:00
|
|
|
*ctl->addr_cmd = PARASITE_CMD_INIT_DAEMON;
|
|
|
|
|
|
|
|
args = parasite_args(ctl, struct parasite_init_args);
|
|
|
|
|
|
|
|
args->sigframe = ctl->rsigframe;
|
|
|
|
args->log_level = log_get_loglevel();
|
|
|
|
|
2014-09-29 22:05:43 +04:00
|
|
|
if (prepare_tsock(ctl, pid, args, net))
|
2015-03-31 15:32:34 +00:00
|
|
|
goto err;
|
2013-05-24 16:20:12 +04:00
|
|
|
|
2013-10-02 19:29:24 +04:00
|
|
|
/* after this we can catch parasite errors in chld handler */
|
|
|
|
if (setup_child_handler())
|
|
|
|
goto err;
|
|
|
|
|
2013-10-30 16:49:22 +04:00
|
|
|
regs = ctl->orig.regs;
|
2013-10-30 18:26:46 +04:00
|
|
|
if (parasite_run(pid, PTRACE_CONT, ctl->parasite_ip, ctl->rstack, ®s, &ctl->orig))
|
2013-05-24 16:20:12 +04:00
|
|
|
goto err;
|
|
|
|
|
2014-09-29 22:05:31 +04:00
|
|
|
if (accept_tsock(ctl) < 0)
|
2013-07-11 13:46:55 +04:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (parasite_send_fd(ctl, log_get_fd()))
|
|
|
|
goto err;
|
|
|
|
|
2013-05-24 16:20:12 +04:00
|
|
|
pr_info("Wait for parasite being daemonized...\n");
|
|
|
|
|
2013-07-11 13:46:55 +04:00
|
|
|
if (parasite_wait_ack(ctl->tsock, PARASITE_CMD_INIT_DAEMON, &m)) {
|
2013-05-24 16:20:12 +04:00
|
|
|
pr_err("Can't switch parasite %d to daemon mode %d\n",
|
|
|
|
pid, m.err);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2014-09-17 19:12:03 +04:00
|
|
|
ctl->sigreturn_addr = args->sigreturn_addr;
|
2013-05-27 16:38:51 +04:00
|
|
|
ctl->daemonized = true;
|
2013-05-24 16:20:12 +04:00
|
|
|
pr_info("Parasite %d has been switched to daemon mode\n", pid);
|
|
|
|
return 0;
|
|
|
|
err:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-05-24 16:20:08 +04:00
|
|
|
int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
|
|
|
|
struct pid *tid, CoreEntry *core)
|
2012-02-21 09:25:17 +03:00
|
|
|
{
|
2012-11-12 17:42:53 +04:00
|
|
|
struct parasite_dump_thread *args;
|
2013-07-10 17:42:03 +04:00
|
|
|
pid_t pid = tid->real;
|
2013-07-16 19:29:42 +04:00
|
|
|
ThreadCoreEntry *tc = core->thread_core;
|
2012-02-21 09:25:17 +03:00
|
|
|
int ret;
|
2013-10-30 16:54:37 +04:00
|
|
|
struct thread_ctx octx;
|
2012-02-21 09:25:17 +03:00
|
|
|
|
2013-07-10 17:42:03 +04:00
|
|
|
BUG_ON(id == 0); /* Leader is dumped in dump_task_core_all */
|
2012-10-11 15:59:43 +04:00
|
|
|
|
2013-07-10 17:42:03 +04:00
|
|
|
args = parasite_args(ctl, struct parasite_dump_thread);
|
2013-05-27 16:38:50 +04:00
|
|
|
|
2013-10-30 17:48:08 +04:00
|
|
|
ret = get_thread_ctx(pid, &octx);
|
|
|
|
if (ret)
|
2013-07-11 13:46:51 +04:00
|
|
|
return -1;
|
2013-10-30 17:48:08 +04:00
|
|
|
|
2013-07-16 19:29:42 +04:00
|
|
|
tc->has_blk_sigset = true;
|
2013-10-30 16:54:37 +04:00
|
|
|
memcpy(&tc->blk_sigset, &octx.sigmask, sizeof(k_rtsigset_t));
|
2013-07-11 13:46:51 +04:00
|
|
|
|
2013-07-11 13:46:54 +04:00
|
|
|
ret = parasite_execute_trap_by_pid(PARASITE_CMD_DUMP_THREAD, ctl,
|
2013-10-30 16:59:38 +04:00
|
|
|
pid, ctl->r_thread_stack, &octx);
|
2013-07-10 17:42:03 +04:00
|
|
|
if (ret) {
|
|
|
|
pr_err("Can't init thread in parasite %d\n", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-05-27 16:38:50 +04:00
|
|
|
|
2013-10-30 16:54:37 +04:00
|
|
|
ret = get_task_regs(pid, octx.regs, core);
|
2013-07-11 13:46:54 +04:00
|
|
|
if (ret) {
|
2013-07-10 17:42:03 +04:00
|
|
|
pr_err("Can't obtain regs for thread %d\n", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-05-27 16:38:50 +04:00
|
|
|
|
2013-01-09 18:27:54 +03:00
|
|
|
tid->virt = args->tid;
|
2013-07-16 19:47:52 +04:00
|
|
|
return dump_thread_core(pid, core, args);
|
2012-02-21 09:25:17 +03:00
|
|
|
}
|
|
|
|
|
2014-09-29 12:47:37 +04:00
|
|
|
int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_imgset)
|
2012-01-24 16:45:19 +04:00
|
|
|
{
|
2012-10-11 15:59:43 +04:00
|
|
|
struct parasite_dump_sa_args *args;
|
2014-09-29 12:48:53 +04:00
|
|
|
int ret, sig;
|
|
|
|
struct cr_img *img;
|
2012-07-18 16:25:06 +04:00
|
|
|
SaEntry se = SA_ENTRY__INIT;
|
2012-07-15 10:18:35 +04:00
|
|
|
|
2012-10-30 20:58:03 +03:00
|
|
|
args = parasite_args(ctl, struct parasite_dump_sa_args);
|
2012-10-11 15:59:43 +04:00
|
|
|
|
2013-05-24 16:20:12 +04:00
|
|
|
ret = parasite_execute_daemon(PARASITE_CMD_DUMP_SIGACTS, ctl);
|
2012-07-15 10:18:35 +04:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
img = img_from_set(cr_imgset, CR_FD_SIGACT);
|
2012-07-15 10:18:35 +04:00
|
|
|
|
2012-12-04 19:26:54 +04:00
|
|
|
for (sig = 1; sig <= SIGMAX; sig++) {
|
|
|
|
int i = sig - 1;
|
|
|
|
|
|
|
|
if (sig == SIGSTOP || sig == SIGKILL)
|
2012-07-15 10:18:35 +04:00
|
|
|
continue;
|
|
|
|
|
2013-01-18 11:08:38 +04:00
|
|
|
ASSIGN_TYPED(se.sigaction, encode_pointer(args->sas[i].rt_sa_handler));
|
2012-10-11 15:59:43 +04:00
|
|
|
ASSIGN_TYPED(se.flags, args->sas[i].rt_sa_flags);
|
2013-01-18 11:08:38 +04:00
|
|
|
ASSIGN_TYPED(se.restorer, encode_pointer(args->sas[i].rt_sa_restorer));
|
2012-10-11 15:59:43 +04:00
|
|
|
ASSIGN_TYPED(se.mask, args->sas[i].rt_sa_mask.sig[0]);
|
2012-07-15 10:18:35 +04:00
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
if (pb_write_one(img, &se, PB_SIGACT) < 0)
|
2012-07-15 10:18:35 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2012-01-24 16:45:19 +04:00
|
|
|
}
|
|
|
|
|
2014-04-15 21:58:49 +04:00
|
|
|
static void encode_itimer(struct itimerval *v, ItimerEntry *ie)
|
2012-07-18 07:23:05 +04:00
|
|
|
{
|
2014-04-15 21:58:49 +04:00
|
|
|
ie->isec = v->it_interval.tv_sec;
|
|
|
|
ie->iusec = v->it_interval.tv_usec;
|
|
|
|
ie->vsec = v->it_value.tv_sec;
|
|
|
|
ie->vusec = v->it_value.tv_usec;
|
2012-07-18 07:23:05 +04:00
|
|
|
}
|
|
|
|
|
2014-04-15 21:58:49 +04:00
|
|
|
int parasite_dump_itimers_seized(struct parasite_ctl *ctl, struct pstree_item *item)
|
2012-01-24 16:45:19 +04:00
|
|
|
{
|
2014-04-15 21:58:49 +04:00
|
|
|
CoreEntry *core = item->core[0];
|
2012-10-11 15:59:43 +04:00
|
|
|
struct parasite_dump_itimers_args *args;
|
2014-04-15 21:58:49 +04:00
|
|
|
int ret;
|
2012-07-18 07:23:05 +04:00
|
|
|
|
2012-10-30 20:58:03 +03:00
|
|
|
args = parasite_args(ctl, struct parasite_dump_itimers_args);
|
2012-10-11 15:59:43 +04:00
|
|
|
|
2013-05-24 16:20:12 +04:00
|
|
|
ret = parasite_execute_daemon(PARASITE_CMD_DUMP_ITIMERS, ctl);
|
2012-07-18 07:23:05 +04:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2014-04-15 21:58:49 +04:00
|
|
|
encode_itimer(&args->real, core->tc->timers->real);
|
|
|
|
encode_itimer(&args->virt, core->tc->timers->virt);
|
|
|
|
encode_itimer(&args->prof, core->tc->timers->prof);
|
2012-07-18 07:23:05 +04:00
|
|
|
|
2014-04-15 21:58:49 +04:00
|
|
|
return 0;
|
2012-01-24 16:45:19 +04:00
|
|
|
}
|
|
|
|
|
2014-04-15 21:59:05 +04:00
|
|
|
static void encode_posix_timer(struct posix_timer *v, struct proc_posix_timer *vp, PosixTimerEntry *pte)
|
2013-06-27 23:32:22 +04:00
|
|
|
{
|
2014-04-15 21:59:05 +04:00
|
|
|
pte->it_id = vp->spt.it_id;
|
|
|
|
pte->clock_id = vp->spt.clock_id;
|
|
|
|
pte->si_signo = vp->spt.si_signo;
|
|
|
|
pte->it_sigev_notify = vp->spt.it_sigev_notify;
|
|
|
|
pte->sival_ptr = encode_pointer(vp->spt.sival_ptr);
|
2013-06-27 23:32:22 +04:00
|
|
|
|
2014-04-15 21:59:05 +04:00
|
|
|
pte->overrun = v->overrun;
|
2013-06-27 23:32:22 +04:00
|
|
|
|
2014-04-15 21:59:05 +04:00
|
|
|
pte->isec = v->val.it_interval.tv_sec;
|
|
|
|
pte->insec = v->val.it_interval.tv_nsec;
|
|
|
|
pte->vsec = v->val.it_value.tv_sec;
|
|
|
|
pte->vnsec = v->val.it_value.tv_nsec;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int core_alloc_posix_timers(TaskTimersEntry *tte, int n,
|
|
|
|
PosixTimerEntry **pte)
|
|
|
|
{
|
|
|
|
int sz;
|
2013-06-27 23:32:22 +04:00
|
|
|
|
2014-04-15 21:59:05 +04:00
|
|
|
/*
|
|
|
|
* Will be free()-ed in core_entry_free()
|
|
|
|
*/
|
|
|
|
|
|
|
|
sz = n * (sizeof(PosixTimerEntry *) + sizeof(PosixTimerEntry));
|
|
|
|
tte->posix = xmalloc(sz);
|
|
|
|
if (!tte->posix)
|
|
|
|
return -1;
|
2013-06-27 23:32:22 +04:00
|
|
|
|
2014-04-15 21:59:05 +04:00
|
|
|
tte->n_posix = n;
|
|
|
|
*pte = (PosixTimerEntry *)(tte->posix + n);
|
|
|
|
return 0;
|
2013-06-27 23:32:22 +04:00
|
|
|
}
|
|
|
|
|
2014-04-15 21:59:05 +04:00
|
|
|
int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc_args,
|
|
|
|
struct parasite_ctl *ctl, struct pstree_item *item)
|
2013-06-27 23:32:22 +04:00
|
|
|
{
|
2014-04-15 21:59:05 +04:00
|
|
|
CoreEntry *core = item->core[0];
|
|
|
|
TaskTimersEntry *tte = core->tc->timers;
|
|
|
|
PosixTimerEntry *pte;
|
2013-06-27 23:32:22 +04:00
|
|
|
struct parasite_dump_posix_timers_args * args;
|
|
|
|
struct proc_posix_timer *temp;
|
2014-04-15 21:59:05 +04:00
|
|
|
int i;
|
2013-06-27 23:32:22 +04:00
|
|
|
int ret = 0;
|
|
|
|
|
2014-04-15 21:59:05 +04:00
|
|
|
if (core_alloc_posix_timers(tte, proc_args->timer_n, &pte))
|
|
|
|
return -1;
|
|
|
|
|
2013-06-27 23:32:22 +04:00
|
|
|
args = parasite_args_s(ctl, posix_timers_dump_size(proc_args->timer_n));
|
|
|
|
args->timer_n = proc_args->timer_n;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
list_for_each_entry(temp, &proc_args->timers, list) {
|
|
|
|
args->timer[i].it_id = temp->spt.it_id;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = parasite_execute_daemon(PARASITE_CMD_DUMP_POSIX_TIMERS, ctl);
|
|
|
|
if (ret < 0)
|
|
|
|
goto end_posix;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
list_for_each_entry(temp, &proc_args->timers, list) {
|
2014-04-15 21:59:05 +04:00
|
|
|
posix_timer_entry__init(&pte[i]);
|
|
|
|
encode_posix_timer(&args->timer[i], temp, &pte[i]);
|
|
|
|
tte->posix[i] = &pte[i];
|
2013-06-27 23:32:22 +04:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
end_posix:
|
2014-04-15 21:59:21 +04:00
|
|
|
free_posix_timers(proc_args);
|
2013-06-27 23:32:22 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-01-27 21:35:59 +04:00
|
|
|
int parasite_dump_misc_seized(struct parasite_ctl *ctl, struct parasite_dump_misc *misc)
|
|
|
|
{
|
2012-10-11 15:59:43 +04:00
|
|
|
struct parasite_dump_misc *ma;
|
|
|
|
|
2012-10-30 20:58:03 +03:00
|
|
|
ma = parasite_args(ctl, struct parasite_dump_misc);
|
2013-05-24 16:20:12 +04:00
|
|
|
if (parasite_execute_daemon(PARASITE_CMD_DUMP_MISC, ctl) < 0)
|
2012-10-11 15:59:43 +04:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
*misc = *ma;
|
|
|
|
return 0;
|
2012-01-27 21:35:59 +04:00
|
|
|
}
|
|
|
|
|
2014-10-16 14:27:21 +04:00
|
|
|
struct parasite_tty_args *parasite_dump_tty(struct parasite_ctl *ctl, int fd, int type)
|
2012-10-15 23:42:49 +04:00
|
|
|
{
|
2012-10-15 23:55:34 +04:00
|
|
|
struct parasite_tty_args *p;
|
2012-10-15 23:42:49 +04:00
|
|
|
|
2012-10-30 20:58:03 +03:00
|
|
|
p = parasite_args(ctl, struct parasite_tty_args);
|
2012-10-15 23:55:34 +04:00
|
|
|
p->fd = fd;
|
2014-10-16 14:27:21 +04:00
|
|
|
p->type = type;
|
2012-10-15 23:55:34 +04:00
|
|
|
|
2013-05-24 16:20:12 +04:00
|
|
|
if (parasite_execute_daemon(PARASITE_CMD_DUMP_TTY, ctl) < 0)
|
2012-10-15 23:55:34 +04:00
|
|
|
return NULL;
|
2012-10-15 23:42:49 +04:00
|
|
|
|
2012-10-15 23:55:34 +04:00
|
|
|
return p;
|
2012-10-15 23:42:49 +04:00
|
|
|
}
|
|
|
|
|
2012-10-11 15:59:43 +04:00
|
|
|
int parasite_dump_creds(struct parasite_ctl *ctl, CredsEntry *ce)
|
|
|
|
{
|
|
|
|
struct parasite_dump_creds *pc;
|
|
|
|
|
2014-08-09 09:22:00 +04:00
|
|
|
BUILD_BUG_ON(sizeof(*pc) > PAGE_SIZE);
|
|
|
|
|
2012-10-30 20:58:03 +03:00
|
|
|
pc = parasite_args(ctl, struct parasite_dump_creds);
|
2014-11-10 10:47:42 +04:00
|
|
|
pc->cap_last_cap = kdat.last_cap;
|
2014-08-14 06:47:00 +04:00
|
|
|
|
2013-05-24 16:20:12 +04:00
|
|
|
if (parasite_execute_daemon(PARASITE_CMD_DUMP_CREDS, ctl) < 0)
|
2012-10-11 15:59:43 +04:00
|
|
|
return -1;
|
|
|
|
|
2014-08-14 06:47:00 +04:00
|
|
|
ce->n_cap_inh = CR_CAP_SIZE;
|
|
|
|
ce->cap_inh = pc->cap_inh;
|
|
|
|
ce->n_cap_prm = CR_CAP_SIZE;
|
|
|
|
ce->cap_prm = pc->cap_prm;
|
|
|
|
ce->n_cap_eff = CR_CAP_SIZE;
|
|
|
|
ce->cap_eff = pc->cap_eff;
|
|
|
|
ce->n_cap_bnd = CR_CAP_SIZE;
|
|
|
|
ce->cap_bnd = pc->cap_bnd;
|
|
|
|
|
2012-10-11 15:59:43 +04:00
|
|
|
ce->secbits = pc->secbits;
|
2012-10-11 16:52:52 +04:00
|
|
|
ce->n_groups = pc->ngroups;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Achtung! We leak the parasite args pointer to the caller.
|
|
|
|
* It's not safe in general, but in our case is OK, since the
|
|
|
|
* latter doesn't go to parasite before using the data in it.
|
|
|
|
*/
|
|
|
|
|
|
|
|
BUILD_BUG_ON(sizeof(ce->groups[0]) != sizeof(pc->groups[0]));
|
|
|
|
ce->groups = pc->groups;
|
2014-10-31 12:14:22 +03:00
|
|
|
|
|
|
|
ce->uid = pc->uids[0];
|
|
|
|
ce->gid = pc->gids[0];
|
|
|
|
ce->euid = pc->uids[1];
|
|
|
|
ce->egid = pc->gids[1];
|
|
|
|
ce->suid = pc->uids[2];
|
|
|
|
ce->sgid = pc->gids[2];
|
|
|
|
ce->fsuid = pc->uids[3];
|
|
|
|
ce->fsgid = pc->gids[3];
|
|
|
|
|
2012-10-11 15:59:43 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-21 19:59:07 +04:00
|
|
|
int parasite_drain_fds_seized(struct parasite_ctl *ctl,
|
2012-09-05 16:41:14 +04:00
|
|
|
struct parasite_drain_fd *dfds, int *lfds, struct fd_opts *opts)
|
2012-03-28 17:36:00 +04:00
|
|
|
{
|
2012-10-11 15:59:43 +04:00
|
|
|
int ret = -1, size;
|
|
|
|
struct parasite_drain_fd *args;
|
|
|
|
|
|
|
|
size = drain_fds_size(dfds);
|
2012-10-30 20:58:03 +03:00
|
|
|
args = parasite_args_s(ctl, size);
|
2012-10-11 15:59:43 +04:00
|
|
|
memcpy(args, dfds, size);
|
2012-03-28 17:36:00 +04:00
|
|
|
|
2013-07-17 08:54:24 +04:00
|
|
|
ret = __parasite_execute_daemon(PARASITE_CMD_DRAIN_FDS, ctl);
|
2012-03-28 17:36:00 +04:00
|
|
|
if (ret) {
|
|
|
|
pr_err("Parasite failed to drain descriptors\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-09-05 16:41:14 +04:00
|
|
|
ret = recv_fds(ctl->tsock, lfds, dfds->nr_fds, opts);
|
2013-05-24 16:20:12 +04:00
|
|
|
if (ret)
|
2012-03-28 17:36:00 +04:00
|
|
|
pr_err("Can't retrieve FDs from socket\n");
|
|
|
|
|
2013-07-17 08:56:17 +04:00
|
|
|
ret |= __parasite_wait_daemon_ack(PARASITE_CMD_DRAIN_FDS, ctl);
|
2012-03-28 17:36:00 +04:00
|
|
|
err:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-09-07 19:16:33 +04:00
|
|
|
int parasite_get_proc_fd_seized(struct parasite_ctl *ctl)
|
|
|
|
{
|
|
|
|
int ret = -1, fd;
|
|
|
|
|
2013-07-17 08:54:24 +04:00
|
|
|
ret = __parasite_execute_daemon(PARASITE_CMD_GET_PROC_FD, ctl);
|
2012-09-07 19:16:33 +04:00
|
|
|
if (ret) {
|
|
|
|
pr_err("Parasite failed to get proc fd\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = recv_fd(ctl->tsock);
|
2013-05-24 16:20:12 +04:00
|
|
|
if (fd < 0)
|
2012-09-07 19:16:33 +04:00
|
|
|
pr_err("Can't retrieve FD from socket\n");
|
2013-07-17 08:56:17 +04:00
|
|
|
if (__parasite_wait_daemon_ack(PARASITE_CMD_GET_PROC_FD, ctl)) {
|
2014-04-09 14:46:14 +04:00
|
|
|
close_safe(&fd);
|
2013-05-24 16:20:12 +04:00
|
|
|
return -1;
|
2012-09-07 19:16:33 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2014-07-06 23:47:00 +04:00
|
|
|
/* This is officially the 50000'th line in the CRIU source code */
|
2013-06-14 15:04:58 +04:00
|
|
|
|
|
|
|
static bool task_in_parasite(struct parasite_ctl *ctl, user_regs_struct_t *regs)
|
|
|
|
{
|
|
|
|
void *addr = (void *) REG_IP(*regs);
|
|
|
|
return addr >= ctl->remote_map &&
|
|
|
|
addr < ctl->remote_map + ctl->map_length;
|
|
|
|
}
|
|
|
|
|
2013-05-24 16:20:23 +04:00
|
|
|
static int parasite_fini_seized(struct parasite_ctl *ctl)
|
2012-11-12 17:42:51 +04:00
|
|
|
{
|
2013-05-27 16:38:51 +04:00
|
|
|
pid_t pid = ctl->pid.real;
|
2013-06-14 15:04:58 +04:00
|
|
|
user_regs_struct_t regs;
|
|
|
|
int status, ret = 0;
|
2014-09-19 23:08:00 +04:00
|
|
|
enum trace_flags flag;
|
2013-05-24 16:20:12 +04:00
|
|
|
|
2013-10-02 19:29:24 +04:00
|
|
|
/* stop getting chld from parasite -- we're about to step-by-step it */
|
|
|
|
if (restore_child_handler())
|
|
|
|
return -1;
|
|
|
|
|
2013-05-27 16:38:51 +04:00
|
|
|
/* Start to trace syscalls for each thread */
|
2013-06-14 15:04:56 +04:00
|
|
|
if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL)) {
|
|
|
|
pr_perror("Unable to interrupt the process");
|
|
|
|
return -1;
|
|
|
|
}
|
2013-05-24 16:20:12 +04:00
|
|
|
|
2013-05-27 16:38:51 +04:00
|
|
|
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;
|
|
|
|
}
|
2013-05-24 16:20:12 +04:00
|
|
|
|
2013-05-27 16:38:51 +04:00
|
|
|
pr_debug("Daemon %d exited trapping\n", pid);
|
|
|
|
if (!WIFSTOPPED(status)) {
|
|
|
|
pr_err("Task is still running (pid: %d)\n", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-05-24 16:20:23 +04:00
|
|
|
|
2013-11-01 14:23:32 +04:00
|
|
|
ret = ptrace_get_regs(pid, ®s);
|
2013-06-14 15:04:58 +04:00
|
|
|
if (ret) {
|
|
|
|
pr_perror("Unable to get registers");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!task_in_parasite(ctl, ®s)) {
|
|
|
|
pr_err("The task is not in parasite code\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-09-17 19:12:02 +04:00
|
|
|
ret = __parasite_execute_daemon(PARASITE_CMD_FINI, ctl);
|
|
|
|
close_safe(&ctl->tsock);
|
|
|
|
if (ret)
|
|
|
|
return -1;
|
|
|
|
|
2014-09-17 19:12:03 +04:00
|
|
|
/* Go to sigreturn as closer as we can */
|
2014-09-22 13:37:00 +04:00
|
|
|
ret = ptrace_stop_pie(pid, ctl->sigreturn_addr, &flag);
|
2014-09-17 19:12:03 +04:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2012-11-12 17:42:51 +04:00
|
|
|
|
2014-09-19 23:08:00 +04:00
|
|
|
if (parasite_stop_on_syscall(1, __NR_rt_sigreturn, flag))
|
2013-09-23 14:33:26 +04:00
|
|
|
return -1;
|
|
|
|
|
2014-09-19 23:48:00 +04:00
|
|
|
if (ptrace_flush_breakpoints(pid))
|
|
|
|
return -1;
|
|
|
|
|
2013-09-30 18:46:50 +04:00
|
|
|
/*
|
|
|
|
* All signals are unblocked now. The kernel notifies about leaving
|
|
|
|
* syscall before starting to deliver signals. All parasite code are
|
|
|
|
* executed with blocked signals, so we can sefly unmap a parasite blob.
|
|
|
|
*/
|
|
|
|
|
2013-09-23 14:33:26 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-23 14:33:27 +04:00
|
|
|
/*
|
|
|
|
* Trap tasks on the exit from the specified syscall
|
|
|
|
*
|
|
|
|
* tasks - number of processes, which should be trapped
|
|
|
|
* sys_nr - the required syscall number
|
|
|
|
*/
|
2014-09-19 23:08:00 +04:00
|
|
|
int parasite_stop_on_syscall(int tasks, const int sys_nr, enum trace_flags trace)
|
2013-09-23 14:33:26 +04:00
|
|
|
{
|
|
|
|
user_regs_struct_t regs;
|
|
|
|
int status, ret;
|
2013-09-23 14:33:27 +04:00
|
|
|
pid_t pid;
|
2014-09-19 23:08:00 +04:00
|
|
|
|
|
|
|
if (tasks > 1)
|
|
|
|
trace = TRACE_ALL;
|
2013-09-23 14:33:26 +04:00
|
|
|
|
2013-05-24 16:20:23 +04:00
|
|
|
/* Stop all threads on the enter point in sys_rt_sigreturn */
|
2013-09-23 14:33:27 +04:00
|
|
|
while (tasks) {
|
|
|
|
pid = wait4(-1, &status, __WALL, NULL);
|
|
|
|
if (pid == -1) {
|
2013-05-24 16:20:23 +04:00
|
|
|
pr_perror("wait4 failed");
|
|
|
|
return -1;
|
|
|
|
}
|
2013-05-24 16:20:12 +04:00
|
|
|
|
2013-06-22 13:14:42 +04:00
|
|
|
if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP) {
|
|
|
|
pr_err("Task is in unexpected state: %x\n", status);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-05-24 16:20:23 +04:00
|
|
|
pr_debug("%d was trapped\n", pid);
|
2014-09-16 00:27:00 +04:00
|
|
|
|
|
|
|
if (trace == TRACE_EXIT) {
|
|
|
|
trace = TRACE_ENTER;
|
|
|
|
pr_debug("`- Expecting exit\n");
|
|
|
|
goto goon;
|
|
|
|
}
|
|
|
|
if (trace == TRACE_ENTER)
|
|
|
|
trace = TRACE_EXIT;
|
|
|
|
|
2013-11-01 14:23:32 +04:00
|
|
|
ret = ptrace_get_regs(pid, ®s);
|
2013-05-24 16:20:23 +04:00
|
|
|
if (ret) {
|
|
|
|
pr_perror("ptrace");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-05-31 09:20:47 +04:00
|
|
|
pr_debug("%d is going to execute the syscall %lx\n", pid, REG_SYSCALL_NR(regs));
|
2013-09-23 14:33:26 +04:00
|
|
|
if (REG_SYSCALL_NR(regs) == sys_nr) {
|
2013-09-23 14:33:27 +04:00
|
|
|
/*
|
|
|
|
* The process is going to execute the required syscall,
|
|
|
|
* the next stop will be on the exit from this syscall
|
|
|
|
*/
|
|
|
|
ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
|
|
|
|
if (ret) {
|
|
|
|
pr_perror("ptrace");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pid = wait4(pid, &status, __WALL, NULL);
|
|
|
|
if (pid == -1) {
|
|
|
|
pr_perror("wait4 failed");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP) {
|
|
|
|
pr_err("Task is in unexpected state: %x\n", status);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-05-24 16:20:23 +04:00
|
|
|
pr_debug("%d was stopped\n", pid);
|
2013-09-23 14:33:27 +04:00
|
|
|
tasks--;
|
|
|
|
continue;
|
2013-05-24 16:20:23 +04:00
|
|
|
}
|
2014-09-16 00:27:00 +04:00
|
|
|
goon:
|
2013-05-24 16:20:23 +04:00
|
|
|
ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
|
|
|
|
if (ret) {
|
|
|
|
pr_perror("ptrace");
|
|
|
|
return -1;
|
|
|
|
}
|
2013-05-24 16:20:12 +04:00
|
|
|
}
|
|
|
|
|
2013-09-23 14:33:26 +04:00
|
|
|
return 0;
|
2013-05-24 16:20:08 +04:00
|
|
|
}
|
|
|
|
|
2014-10-14 16:31:08 +04:00
|
|
|
int parasite_stop_daemon(struct parasite_ctl *ctl)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
2014-10-14 16:31:08 +04:00
|
|
|
if (ctl->daemonized) {
|
|
|
|
/*
|
|
|
|
* Looks like a previous attempt failed, we should do
|
|
|
|
* nothing in this case. parasite will try to cure itself.
|
|
|
|
*/
|
|
|
|
if (ctl->tsock < 0)
|
|
|
|
return -1;
|
2012-02-01 16:23:50 +03:00
|
|
|
|
2014-10-14 16:31:08 +04:00
|
|
|
if (parasite_fini_seized(ctl)) {
|
|
|
|
close_safe(&ctl->tsock);
|
2013-05-24 16:20:23 +04:00
|
|
|
return -1;
|
2014-10-14 16:31:08 +04:00
|
|
|
}
|
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2014-10-14 16:31:08 +04:00
|
|
|
ctl->daemonized = false;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int parasite_cure_remote(struct parasite_ctl *ctl)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (parasite_stop_daemon(ctl))
|
|
|
|
return -1;
|
2013-05-24 16:20:12 +04:00
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
if (ctl->remote_map) {
|
2013-09-23 14:33:36 +04:00
|
|
|
struct parasite_unmap_args *args;
|
|
|
|
|
|
|
|
*ctl->addr_cmd = PARASITE_CMD_UNMAP;
|
|
|
|
|
|
|
|
args = parasite_args(ctl, struct parasite_unmap_args);
|
|
|
|
args->parasite_start = ctl->remote_map;
|
|
|
|
args->parasite_len = ctl->map_length;
|
|
|
|
if (parasite_unmap(ctl, ctl->parasite_ip))
|
2012-02-15 18:00:50 +04:00
|
|
|
ret = -1;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2013-05-14 11:48:51 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int parasite_cure_local(struct parasite_ctl *ctl)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (ctl->local_map) {
|
|
|
|
if (munmap(ctl->local_map, ctl->map_length)) {
|
|
|
|
pr_err("munmap failed (pid: %d)\n", ctl->pid.real);
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-11 13:32:43 +04:00
|
|
|
free(ctl);
|
2011-09-23 12:00:45 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-05-24 16:20:08 +04:00
|
|
|
int parasite_cure_seized(struct parasite_ctl *ctl)
|
2013-05-14 11:48:51 +04:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2013-05-24 16:20:08 +04:00
|
|
|
ret = parasite_cure_remote(ctl);
|
2013-05-14 11:48:51 +04:00
|
|
|
if (!ret)
|
|
|
|
ret = parasite_cure_local(ctl);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-09-23 14:33:28 +04:00
|
|
|
/*
|
2013-09-23 14:33:29 +04:00
|
|
|
* parasite_unmap() is used for unmapping parasite and restorer blobs.
|
|
|
|
* A blob can contain code for unmapping itself, so the porcess is
|
|
|
|
* trapped on the exit from the munmap syscall.
|
2013-09-23 14:33:28 +04:00
|
|
|
*/
|
2013-09-23 14:33:29 +04:00
|
|
|
int parasite_unmap(struct parasite_ctl *ctl, unsigned long addr)
|
|
|
|
{
|
2013-10-30 18:26:46 +04:00
|
|
|
user_regs_struct_t regs = ctl->orig.regs;
|
2013-09-23 14:33:29 +04:00
|
|
|
pid_t pid = ctl->pid.real;
|
|
|
|
int ret = -1;
|
|
|
|
|
2013-10-30 18:26:46 +04:00
|
|
|
ret = parasite_run(pid, PTRACE_SYSCALL, addr, NULL, ®s, &ctl->orig);
|
|
|
|
if (ret)
|
2013-09-23 14:33:29 +04:00
|
|
|
goto err;
|
|
|
|
|
2014-09-19 23:08:00 +04:00
|
|
|
ret = parasite_stop_on_syscall(1, __NR_munmap, TRACE_ENTER);
|
2013-09-23 14:33:29 +04:00
|
|
|
|
2013-10-30 19:46:13 +04:00
|
|
|
if (restore_thread_ctx(pid, &ctl->orig))
|
2013-09-23 14:33:29 +04:00
|
|
|
ret = -1;
|
|
|
|
err:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If vma_area_list is NULL, a place for injecting syscall will not be set. */
|
2013-05-27 16:38:52 +04:00
|
|
|
struct parasite_ctl *parasite_prep_ctl(pid_t pid, struct vm_area_list *vma_area_list)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
struct parasite_ctl *ctl = NULL;
|
|
|
|
struct vma_area *vma_area;
|
|
|
|
|
2013-03-27 15:43:27 +04:00
|
|
|
if (!arch_can_dump_task(pid))
|
2013-02-14 20:26:29 +04:00
|
|
|
goto err;
|
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
/*
|
|
|
|
* Control block early setup.
|
|
|
|
*/
|
2013-05-27 16:38:52 +04:00
|
|
|
ctl = xzalloc(sizeof(*ctl));
|
2011-09-23 12:00:45 +04:00
|
|
|
if (!ctl) {
|
2011-09-30 14:37:12 +04:00
|
|
|
pr_err("Parasite control block allocation failed (pid: %d)\n", pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-07-14 15:36:00 +04:00
|
|
|
ctl->tsock = -1;
|
|
|
|
|
2013-10-30 17:48:08 +04:00
|
|
|
if (get_thread_ctx(pid, &ctl->orig))
|
2012-02-15 18:00:50 +04:00
|
|
|
goto err;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2013-09-23 14:33:28 +04:00
|
|
|
ctl->pid.real = pid;
|
|
|
|
ctl->pid.virt = 0;
|
|
|
|
|
|
|
|
if (vma_area_list == NULL)
|
|
|
|
return ctl;
|
|
|
|
|
|
|
|
/* Search a place for injecting syscall */
|
2013-10-30 16:49:22 +04:00
|
|
|
vma_area = get_vma_by_ip(&vma_area_list->h, REG_IP(ctl->orig.regs));
|
2011-09-23 12:00:45 +04:00
|
|
|
if (!vma_area) {
|
2011-09-30 14:37:12 +04:00
|
|
|
pr_err("No suitable VMA found to run parasite "
|
2012-02-15 18:00:50 +04:00
|
|
|
"bootstrap code (pid: %d)\n", pid);
|
2012-02-13 23:17:51 +04:00
|
|
|
goto err;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2014-02-04 00:08:16 +04:00
|
|
|
ctl->syscall_ip = vma_area->e->start;
|
2014-05-07 22:20:26 +04:00
|
|
|
pr_debug("Parasite syscall_ip at %p\n", (void *)ctl->syscall_ip);
|
2012-02-15 18:00:50 +04:00
|
|
|
|
2012-12-17 22:53:23 +03:00
|
|
|
return ctl;
|
|
|
|
|
|
|
|
err:
|
|
|
|
xfree(ctl);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int parasite_map_exchange(struct parasite_ctl *ctl, unsigned long size)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
|
2012-12-18 20:48:56 +03:00
|
|
|
ctl->remote_map = mmap_seized(ctl, NULL, size,
|
2012-02-13 23:17:51 +04:00
|
|
|
PROT_READ | PROT_WRITE | PROT_EXEC,
|
|
|
|
MAP_ANONYMOUS | MAP_SHARED, -1, 0);
|
|
|
|
if (!ctl->remote_map) {
|
2013-04-08 17:56:48 +04:00
|
|
|
pr_err("Can't allocate memory for parasite blob (pid: %d)\n", ctl->pid.real);
|
2012-12-17 22:53:23 +03:00
|
|
|
return -1;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2015-04-20 18:09:00 +03:00
|
|
|
ctl->map_length = round_up(size, page_size());
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2013-04-08 17:56:48 +04:00
|
|
|
fd = open_proc_rw(ctl->pid.real, "map_files/%p-%p",
|
2012-02-15 18:00:50 +04:00
|
|
|
ctl->remote_map, ctl->remote_map + ctl->map_length);
|
2012-02-17 01:39:36 +04:00
|
|
|
if (fd < 0)
|
2012-12-17 22:53:23 +03:00
|
|
|
return -1;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-12-18 20:48:56 +03:00
|
|
|
ctl->local_map = mmap(NULL, size, PROT_READ | PROT_WRITE,
|
2012-02-13 23:17:51 +04:00
|
|
|
MAP_SHARED | MAP_FILE, fd, 0);
|
2012-02-12 14:50:34 +04:00
|
|
|
close(fd);
|
|
|
|
|
|
|
|
if (ctl->local_map == MAP_FAILED) {
|
2012-02-15 18:00:50 +04:00
|
|
|
ctl->local_map = NULL;
|
2012-02-12 14:50:34 +04:00
|
|
|
pr_perror("Can't map remote parasite map");
|
2012-12-17 22:53:23 +03:00
|
|
|
return -1;
|
2012-02-12 14:50:34 +04:00
|
|
|
}
|
|
|
|
|
2012-12-17 22:53:23 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-11-07 17:53:00 +04:00
|
|
|
static unsigned long parasite_args_size = PARASITE_ARG_SIZE_MIN;
|
|
|
|
void parasite_ensure_args_size(unsigned long sz)
|
2013-03-01 20:11:28 +04:00
|
|
|
{
|
2014-11-07 17:53:00 +04:00
|
|
|
if (parasite_args_size < sz)
|
|
|
|
parasite_args_size = sz;
|
2013-03-01 20:11:28 +04:00
|
|
|
}
|
|
|
|
|
2013-07-11 13:46:55 +04:00
|
|
|
static int parasite_start_daemon(struct parasite_ctl *ctl, struct pstree_item *item)
|
|
|
|
{
|
|
|
|
pid_t pid = ctl->pid.real;
|
|
|
|
|
2013-07-16 20:30:55 +04:00
|
|
|
/*
|
|
|
|
* Get task registers before going daemon, since the
|
|
|
|
* get_task_regs needs to call ptrace on _stopped_ task,
|
|
|
|
* while in daemon it is not such.
|
|
|
|
*/
|
|
|
|
|
2013-10-30 16:49:22 +04:00
|
|
|
if (get_task_regs(pid, ctl->orig.regs, item->core[0])) {
|
2013-07-11 13:46:55 +04:00
|
|
|
pr_err("Can't obtain regs for thread %d\n", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (construct_sigframe(ctl->sigframe, ctl->rsigframe, item->core[0]))
|
|
|
|
return -1;
|
|
|
|
|
2014-09-29 22:05:43 +04:00
|
|
|
if (parasite_init_daemon(ctl, dmpi(item)->netns))
|
2015-03-31 15:32:34 +00:00
|
|
|
return -1;
|
2013-07-11 13:46:55 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-01 20:11:38 +04:00
|
|
|
struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
|
2014-11-07 17:53:00 +04:00
|
|
|
struct vm_area_list *vma_area_list)
|
2012-12-17 22:53:23 +03:00
|
|
|
{
|
2013-05-27 16:38:52 +04:00
|
|
|
int ret;
|
2012-12-17 22:53:23 +03:00
|
|
|
struct parasite_ctl *ctl;
|
2013-05-27 16:38:52 +04:00
|
|
|
unsigned long p, map_exchange_size;
|
2012-12-17 22:53:23 +03:00
|
|
|
|
2013-05-24 16:20:08 +04:00
|
|
|
BUG_ON(item->threads[0].real != pid);
|
|
|
|
|
2013-05-27 16:38:52 +04:00
|
|
|
ctl = parasite_prep_ctl(pid, vma_area_list);
|
2012-12-17 22:53:23 +03:00
|
|
|
if (!ctl)
|
|
|
|
return NULL;
|
|
|
|
|
2014-11-07 17:53:00 +04:00
|
|
|
parasite_ensure_args_size(dump_pages_args_size(vma_area_list));
|
2014-12-19 16:01:54 +03:00
|
|
|
parasite_ensure_args_size(aio_rings_args_size(vma_area_list));
|
2014-11-07 17:53:00 +04:00
|
|
|
|
2012-12-17 22:53:23 +03:00
|
|
|
/*
|
|
|
|
* Inject a parasite engine. Ie allocate memory inside alien
|
|
|
|
* space and copy engine code there. Then re-map the engine
|
|
|
|
* locally, so we will get an easy way to access engine memory
|
|
|
|
* without using ptrace at all.
|
|
|
|
*/
|
|
|
|
|
2014-11-07 17:53:00 +04:00
|
|
|
ctl->args_size = round_up(parasite_args_size, PAGE_SIZE);
|
|
|
|
parasite_args_size = PARASITE_ARG_SIZE_MIN; /* reset for next task */
|
2015-07-23 07:59:48 -04:00
|
|
|
map_exchange_size = pie_size(parasite_blob) + ctl->args_size;
|
2013-05-27 16:38:52 +04:00
|
|
|
map_exchange_size += RESTORE_STACK_SIGFRAME + PARASITE_STACK_SIZE;
|
|
|
|
if (item->nr_threads > 1)
|
|
|
|
map_exchange_size += PARASITE_STACK_SIZE;
|
2013-07-11 13:46:51 +04:00
|
|
|
|
2013-10-30 16:49:22 +04:00
|
|
|
memcpy(&item->core[0]->tc->blk_sigset, &ctl->orig.sigmask, sizeof(k_rtsigset_t));
|
2013-07-11 13:46:51 +04:00
|
|
|
|
2013-05-27 16:38:52 +04:00
|
|
|
ret = parasite_map_exchange(ctl, map_exchange_size);
|
2012-12-17 22:53:23 +03:00
|
|
|
if (ret)
|
|
|
|
goto err_restore;
|
|
|
|
|
2012-02-12 14:50:34 +04:00
|
|
|
pr_info("Putting parasite blob into %p->%p\n", ctl->local_map, ctl->remote_map);
|
2012-02-13 21:49:18 +04:00
|
|
|
memcpy(ctl->local_map, parasite_blob, sizeof(parasite_blob));
|
2012-02-12 14:50:34 +04:00
|
|
|
|
2015-06-15 23:16:00 +03:00
|
|
|
ELF_RELOCS_APPLY_PARASITE(ctl->local_map, ctl->remote_map);
|
2015-06-05 00:04:11 +03:00
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
/* Setup the rest of a control block */
|
2012-11-13 20:51:32 +03:00
|
|
|
ctl->parasite_ip = (unsigned long)parasite_sym(ctl->remote_map, __export_parasite_head_start);
|
|
|
|
ctl->addr_cmd = parasite_sym(ctl->local_map, __export_parasite_cmd);
|
|
|
|
ctl->addr_args = parasite_sym(ctl->local_map, __export_parasite_args);
|
2012-02-12 14:51:38 +04:00
|
|
|
|
2015-07-23 07:59:48 -04:00
|
|
|
p = pie_size(parasite_blob) + ctl->args_size;
|
2013-05-24 16:20:10 +04:00
|
|
|
|
2013-05-27 16:38:52 +04:00
|
|
|
ctl->rsigframe = ctl->remote_map + p;
|
|
|
|
ctl->sigframe = ctl->local_map + p;
|
|
|
|
|
|
|
|
p += RESTORE_STACK_SIGFRAME;
|
|
|
|
p += PARASITE_STACK_SIZE;
|
2013-11-06 12:33:47 +04:00
|
|
|
ctl->rstack = ctl->remote_map + p;
|
2013-05-24 16:20:21 +04:00
|
|
|
|
2013-05-27 16:38:52 +04:00
|
|
|
if (item->nr_threads > 1) {
|
|
|
|
p += PARASITE_STACK_SIZE;
|
2013-11-06 12:33:47 +04:00
|
|
|
ctl->r_thread_stack = ctl->remote_map + p;
|
2013-05-24 16:20:10 +04:00
|
|
|
}
|
|
|
|
|
2013-07-11 13:46:55 +04:00
|
|
|
if (parasite_start_daemon(ctl, item))
|
2013-05-27 16:38:52 +04:00
|
|
|
goto err_restore;
|
2013-05-24 16:20:15 +04:00
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
return ctl;
|
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
err_restore:
|
2013-05-24 16:20:08 +04:00
|
|
|
parasite_cure_seized(ctl);
|
2012-04-06 17:58:00 +04:00
|
|
|
return NULL;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
2014-09-22 13:37:00 +04:00
|
|
|
|
|
|
|
int ptrace_stop_pie(pid_t pid, void *addr, enum trace_flags *tf)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = ptrace_set_breakpoint(pid, addr);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (ret > 0) {
|
|
|
|
/*
|
|
|
|
* PIE will stop on a breakpoint, next
|
|
|
|
* stop after that will be syscall enter.
|
|
|
|
*/
|
|
|
|
*tf = TRACE_EXIT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* No breakpoints available -- start tracing it
|
|
|
|
* in a per-syscall manner.
|
|
|
|
*/
|
|
|
|
ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
|
|
|
|
if (ret) {
|
2015-04-23 14:35:00 +03:00
|
|
|
pr_perror("Unable to restart the %d process", pid);
|
2014-09-22 13:37:00 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*tf = TRACE_ENTER;
|
|
|
|
return 0;
|
|
|
|
}
|