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"
|
|
|
|
#include "protobuf/itimer.pb-c.h"
|
|
|
|
#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
|
|
|
|
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"
|
2012-10-08 18:59:36 +04:00
|
|
|
#include "pstree.h"
|
2013-01-15 23:24:01 +04:00
|
|
|
#include "net.h"
|
2013-03-01 20:13:11 +04:00
|
|
|
#include "page-pipe.h"
|
2013-03-12 21:14:40 +04:00
|
|
|
#include "page-xfer.h"
|
2012-05-29 20:11:00 +04:00
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.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"
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
#define parasite_size (round_up(sizeof(parasite_blob), sizeof(long)))
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
return can_run_syscall((unsigned long)vma_area->vma.start,
|
|
|
|
(unsigned long)vma_area->vma.start,
|
|
|
|
(unsigned long)vma_area->vma.end);
|
|
|
|
}
|
|
|
|
|
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) {
|
2013-01-18 11:08:36 +04:00
|
|
|
if (vma_area->vma.start >= TASK_SIZE)
|
2012-02-15 18:00:50 +04:00
|
|
|
continue;
|
|
|
|
if (!(vma_area->vma.prot & PROT_EXEC))
|
|
|
|
continue;
|
|
|
|
if (syscall_fits_vma_area(vma_area))
|
|
|
|
return vma_area;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
/* we run at @regs->ip */
|
2013-01-09 17:26:46 +04:00
|
|
|
int __parasite_execute(struct parasite_ctl *ctl, pid_t pid, user_regs_struct_t *regs)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
siginfo_t siginfo;
|
|
|
|
int status;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
again:
|
2012-02-15 18:00:50 +04:00
|
|
|
if (ptrace(PTRACE_SETREGS, pid, NULL, regs)) {
|
2013-02-26 17:08:47 +04:00
|
|
|
pr_perror("Can't set registers (pid: %d)", pid);
|
2012-02-15 18:00:50 +04:00
|
|
|
goto err;
|
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 (ptrace(PTRACE_CONT, pid, NULL, NULL)) {
|
2013-02-26 17:08:47 +04:00
|
|
|
pr_perror("Can't continue (pid: %d)", pid);
|
2012-02-15 18:00:50 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
if (ptrace(PTRACE_GETREGS, pid, NULL, 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) {
|
2011-09-23 12:00:45 +04:00
|
|
|
retry_signal:
|
2012-02-15 18:00:50 +04:00
|
|
|
pr_debug("** delivering signal %d si_code=%d\n",
|
|
|
|
siginfo.si_signo, siginfo.si_code);
|
|
|
|
|
2012-03-01 19:01:05 +04:00
|
|
|
if (ctl->signals_blocked) {
|
|
|
|
pr_err("Unexpected %d task interruption, aborting\n", pid);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-02-13 23:06:18 +04:00
|
|
|
/* FIXME: jerr(siginfo.si_code > 0, err_restore); */
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
/*
|
|
|
|
* This requires some explanation. If a signal from original
|
|
|
|
* program delivered while we're trying to execute our
|
|
|
|
* injected blob -- we need to setup original registers back
|
|
|
|
* so the kernel would make sigframe for us and update the
|
|
|
|
* former registers.
|
|
|
|
*
|
|
|
|
* Then we should swap registers back to our modified copy
|
|
|
|
* and retry.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (ptrace(PTRACE_SETREGS, pid, NULL, &ctl->regs_orig)) {
|
2013-02-26 17:08:47 +04:00
|
|
|
pr_perror("Can't set registers (pid: %d)", pid);
|
2012-02-15 18:00:50 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL)) {
|
2013-02-26 17:08:47 +04:00
|
|
|
pr_perror("Can't interrupt (pid: %d)", pid);
|
2012-02-15 18:00:50 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ptrace(PTRACE_CONT, pid, NULL, (void *)(unsigned long)siginfo.si_signo)) {
|
2013-02-26 17:08:47 +04:00
|
|
|
pr_perror("Can't continue (pid: %d)", pid);
|
2012-02-15 18:00:50 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
2012-04-25 21:34:05 +04:00
|
|
|
if (SI_EVENT(siginfo.si_code) != PTRACE_EVENT_STOP)
|
2011-09-23 12:00:45 +04:00
|
|
|
goto retry_signal;
|
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
/*
|
|
|
|
* Signal is delivered, so we should update
|
|
|
|
* original registers.
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
user_regs_struct_t r;
|
|
|
|
if (ptrace(PTRACE_GETREGS, pid, NULL, &r)) {
|
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;
|
|
|
|
}
|
|
|
|
ctl->regs_orig = r;
|
|
|
|
}
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-10-29 13:40:45 +04:00
|
|
|
* We've reached this point iif int3 is triggered inside our
|
|
|
|
* 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:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-10-30 20:58:03 +03:00
|
|
|
static 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;
|
|
|
|
}
|
|
|
|
|
2012-10-30 20:58:03 +03:00
|
|
|
#define parasite_args(ctl, type) ({ \
|
2013-03-01 20:11:28 +04:00
|
|
|
BUILD_BUG_ON(sizeof(type) > PARASITE_ARG_SIZE_MIN);\
|
2012-10-30 20:58:03 +03:00
|
|
|
ctl->addr_args; \
|
|
|
|
})
|
|
|
|
|
2012-10-11 15:59:43 +04:00
|
|
|
static int parasite_execute_by_pid(unsigned int cmd, struct parasite_ctl *ctl, pid_t pid)
|
2012-02-12 00:32:32 +04:00
|
|
|
{
|
|
|
|
int ret;
|
2012-02-21 09:25:16 +03:00
|
|
|
user_regs_struct_t regs_orig, regs;
|
|
|
|
|
|
|
|
if (ctl->pid == pid)
|
|
|
|
regs = ctl->regs_orig;
|
|
|
|
else {
|
|
|
|
if (ptrace(PTRACE_GETREGS, pid, NULL, ®s_orig)) {
|
2013-02-26 17:08:47 +04:00
|
|
|
pr_perror("Can't obtain registers (pid: %d)", pid);
|
2012-02-21 09:25:16 +03:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
regs = regs_orig;
|
|
|
|
}
|
2012-02-12 00:32:32 +04:00
|
|
|
|
2012-10-11 17:59:10 +04:00
|
|
|
*ctl->addr_cmd = cmd;
|
2012-02-12 00:32:32 +04:00
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
parasite_setup_regs(ctl->parasite_ip, ®s);
|
2012-02-12 00:32:32 +04:00
|
|
|
|
2012-02-21 09:25:16 +03:00
|
|
|
ret = __parasite_execute(ctl, pid, ®s);
|
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-21 09:25:16 +03:00
|
|
|
if (ctl->pid != pid)
|
|
|
|
if (ptrace(PTRACE_SETREGS, pid, NULL, ®s_orig)) {
|
2013-02-26 17:08:47 +04:00
|
|
|
pr_perror("Can't restore registers (pid: %d)", ctl->pid);
|
2012-02-21 09:25:16 +03:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-02-12 00:32:32 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-10-11 15:59:43 +04:00
|
|
|
static int parasite_execute(unsigned int cmd, struct parasite_ctl *ctl)
|
2012-02-21 09:25:16 +03:00
|
|
|
{
|
2012-10-11 15:59:43 +04:00
|
|
|
return parasite_execute_by_pid(cmd, ctl, ctl->pid);
|
2012-02-21 09:25:16 +03:00
|
|
|
}
|
|
|
|
|
2012-12-17 22:52:06 +03:00
|
|
|
static int munmap_seized(struct parasite_ctl *ctl, void *addr, size_t length)
|
|
|
|
{
|
|
|
|
unsigned long x;
|
2011-11-29 13:33:59 +03:00
|
|
|
|
2012-12-17 22:52:06 +03:00
|
|
|
return syscall_seized(ctl, __NR_munmap, &x,
|
|
|
|
(unsigned long)addr, length, 0, 0, 0, 0);
|
2011-11-29 13:33:59 +03: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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int parasite_send_fd(struct parasite_ctl *ctl, int fd)
|
|
|
|
{
|
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
|
|
|
}
|
|
|
|
|
|
|
|
static int parasite_set_logfd(struct parasite_ctl *ctl, pid_t pid)
|
|
|
|
{
|
|
|
|
int ret;
|
2012-10-11 15:59:43 +04:00
|
|
|
struct parasite_log_args *a;
|
2012-02-01 16:23:50 +03:00
|
|
|
|
2012-03-01 18:52:42 +04:00
|
|
|
ret = parasite_send_fd(ctl, log_get_fd());
|
2012-02-01 16:23:50 +03:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2012-10-30 20:58:03 +03:00
|
|
|
a = parasite_args(ctl, struct parasite_log_args);
|
2012-10-11 15:59:43 +04:00
|
|
|
a->log_level = log_get_loglevel();
|
2012-10-08 19:56:12 +04:00
|
|
|
|
2012-10-11 15:59:43 +04:00
|
|
|
ret = parasite_execute(PARASITE_CMD_CFG_LOG, ctl);
|
2012-02-01 16:23:50 +03:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-11-12 17:42:48 +04:00
|
|
|
static int parasite_init(struct parasite_ctl *ctl, pid_t pid, int nr_threads)
|
2012-07-14 15:36:00 +04:00
|
|
|
{
|
2012-10-11 15:59:43 +04:00
|
|
|
struct parasite_init_args *args;
|
2012-08-01 10:17:14 +04:00
|
|
|
static int sock = -1;
|
2012-07-14 15:36:00 +04:00
|
|
|
|
2012-10-30 20:58:03 +03:00
|
|
|
args = parasite_args(ctl, struct parasite_init_args);
|
2012-10-11 15:59:43 +04:00
|
|
|
|
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-10-11 15:59:43 +04:00
|
|
|
args->p_addr_len = gen_parasite_saddr(&args->p_addr, pid);
|
2012-11-12 17:42:48 +04:00
|
|
|
args->nr_threads = nr_threads;
|
2012-07-14 15:36:00 +04:00
|
|
|
|
2012-08-01 10:17:14 +04:00
|
|
|
if (sock == -1) {
|
2012-08-02 08:10:22 +04:00
|
|
|
int rst = -1;
|
|
|
|
|
2013-01-17 18:14:55 +04:00
|
|
|
if (current_ns_mask & CLONE_NEWNET) {
|
2012-08-02 08:10:22 +04:00
|
|
|
pr_info("Switching to %d's net for tsock creation\n", pid);
|
|
|
|
|
2013-01-15 23:24:01 +04:00
|
|
|
if (switch_ns(pid, &net_ns_desc, &rst))
|
2012-08-02 08:10:22 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-08-01 10:17:14 +04:00
|
|
|
sock = socket(PF_UNIX, SOCK_DGRAM, 0);
|
|
|
|
if (sock < 0) {
|
|
|
|
pr_perror("Can't create socket");
|
|
|
|
return -1;
|
|
|
|
}
|
2012-07-14 15:36:00 +04:00
|
|
|
|
2012-10-11 15:59:43 +04:00
|
|
|
if (bind(sock, (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-01-15 23:24:01 +04:00
|
|
|
if (rst > 0 && restore_ns(rst, &net_ns_desc) < 0)
|
2012-08-02 08:10:22 +04:00
|
|
|
goto err;
|
2012-08-01 10:17:14 +04:00
|
|
|
} else {
|
|
|
|
struct sockaddr addr = { .sa_family = AF_UNSPEC, };
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When the peer of a dgram socket dies the original socket
|
|
|
|
* remains in connected state, thus denying any connections
|
|
|
|
* from "other" sources. Unconnect the socket by hands thus
|
|
|
|
* allowing for parasite to connect back.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (connect(sock, &addr, sizeof(addr)) < 0) {
|
|
|
|
pr_perror("Can't unconnect");
|
|
|
|
goto err;
|
|
|
|
}
|
2012-07-14 15:36:00 +04:00
|
|
|
}
|
|
|
|
|
2012-10-11 15:59:43 +04:00
|
|
|
if (parasite_execute(PARASITE_CMD_INIT, ctl) < 0) {
|
2012-08-01 09:48:02 +04:00
|
|
|
pr_err("Can't init parasite\n");
|
2012-07-14 15:36:00 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-10-11 15:59:43 +04:00
|
|
|
if (connect(sock, (struct sockaddr *)&args->p_addr, args->p_addr_len) < 0) {
|
2012-08-01 09:48:02 +04:00
|
|
|
pr_perror("Can't connect a transport socket");
|
2012-07-14 15:36:00 +04:00
|
|
|
goto err;
|
2012-08-01 09:48:02 +04:00
|
|
|
}
|
2012-07-14 15:36:00 +04:00
|
|
|
|
|
|
|
ctl->tsock = sock;
|
|
|
|
return 0;
|
|
|
|
err:
|
|
|
|
close(sock);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-01-09 18:27:54 +03:00
|
|
|
int parasite_dump_thread_seized(struct parasite_ctl *ctl, struct pid *tid,
|
2013-01-09 18:32:56 +03:00
|
|
|
CoreEntry *core)
|
2012-02-21 09:25:17 +03:00
|
|
|
{
|
2012-11-12 17:42:53 +04:00
|
|
|
struct parasite_dump_thread *args;
|
2012-02-21 09:25:17 +03:00
|
|
|
int ret;
|
|
|
|
|
2012-11-12 17:42:53 +04:00
|
|
|
args = parasite_args(ctl, struct parasite_dump_thread);
|
2012-10-11 15:59:43 +04:00
|
|
|
|
2013-01-09 18:27:54 +03:00
|
|
|
ret = parasite_execute_by_pid(PARASITE_CMD_DUMP_THREAD, ctl, tid->real);
|
2012-02-21 09:25:17 +03:00
|
|
|
|
2013-01-09 18:32:56 +03:00
|
|
|
memcpy(&core->thread_core->blk_sigset, &args->blocked, sizeof(args->blocked));
|
2013-01-18 11:08:38 +04:00
|
|
|
CORE_THREAD_ARCH_INFO(core)->clear_tid_addr = encode_pointer(args->tid_addr);
|
2013-01-09 18:27:54 +03:00
|
|
|
tid->virt = args->tid;
|
2013-01-09 18:32:56 +03:00
|
|
|
core_put_tls(core, args->tls);
|
2012-02-21 09:25:17 +03:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-01-24 16:45:19 +04:00
|
|
|
int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_fdset *cr_fdset)
|
|
|
|
{
|
2012-10-11 15:59:43 +04:00
|
|
|
struct parasite_dump_sa_args *args;
|
2012-12-04 19:26:54 +04:00
|
|
|
int ret, sig, fd;
|
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
|
|
|
|
|
|
|
ret = parasite_execute(PARASITE_CMD_DUMP_SIGACTS, ctl);
|
2012-07-15 10:18:35 +04:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
fd = fdset_fd(cr_fdset, CR_FD_SIGACT);
|
|
|
|
|
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
|
|
|
|
2012-08-07 02:26:50 +04:00
|
|
|
if (pb_write_one(fd, &se, PB_SIGACT) < 0)
|
2012-07-15 10:18:35 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2012-01-24 16:45:19 +04:00
|
|
|
}
|
|
|
|
|
2012-07-18 07:23:05 +04:00
|
|
|
static int dump_one_timer(struct itimerval *v, int fd)
|
|
|
|
{
|
2012-07-18 16:27:01 +04:00
|
|
|
ItimerEntry ie = ITIMER_ENTRY__INIT;
|
2012-07-18 07:23:05 +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_sec;
|
|
|
|
|
2012-08-07 02:26:50 +04:00
|
|
|
return pb_write_one(fd, &ie, PB_ITIMERS);
|
2012-07-18 07:23:05 +04:00
|
|
|
}
|
|
|
|
|
2012-01-24 16:45:19 +04:00
|
|
|
int parasite_dump_itimers_seized(struct parasite_ctl *ctl, struct cr_fdset *cr_fdset)
|
|
|
|
{
|
2012-10-11 15:59:43 +04:00
|
|
|
struct parasite_dump_itimers_args *args;
|
2012-07-18 07:23:05 +04:00
|
|
|
int ret, fd;
|
|
|
|
|
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
|
|
|
|
|
|
|
ret = parasite_execute(PARASITE_CMD_DUMP_ITIMERS, ctl);
|
2012-07-18 07:23:05 +04:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
fd = fdset_fd(cr_fdset, CR_FD_ITIMERS);
|
|
|
|
|
2012-10-11 15:59:43 +04:00
|
|
|
ret = dump_one_timer(&args->real, fd);
|
2012-07-18 07:23:05 +04:00
|
|
|
if (!ret)
|
2012-10-11 15:59:43 +04:00
|
|
|
ret = dump_one_timer(&args->virt, fd);
|
2012-07-18 07:23:05 +04:00
|
|
|
if (!ret)
|
2012-10-11 15:59:43 +04:00
|
|
|
ret = dump_one_timer(&args->prof, fd);
|
2012-07-18 07:23:05 +04:00
|
|
|
|
|
|
|
return ret;
|
2012-01-24 16:45:19 +04:00
|
|
|
}
|
|
|
|
|
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);
|
2012-10-11 15:59:43 +04:00
|
|
|
if (parasite_execute(PARASITE_CMD_DUMP_MISC, ctl) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
*misc = *ma;
|
|
|
|
return 0;
|
2012-01-27 21:35:59 +04:00
|
|
|
}
|
|
|
|
|
2012-10-15 23:55:34 +04:00
|
|
|
struct parasite_tty_args *parasite_dump_tty(struct parasite_ctl *ctl, int fd)
|
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;
|
|
|
|
|
2012-10-15 23:42:49 +04:00
|
|
|
if (parasite_execute(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;
|
|
|
|
|
2012-10-30 20:58:03 +03:00
|
|
|
pc = parasite_args(ctl, struct parasite_dump_creds);
|
2012-10-11 15:59:43 +04:00
|
|
|
if (parasite_execute(PARASITE_CMD_DUMP_CREDS, ctl) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
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;
|
2012-10-11 15:59:43 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-30 00:17:03 +04:00
|
|
|
static unsigned int vmas_mprotect_size(struct vm_area_list *vmas)
|
|
|
|
{
|
|
|
|
return sizeof(struct parasite_mprotect_args) +
|
|
|
|
(vmas->nr * sizeof(struct parasite_vma_entry));
|
|
|
|
}
|
|
|
|
|
2013-03-01 20:12:46 +04:00
|
|
|
static unsigned int vmas_pagemap_size(struct vm_area_list *vmas)
|
|
|
|
{
|
2013-03-01 20:13:11 +04:00
|
|
|
/*
|
|
|
|
* In the worst case I need one iovec for half of the
|
|
|
|
* pages (e.g. every odd/even)
|
|
|
|
*/
|
|
|
|
|
|
|
|
return sizeof(struct parasite_dump_pages_args) +
|
2013-03-15 18:19:59 +04:00
|
|
|
(vmas->priv_size + 1) * sizeof(struct iovec) / 2;
|
2013-03-01 20:13:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
#define PME_PRESENT (1ULL << 63)
|
|
|
|
#define PME_SWAP (1ULL << 62)
|
|
|
|
#define PME_FILE (1ULL << 61)
|
|
|
|
|
|
|
|
static inline bool should_dump_page(VmaEntry *vmae, u64 pme)
|
|
|
|
{
|
|
|
|
if (vma_entry_is(vmae, VMA_AREA_VDSO))
|
|
|
|
return true;
|
|
|
|
/*
|
|
|
|
* Optimisation for private mapping pages, that haven't
|
|
|
|
* yet being COW-ed
|
|
|
|
*/
|
|
|
|
if (vma_entry_is(vmae, VMA_FILE_PRIVATE) && (pme & PME_FILE))
|
|
|
|
return false;
|
|
|
|
if (pme & (PME_PRESENT | PME_SWAP))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int generate_iovs(struct vma_area *vma, int pagemap, struct page_pipe *pp, u64 *map)
|
|
|
|
{
|
|
|
|
unsigned long pfn, nr_to_scan;
|
|
|
|
u64 aux;
|
|
|
|
|
|
|
|
aux = vma->vma.start / PAGE_SIZE * sizeof(*map);
|
|
|
|
if (lseek(pagemap, aux, SEEK_SET) != aux) {
|
|
|
|
pr_perror("Can't rewind pagemap file");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
nr_to_scan = vma_area_len(vma) / PAGE_SIZE;
|
|
|
|
aux = nr_to_scan * sizeof(*map);
|
|
|
|
if (read(pagemap, map, aux) != aux) {
|
|
|
|
pr_perror("Can't read pagemap file");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (pfn = 0; pfn < nr_to_scan; pfn++) {
|
|
|
|
if (!should_dump_page(&vma->vma, map[pfn]))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (page_pipe_add_page(pp, vma->vma.start + pfn * PAGE_SIZE))
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-03-01 20:12:46 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-08 17:28:30 +04:00
|
|
|
static int parasite_mprotect_seized(struct parasite_ctl *ctl, struct vm_area_list *vma_area_list, bool unprotect)
|
2013-03-30 00:17:03 +04:00
|
|
|
{
|
|
|
|
struct parasite_mprotect_args *args;
|
|
|
|
struct parasite_vma_entry *p_vma;
|
|
|
|
struct vma_area *vma;
|
|
|
|
|
|
|
|
args = parasite_args_s(ctl, vmas_pagemap_size(vma_area_list));
|
|
|
|
|
|
|
|
p_vma = args->vmas;
|
|
|
|
args->nr = 0;
|
|
|
|
|
|
|
|
list_for_each_entry(vma, &vma_area_list->h, list) {
|
|
|
|
if (!privately_dump_vma(vma))
|
|
|
|
continue;
|
|
|
|
if (vma->vma.prot & PROT_READ)
|
|
|
|
continue;
|
|
|
|
p_vma->start = vma->vma.start;
|
|
|
|
p_vma->len = vma_area_len(vma);
|
|
|
|
p_vma->prot = vma->vma.prot;
|
|
|
|
if (unprotect)
|
|
|
|
p_vma->prot |= PROT_READ;
|
|
|
|
args->nr++;
|
|
|
|
p_vma++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return parasite_execute(PARASITE_CMD_MPROTECT_VMAS, ctl);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __parasite_dump_pages_seized(struct parasite_ctl *ctl, int vpid,
|
2013-03-12 21:00:05 +04:00
|
|
|
struct vm_area_list *vma_area_list, struct cr_fdset *cr_fdset)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
2013-03-01 20:13:11 +04:00
|
|
|
struct parasite_dump_pages_args *args;
|
|
|
|
u64 *map;
|
2013-03-12 21:14:40 +04:00
|
|
|
int pagemap;
|
2013-03-01 20:13:11 +04:00
|
|
|
struct page_pipe *pp;
|
|
|
|
struct page_pipe_buf *ppb;
|
2011-09-23 12:00:45 +04:00
|
|
|
struct vma_area *vma_area;
|
2012-02-15 18:00:50 +04:00
|
|
|
int ret = -1;
|
2013-03-12 21:14:40 +04:00
|
|
|
struct page_xfer xfer;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
pr_info("\n");
|
2012-01-11 13:30:38 +04:00
|
|
|
pr_info("Dumping pages (type: %d pid: %d)\n", CR_FD_PAGES, ctl->pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
|
2013-03-01 20:13:11 +04:00
|
|
|
pr_debug(" Private vmas %lu/%lu pages\n",
|
|
|
|
vma_area_list->longest, vma_area_list->priv_size);
|
|
|
|
|
|
|
|
args = parasite_args_s(ctl, vmas_pagemap_size(vma_area_list));
|
2011-10-03 11:52:13 +04:00
|
|
|
|
2013-03-01 20:13:11 +04:00
|
|
|
map = xmalloc(vma_area_list->longest * sizeof(*map));
|
|
|
|
if (!map)
|
2012-02-12 00:26:54 +04:00
|
|
|
goto out;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2013-03-01 20:13:11 +04:00
|
|
|
ret = pagemap = open_proc(ctl->pid, "pagemap");
|
|
|
|
if (ret < 0)
|
|
|
|
goto out_free;
|
|
|
|
|
|
|
|
ret = -1;
|
|
|
|
pp = create_page_pipe(vma_area_list->priv_size / 2, args->iovs);
|
|
|
|
if (!pp)
|
|
|
|
goto out_close;
|
2012-10-11 15:59:43 +04:00
|
|
|
|
2013-03-01 20:11:51 +04:00
|
|
|
list_for_each_entry(vma_area, &vma_area_list->h, list) {
|
2013-03-01 20:12:02 +04:00
|
|
|
if (!privately_dump_vma(vma_area))
|
2013-01-09 17:23:48 +04:00
|
|
|
continue;
|
|
|
|
|
2013-03-01 20:13:11 +04:00
|
|
|
ret = generate_iovs(vma_area, pagemap, pp, map);
|
|
|
|
if (ret < 0)
|
|
|
|
goto out_pp;
|
|
|
|
}
|
2011-11-22 20:07:20 +04:00
|
|
|
|
2013-03-01 20:13:11 +04:00
|
|
|
args->off = 0;
|
|
|
|
list_for_each_entry(ppb, &pp->bufs, l) {
|
|
|
|
ret = parasite_send_fd(ctl, ppb->p[1]);
|
|
|
|
if (ret)
|
|
|
|
goto out_pp;
|
2012-04-27 04:53:17 +04:00
|
|
|
|
2013-03-01 20:13:11 +04:00
|
|
|
args->nr = ppb->nr_segs;
|
|
|
|
args->nr_pages = ppb->pages_in;
|
|
|
|
pr_debug("PPB: %d pages %d segs %u pipe %d off\n",
|
|
|
|
args->nr_pages, args->nr, ppb->pipe_size, args->off);
|
|
|
|
|
|
|
|
ret = parasite_execute(PARASITE_CMD_DUMPPAGES, ctl);
|
|
|
|
if (ret < 0)
|
|
|
|
goto out_pp;
|
|
|
|
|
|
|
|
args->off += args->nr;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2013-03-12 21:14:40 +04:00
|
|
|
ret = open_page_xfer(&xfer, CR_FD_PAGEMAP, vpid);
|
|
|
|
if (ret < 0)
|
2013-03-12 21:00:05 +04:00
|
|
|
goto out_pp;
|
|
|
|
|
2013-03-15 18:12:34 +04:00
|
|
|
ret = page_xfer_dump_pages(&xfer, pp, 0);
|
2013-03-12 21:00:05 +04:00
|
|
|
|
2013-03-12 21:14:40 +04:00
|
|
|
xfer.close(&xfer);
|
2013-03-01 20:13:11 +04:00
|
|
|
out_pp:
|
|
|
|
destroy_page_pipe(pp);
|
|
|
|
out_close:
|
|
|
|
close(pagemap);
|
|
|
|
out_free:
|
|
|
|
xfree(map);
|
2011-11-23 13:08:28 +04:00
|
|
|
out:
|
2011-09-23 12:00:45 +04:00
|
|
|
pr_info("----------------------------------------\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-03-30 00:17:03 +04:00
|
|
|
int parasite_dump_pages_seized(struct parasite_ctl *ctl, int vpid,
|
|
|
|
struct vm_area_list *vma_area_list, struct cr_fdset *cr_fdset)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = parasite_mprotect_seized(ctl, vma_area_list, true);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("Can't dump unprotect vmas with parasite\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = __parasite_dump_pages_seized(ctl, vpid, vma_area_list, cr_fdset);
|
|
|
|
if (ret)
|
|
|
|
pr_err("Can't dump page with parasite\n");
|
|
|
|
|
|
|
|
if (parasite_mprotect_seized(ctl, vma_area_list, false)) {
|
|
|
|
pr_err("Can't rollback unprotected vmas with parasite\n");
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2012-10-11 15:59:43 +04:00
|
|
|
ret = parasite_execute(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);
|
2012-03-28 17:36:00 +04:00
|
|
|
if (ret) {
|
|
|
|
pr_err("Can't retrieve FDs from socket\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2012-10-11 15:59:43 +04:00
|
|
|
ret = parasite_execute(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);
|
|
|
|
if (fd < 0) {
|
|
|
|
pr_err("Can't retrieve FD from socket\n");
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2012-11-12 17:42:51 +04:00
|
|
|
int parasite_init_threads_seized(struct parasite_ctl *ctl, struct pstree_item *item)
|
|
|
|
{
|
|
|
|
int ret = 0, i;
|
|
|
|
|
|
|
|
for (i = 0; i < item->nr_threads; i++) {
|
|
|
|
if (item->pid.real == item->threads[i].real)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ret = parasite_execute_by_pid(PARASITE_CMD_INIT_THREAD, ctl,
|
|
|
|
item->threads[i].real);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("Can't init thread in parasite %d\n",
|
|
|
|
item->threads[i].real);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int parasite_fini_threads_seized(struct parasite_ctl *ctl, struct pstree_item *item)
|
|
|
|
{
|
|
|
|
int ret = 0, i;
|
|
|
|
|
|
|
|
for (i = 0; i < item->nr_threads; i++) {
|
|
|
|
if (item->pid.real == item->threads[i].real)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ret = parasite_execute_by_pid(PARASITE_CMD_FINI_THREAD, ctl,
|
|
|
|
item->threads[i].real);
|
|
|
|
/*
|
|
|
|
* Note the thread's fini() can be called even when not
|
|
|
|
* all threads were init()'ed, say we're rolling back from
|
|
|
|
* error happened while we were init()'ing some thread, thus
|
|
|
|
* -ENOENT will be returned but we should continie for the
|
|
|
|
* rest of threads set.
|
|
|
|
*
|
|
|
|
* Strictly speaking we always init() threads in sequence thus
|
|
|
|
* we could simply break the loop once first -ENOENT returned
|
|
|
|
* but I prefer to be on a safe side even if some future changes
|
|
|
|
* would change the code logic.
|
|
|
|
*/
|
|
|
|
if (ret && ret != -ENOENT) {
|
|
|
|
pr_err("Can't fini thread in parasite %d\n",
|
|
|
|
item->threads[i].real);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-11-12 17:42:55 +04:00
|
|
|
int parasite_cure_seized(struct parasite_ctl *ctl, struct pstree_item *item)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
2012-02-15 18:00:50 +04:00
|
|
|
int ret = 0;
|
2012-02-01 16:23:50 +03:00
|
|
|
|
2012-08-01 10:17:14 +04:00
|
|
|
ctl->tsock = -1;
|
2012-07-14 15:36:00 +04:00
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
if (ctl->parasite_ip) {
|
2012-03-01 19:01:05 +04:00
|
|
|
ctl->signals_blocked = 0;
|
2012-11-12 17:42:55 +04:00
|
|
|
parasite_fini_threads_seized(ctl, item);
|
2012-10-11 15:59:43 +04:00
|
|
|
parasite_execute(PARASITE_CMD_FINI, ctl);
|
2012-02-01 16:23:50 +03:00
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
if (ctl->remote_map) {
|
|
|
|
if (munmap_seized(ctl, (void *)ctl->remote_map, ctl->map_length)) {
|
2012-03-01 18:52:42 +04:00
|
|
|
pr_err("munmap_seized failed (pid: %d)\n", ctl->pid);
|
2012-02-15 18:00:50 +04:00
|
|
|
ret = -1;
|
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
if (ctl->local_map) {
|
2012-12-18 20:48:56 +03:00
|
|
|
if (munmap(ctl->local_map, ctl->map_length)) {
|
2012-03-01 18:52:42 +04:00
|
|
|
pr_err("munmap failed (pid: %d)\n", ctl->pid);
|
2012-02-15 18:00:50 +04:00
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
if (ptrace_poke_area(ctl->pid, (void *)ctl->code_orig,
|
|
|
|
(void *)ctl->syscall_ip, sizeof(ctl->code_orig))) {
|
2012-03-01 18:52:42 +04:00
|
|
|
pr_err("Can't restore syscall blob (pid: %d)\n", ctl->pid);
|
2012-02-15 18:00:50 +04:00
|
|
|
ret = -1;
|
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
if (ptrace(PTRACE_SETREGS, ctl->pid, NULL, &ctl->regs_orig)) {
|
2012-03-01 18:52:42 +04:00
|
|
|
pr_err("Can't restore registers (pid: %d)\n", ctl->pid);
|
2012-02-08 14:11:54 +04:00
|
|
|
ret = -1;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2012-01-11 13:32:43 +04:00
|
|
|
free(ctl);
|
2011-09-23 12:00:45 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-03-01 20:11:51 +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.
|
|
|
|
*/
|
2012-01-13 17:20:57 +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;
|
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
if (ptrace(PTRACE_GETREGS, pid, NULL, &ctl->regs_orig)) {
|
|
|
|
pr_err("Can't obtain registers (pid: %d)\n", pid);
|
|
|
|
goto err;
|
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2013-03-01 20:11:51 +04:00
|
|
|
vma_area = get_vma_by_ip(&vma_area_list->h, REG_IP(ctl->regs_orig));
|
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
|
|
|
}
|
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
ctl->pid = pid;
|
|
|
|
ctl->syscall_ip = vma_area->vma.start;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Inject syscall instruction and remember original code,
|
|
|
|
* we will need it to restore original program content.
|
|
|
|
*/
|
|
|
|
memcpy(ctl->code_orig, code_syscall, sizeof(ctl->code_orig));
|
|
|
|
if (ptrace_swap_area(ctl->pid, (void *)ctl->syscall_ip,
|
|
|
|
(void *)ctl->code_orig, sizeof(ctl->code_orig))) {
|
|
|
|
pr_err("Can't inject syscall blob (pid: %d)\n", pid);
|
|
|
|
goto err;
|
|
|
|
}
|
2011-09-23 12:00:45 +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) {
|
2012-12-17 22:53:23 +03:00
|
|
|
pr_err("Can't allocate memory for parasite blob (pid: %d)\n", ctl->pid);
|
|
|
|
return -1;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2012-12-18 20:48:56 +03:00
|
|
|
ctl->map_length = round_up(size, PAGE_SIZE);
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2012-12-17 22:53:23 +03:00
|
|
|
fd = open_proc_rw(ctl->pid, "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;
|
|
|
|
}
|
|
|
|
|
2013-03-01 20:12:46 +04:00
|
|
|
static unsigned long parasite_args_size(struct vm_area_list *vmas, struct parasite_drain_fd *dfds)
|
2013-03-01 20:11:28 +04:00
|
|
|
{
|
2013-03-01 20:11:38 +04:00
|
|
|
unsigned long size = PARASITE_ARG_SIZE_MIN;
|
|
|
|
|
|
|
|
size = max(size, (unsigned long)drain_fds_size(dfds));
|
2013-03-01 20:12:46 +04:00
|
|
|
size = max(size, (unsigned long)vmas_pagemap_size(vmas));
|
2013-03-30 00:17:03 +04:00
|
|
|
size = max(size, (unsigned long)vmas_mprotect_size(vmas));
|
2013-03-01 20:11:38 +04:00
|
|
|
|
|
|
|
return size;
|
2013-03-01 20:11:28 +04:00
|
|
|
}
|
|
|
|
|
2013-03-01 20:11:38 +04:00
|
|
|
struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
|
2013-03-01 20:11:51 +04:00
|
|
|
struct vm_area_list *vma_area_list, struct parasite_drain_fd *dfds)
|
2012-12-17 22:53:23 +03:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct parasite_ctl *ctl;
|
|
|
|
|
|
|
|
ctl = parasite_prep_ctl(pid, vma_area_list);
|
|
|
|
if (!ctl)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2013-03-01 20:12:46 +04:00
|
|
|
ctl->args_size = parasite_args_size(vma_area_list, dfds);
|
2013-03-01 20:11:28 +04:00
|
|
|
ret = parasite_map_exchange(ctl, parasite_size + ctl->args_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
|
|
|
|
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
|
|
|
|
2012-11-12 17:42:48 +04:00
|
|
|
ret = parasite_init(ctl, pid, item->nr_threads);
|
2012-02-01 16:23:50 +03:00
|
|
|
if (ret) {
|
|
|
|
pr_err("%d: Can't create a transport socket\n", pid);
|
2012-02-15 18:00:50 +04:00
|
|
|
goto err_restore;
|
2012-02-01 16:23:50 +03:00
|
|
|
}
|
|
|
|
|
2012-03-01 19:01:05 +04:00
|
|
|
ctl->signals_blocked = 1;
|
|
|
|
|
2012-02-01 16:23:50 +03:00
|
|
|
ret = parasite_set_logfd(ctl, pid);
|
|
|
|
if (ret) {
|
|
|
|
pr_err("%d: Can't set a logging descriptor\n", pid);
|
2012-02-15 18:00:50 +04:00
|
|
|
goto err_restore;
|
2012-02-01 16:23:50 +03:00
|
|
|
}
|
|
|
|
|
2012-11-12 17:42:55 +04:00
|
|
|
ret = parasite_init_threads_seized(ctl, item);
|
|
|
|
if (ret)
|
|
|
|
goto err_restore;
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
return ctl;
|
|
|
|
|
2012-02-15 18:00:50 +04:00
|
|
|
err_restore:
|
2012-11-12 17:42:55 +04:00
|
|
|
parasite_cure_seized(ctl, item);
|
2012-04-06 17:58:00 +04:00
|
|
|
return NULL;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|