mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-30 05:48:05 +00:00
infect: Move infect() into infect.c
Not only infect() routine but all dependant code too. This is the core of the library actually. Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com> Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
This commit is contained in:
parent
2724375919
commit
bb33a7742a
@ -4,10 +4,10 @@
|
||||
#include "int.h"
|
||||
#include "types.h"
|
||||
#include "crtools.h"
|
||||
#include "parasite-syscall.h"
|
||||
#include "proc_parse.h"
|
||||
#include "ptrace.h"
|
||||
#include "pstree.h"
|
||||
#include "parasite-syscall.h"
|
||||
#include "vma.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
@ -32,4 +32,6 @@ struct parasite_ctl {
|
||||
int tsock; /* transport socket for transferring fds */
|
||||
};
|
||||
|
||||
int parasite_run(pid_t pid, int cmd, unsigned long ip, void *stack,
|
||||
user_regs_struct_t *regs, struct thread_ctx *octx);
|
||||
#endif
|
||||
|
@ -23,4 +23,8 @@ extern int compel_wait_task(int pid, int ppid,
|
||||
#define TASK_STOPPED 0x3
|
||||
#define TASK_ZOMBIE 0x6
|
||||
|
||||
struct parasite_ctl;
|
||||
|
||||
extern int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size);
|
||||
|
||||
#endif
|
||||
|
299
criu/infect.c
299
criu/infect.c
@ -6,12 +6,23 @@
|
||||
#include <signal.h>
|
||||
#include <linux/seccomp.h>
|
||||
|
||||
#include "ptrace.h"
|
||||
#include "signal.h"
|
||||
#include "asm/parasite-syscall.h"
|
||||
#include "asm/dump.h"
|
||||
#include "restorer.h"
|
||||
#include "parasite.h"
|
||||
#include "parasite-syscall.h"
|
||||
|
||||
#include "pie-relocs.h"
|
||||
#include "parasite-blob.h"
|
||||
#include "sigframe.h"
|
||||
#include "log.h"
|
||||
#include "infect.h"
|
||||
#include "infect-priv.h"
|
||||
|
||||
/* XXX will be removed soon */
|
||||
extern int parasite_wait_ack(int sockfd, unsigned int cmd, struct ctl_msg *m);
|
||||
|
||||
#define PTRACE_EVENT_STOP 128
|
||||
|
||||
#ifndef SECCOMP_MODE_DISABLED
|
||||
@ -230,3 +241,289 @@ err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int gen_parasite_saddr(struct sockaddr_un *saddr, int key)
|
||||
{
|
||||
int sun_len;
|
||||
|
||||
saddr->sun_family = AF_UNIX;
|
||||
snprintf(saddr->sun_path, UNIX_PATH_MAX,
|
||||
"X/crtools-pr-%d", key);
|
||||
|
||||
sun_len = SUN_LEN(saddr);
|
||||
*saddr->sun_path = '\0';
|
||||
|
||||
return sun_len;
|
||||
}
|
||||
|
||||
static int prepare_tsock(struct parasite_ctl *ctl, pid_t pid,
|
||||
struct parasite_init_args *args)
|
||||
{
|
||||
static int ssock = -1;
|
||||
|
||||
pr_info("Putting tsock into pid %d\n", pid);
|
||||
args->h_addr_len = gen_parasite_saddr(&args->h_addr, getpid());
|
||||
|
||||
if (ssock == -1) {
|
||||
ssock = *ctl->ictx.p_sock;
|
||||
if (ssock == -1) {
|
||||
pr_err("No socket in ictx\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
*ctl->ictx.p_sock = -1;
|
||||
|
||||
if (bind(ssock, (struct sockaddr *)&args->h_addr, args->h_addr_len) < 0) {
|
||||
pr_perror("Can't bind socket");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (listen(ssock, 1)) {
|
||||
pr_perror("Can't listen on transport socket");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check a case when parasite can't initialize a command socket */
|
||||
if (ctl->ictx.flags & INFECT_FAIL_CONNECT)
|
||||
args->h_addr_len = gen_parasite_saddr(&args->h_addr, getpid() + 1);
|
||||
|
||||
/*
|
||||
* Set to -1 to prevent any accidental misuse. The
|
||||
* only valid user of it is accept_tsock().
|
||||
*/
|
||||
ctl->tsock = -ssock;
|
||||
return 0;
|
||||
err:
|
||||
close_safe(&ssock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int setup_child_handler(struct parasite_ctl *ctl)
|
||||
{
|
||||
struct sigaction sa = {
|
||||
.sa_sigaction = ctl->ictx.child_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;
|
||||
}
|
||||
|
||||
int parasite_run(pid_t pid, int cmd, unsigned long ip, void *stack,
|
||||
user_regs_struct_t *regs, struct thread_ctx *octx)
|
||||
{
|
||||
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);
|
||||
if (ptrace_set_regs(pid, regs)) {
|
||||
pr_perror("Can't set registers for %d", pid);
|
||||
goto err_regs;
|
||||
}
|
||||
|
||||
if (ptrace(cmd, pid, NULL, NULL)) {
|
||||
pr_perror("Can't run parasite at %d", pid);
|
||||
goto err_cont;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_cont:
|
||||
if (ptrace_set_regs(pid, &octx->regs))
|
||||
pr_perror("Can't restore regs for %d", pid);
|
||||
err_regs:
|
||||
if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), &octx->sigmask))
|
||||
pr_perror("Can't restore sigmask for %d", pid);
|
||||
err_sig:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int accept_tsock(struct parasite_ctl *ctl)
|
||||
{
|
||||
int sock;
|
||||
int ask = -ctl->tsock; /* this '-' is explained above */
|
||||
|
||||
sock = accept(ask, NULL, 0);
|
||||
if (sock < 0) {
|
||||
pr_perror("Can't accept connection to the transport socket");
|
||||
close(ask);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctl->tsock = sock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parasite_init_daemon(struct parasite_ctl *ctl)
|
||||
{
|
||||
struct parasite_init_args *args;
|
||||
pid_t pid = ctl->rpid;
|
||||
user_regs_struct_t regs;
|
||||
struct ctl_msg m = { };
|
||||
|
||||
*ctl->addr_cmd = PARASITE_CMD_INIT_DAEMON;
|
||||
|
||||
args = parasite_args(ctl, struct parasite_init_args);
|
||||
|
||||
args->sigframe = (uintptr_t)ctl->rsigframe;
|
||||
args->log_level = log_get_loglevel();
|
||||
|
||||
futex_set(&args->daemon_connected, 0);
|
||||
|
||||
if (prepare_tsock(ctl, pid, args))
|
||||
goto err;
|
||||
|
||||
/* after this we can catch parasite errors in chld handler */
|
||||
if (setup_child_handler(ctl))
|
||||
goto err;
|
||||
|
||||
regs = ctl->orig.regs;
|
||||
if (parasite_run(pid, PTRACE_CONT, ctl->parasite_ip, ctl->rstack, ®s, &ctl->orig))
|
||||
goto err;
|
||||
|
||||
futex_wait_while_eq(&args->daemon_connected, 0);
|
||||
if (futex_get(&args->daemon_connected) != 1) {
|
||||
errno = -(int)futex_get(&args->daemon_connected);
|
||||
pr_perror("Unable to connect a transport socket");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (accept_tsock(ctl) < 0)
|
||||
goto err;
|
||||
|
||||
if (parasite_send_fd(ctl, log_get_fd()))
|
||||
goto err;
|
||||
|
||||
pr_info("Wait for parasite being daemonized...\n");
|
||||
|
||||
if (parasite_wait_ack(ctl->tsock, PARASITE_CMD_INIT_DAEMON, &m)) {
|
||||
pr_err("Can't switch parasite %d to daemon mode %d\n",
|
||||
pid, m.err);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ctl->sigreturn_addr = args->sigreturn_addr;
|
||||
ctl->daemonized = true;
|
||||
pr_info("Parasite %d has been switched to daemon mode\n", pid);
|
||||
return 0;
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int parasite_start_daemon(struct parasite_ctl *ctl)
|
||||
{
|
||||
pid_t pid = ctl->rpid;
|
||||
struct infect_ctx *ictx = &ctl->ictx;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
if (get_task_regs(pid, ctl->orig.regs, ictx->save_regs, ictx->regs_arg)) {
|
||||
pr_err("Can't obtain regs for thread %d\n", pid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ictx->make_sigframe(ictx->regs_arg, ctl->sigframe, ctl->rsigframe, &ctl->orig.sigmask))
|
||||
return -1;
|
||||
|
||||
if (parasite_init_daemon(ctl))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define init_parasite_ctl(ctl, blob_type) \
|
||||
do { \
|
||||
memcpy(ctl->local_map, parasite_##blob_type##_blob, \
|
||||
sizeof(parasite_##blob_type##_blob)); \
|
||||
ELF_RELOCS_APPLY(parasite_##blob_type, \
|
||||
ctl->local_map, ctl->remote_map); \
|
||||
/* Setup the rest of a control block */ \
|
||||
ctl->parasite_ip = (unsigned long)parasite_sym(ctl->remote_map, \
|
||||
blob_type, __export_parasite_head_start); \
|
||||
ctl->addr_cmd = parasite_sym(ctl->local_map, blob_type, \
|
||||
__export_parasite_cmd); \
|
||||
ctl->addr_args = parasite_sym(ctl->local_map, blob_type, \
|
||||
__export_parasite_args); \
|
||||
} while (0)
|
||||
|
||||
int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size)
|
||||
{
|
||||
int ret;
|
||||
unsigned long p, map_exchange_size, parasite_size = 0;
|
||||
|
||||
if (!arch_can_dump_task(ctl))
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
if (seized_native(ctl))
|
||||
parasite_size = pie_size(parasite_native);
|
||||
#ifdef CONFIG_COMPAT
|
||||
else
|
||||
parasite_size = pie_size(parasite_compat);
|
||||
#endif
|
||||
|
||||
ctl->args_size = round_up(args_size, PAGE_SIZE);
|
||||
parasite_size += ctl->args_size;
|
||||
|
||||
map_exchange_size = parasite_size;
|
||||
map_exchange_size += RESTORE_STACK_SIGFRAME + PARASITE_STACK_SIZE;
|
||||
if (nr_threads > 1)
|
||||
map_exchange_size += PARASITE_STACK_SIZE;
|
||||
|
||||
ret = parasite_map_exchange(ctl, map_exchange_size);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
pr_info("Putting parasite blob into %p->%p\n", ctl->local_map, ctl->remote_map);
|
||||
|
||||
if (seized_native(ctl))
|
||||
init_parasite_ctl(ctl, native);
|
||||
#ifdef CONFIG_COMPAT
|
||||
else
|
||||
init_parasite_ctl(ctl, compat);
|
||||
#endif
|
||||
|
||||
p = parasite_size;
|
||||
|
||||
ctl->rsigframe = ctl->remote_map + p;
|
||||
ctl->sigframe = ctl->local_map + p;
|
||||
|
||||
p += RESTORE_STACK_SIGFRAME;
|
||||
p += PARASITE_STACK_SIZE;
|
||||
ctl->rstack = ctl->remote_map + p;
|
||||
|
||||
if (nr_threads > 1) {
|
||||
p += PARASITE_STACK_SIZE;
|
||||
ctl->r_thread_stack = ctl->remote_map + p;
|
||||
}
|
||||
|
||||
if (parasite_start_daemon(ctl))
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "imgset.h"
|
||||
#include "ptrace.h"
|
||||
#include "parasite-syscall.h"
|
||||
#include "parasite-blob.h"
|
||||
#include "parasite.h"
|
||||
#include "crtools.h"
|
||||
#include "namespaces.h"
|
||||
@ -42,6 +41,7 @@
|
||||
#include "restorer.h"
|
||||
#include "pie/pie-relocs.h"
|
||||
|
||||
#include "infect.h"
|
||||
#include "infect-priv.h"
|
||||
|
||||
#define MEMFD_FNAME "CRIUMFD"
|
||||
@ -126,39 +126,6 @@ bool seized_native(struct parasite_ctl *ctl)
|
||||
{
|
||||
return user_regs_native(&ctl->orig.regs);
|
||||
}
|
||||
static int parasite_run(pid_t pid, int cmd, unsigned long ip, void *stack,
|
||||
user_regs_struct_t *regs, struct thread_ctx *octx)
|
||||
{
|
||||
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);
|
||||
if (ptrace_set_regs(pid, regs)) {
|
||||
pr_perror("Can't set registers for %d", pid);
|
||||
goto err_regs;
|
||||
}
|
||||
|
||||
if (ptrace(cmd, pid, NULL, NULL)) {
|
||||
pr_perror("Can't run parasite at %d", pid);
|
||||
goto err_cont;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_cont:
|
||||
if (ptrace_set_regs(pid, &octx->regs))
|
||||
pr_perror("Can't restore regs for %d", pid);
|
||||
err_regs:
|
||||
if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), &octx->sigmask))
|
||||
pr_perror("Can't restore sigmask for %d", pid);
|
||||
err_sig:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we run at @regs->ip */
|
||||
static int parasite_trap(struct parasite_ctl *ctl, pid_t pid,
|
||||
@ -296,7 +263,7 @@ static int __parasite_send_cmd(int sockfd, struct ctl_msg *m)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parasite_wait_ack(int sockfd, unsigned int cmd, struct ctl_msg *m)
|
||||
int parasite_wait_ack(int sockfd, unsigned int cmd, struct ctl_msg *m)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -364,20 +331,6 @@ int parasite_execute_daemon(unsigned int cmd, struct parasite_ctl *ctl)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gen_parasite_saddr(struct sockaddr_un *saddr, int key)
|
||||
{
|
||||
int sun_len;
|
||||
|
||||
saddr->sun_family = AF_UNIX;
|
||||
snprintf(saddr->sun_path, UNIX_PATH_MAX,
|
||||
"X/crtools-pr-%d", key);
|
||||
|
||||
sun_len = SUN_LEN(saddr);
|
||||
*saddr->sun_path = '\0';
|
||||
|
||||
return sun_len;
|
||||
}
|
||||
|
||||
int parasite_send_fd(struct parasite_ctl *ctl, int fd)
|
||||
{
|
||||
if (send_fd(ctl->tsock, NULL, 0, fd) < 0) {
|
||||
@ -418,23 +371,6 @@ static void sigchld_handler(int signal, siginfo_t *siginfo, void *data)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int setup_child_handler(struct parasite_ctl *ctl)
|
||||
{
|
||||
struct sigaction sa = {
|
||||
.sa_sigaction = ctl->ictx.child_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 = {
|
||||
@ -452,121 +388,6 @@ static int restore_child_handler()
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int prepare_tsock(struct parasite_ctl *ctl, pid_t pid,
|
||||
struct parasite_init_args *args)
|
||||
{
|
||||
static int ssock = -1;
|
||||
|
||||
pr_info("Putting tsock into pid %d\n", pid);
|
||||
args->h_addr_len = gen_parasite_saddr(&args->h_addr, getpid());
|
||||
|
||||
if (ssock == -1) {
|
||||
ssock = *ctl->ictx.p_sock;
|
||||
if (ssock == -1) {
|
||||
pr_err("No socket in ictx\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
*ctl->ictx.p_sock = -1;
|
||||
|
||||
if (bind(ssock, (struct sockaddr *)&args->h_addr, args->h_addr_len) < 0) {
|
||||
pr_perror("Can't bind socket");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (listen(ssock, 1)) {
|
||||
pr_perror("Can't listen on transport socket");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check a case when parasite can't initialize a command socket */
|
||||
if (ctl->ictx.flags & INFECT_FAIL_CONNECT)
|
||||
args->h_addr_len = gen_parasite_saddr(&args->h_addr, getpid() + 1);
|
||||
|
||||
/*
|
||||
* Set to -1 to prevent any accidental misuse. The
|
||||
* only valid user of it is accept_tsock().
|
||||
*/
|
||||
ctl->tsock = -ssock;
|
||||
return 0;
|
||||
err:
|
||||
close_safe(&ssock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int accept_tsock(struct parasite_ctl *ctl)
|
||||
{
|
||||
int sock;
|
||||
int ask = -ctl->tsock; /* this '-' is explained above */
|
||||
|
||||
sock = accept(ask, NULL, 0);
|
||||
if (sock < 0) {
|
||||
pr_perror("Can't accept connection to the transport socket");
|
||||
close(ask);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctl->tsock = sock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parasite_init_daemon(struct parasite_ctl *ctl)
|
||||
{
|
||||
struct parasite_init_args *args;
|
||||
pid_t pid = ctl->rpid;
|
||||
user_regs_struct_t regs;
|
||||
struct ctl_msg m = { };
|
||||
|
||||
*ctl->addr_cmd = PARASITE_CMD_INIT_DAEMON;
|
||||
|
||||
args = parasite_args(ctl, struct parasite_init_args);
|
||||
|
||||
args->sigframe = (uintptr_t)ctl->rsigframe;
|
||||
args->log_level = log_get_loglevel();
|
||||
|
||||
futex_set(&args->daemon_connected, 0);
|
||||
|
||||
if (prepare_tsock(ctl, pid, args))
|
||||
goto err;
|
||||
|
||||
/* after this we can catch parasite errors in chld handler */
|
||||
if (setup_child_handler(ctl))
|
||||
goto err;
|
||||
|
||||
regs = ctl->orig.regs;
|
||||
if (parasite_run(pid, PTRACE_CONT, ctl->parasite_ip, ctl->rstack, ®s, &ctl->orig))
|
||||
goto err;
|
||||
|
||||
futex_wait_while_eq(&args->daemon_connected, 0);
|
||||
if (futex_get(&args->daemon_connected) != 1) {
|
||||
errno = -(int)futex_get(&args->daemon_connected);
|
||||
pr_perror("Unable to connect a transport socket");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (accept_tsock(ctl) < 0)
|
||||
goto err;
|
||||
|
||||
if (parasite_send_fd(ctl, log_get_fd()))
|
||||
goto err;
|
||||
|
||||
pr_info("Wait for parasite being daemonized...\n");
|
||||
|
||||
if (parasite_wait_ack(ctl->tsock, PARASITE_CMD_INIT_DAEMON, &m)) {
|
||||
pr_err("Can't switch parasite %d to daemon mode %d\n",
|
||||
pid, m.err);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ctl->sigreturn_addr = args->sigreturn_addr;
|
||||
ctl->daemonized = true;
|
||||
pr_info("Parasite %d has been switched to daemon mode\n", pid);
|
||||
return 0;
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int alloc_groups_copy_creds(CredsEntry *ce, struct parasite_dump_creds *c)
|
||||
{
|
||||
BUILD_BUG_ON(sizeof(ce->groups[0]) != sizeof(c->groups[0]));
|
||||
@ -1426,53 +1247,11 @@ void parasite_ensure_args_size(unsigned long sz)
|
||||
parasite_args_size = sz;
|
||||
}
|
||||
|
||||
static int parasite_start_daemon(struct parasite_ctl *ctl)
|
||||
{
|
||||
pid_t pid = ctl->rpid;
|
||||
struct infect_ctx *ictx = &ctl->ictx;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
if (get_task_regs(pid, ctl->orig.regs, ictx->save_regs, ictx->regs_arg)) {
|
||||
pr_err("Can't obtain regs for thread %d\n", pid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ictx->make_sigframe(ictx->regs_arg, ctl->sigframe, ctl->rsigframe, &ctl->orig.sigmask))
|
||||
return -1;
|
||||
|
||||
if (parasite_init_daemon(ctl))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define init_parasite_ctl(ctl, blob_type) \
|
||||
do { \
|
||||
memcpy(ctl->local_map, parasite_##blob_type##_blob, \
|
||||
sizeof(parasite_##blob_type##_blob)); \
|
||||
ELF_RELOCS_APPLY(parasite_##blob_type, \
|
||||
ctl->local_map, ctl->remote_map); \
|
||||
/* Setup the rest of a control block */ \
|
||||
ctl->parasite_ip = (unsigned long)parasite_sym(ctl->remote_map, \
|
||||
blob_type, __export_parasite_head_start); \
|
||||
ctl->addr_cmd = parasite_sym(ctl->local_map, blob_type, \
|
||||
__export_parasite_cmd); \
|
||||
ctl->addr_args = parasite_sym(ctl->local_map, blob_type, \
|
||||
__export_parasite_args); \
|
||||
} while (0)
|
||||
|
||||
static int make_sigframe(void *arg, struct rt_sigframe *sf, struct rt_sigframe *rtsf, k_rtsigset_t *bs)
|
||||
{
|
||||
return construct_sigframe(sf, rtsf, bs, (CoreEntry *)arg);
|
||||
}
|
||||
|
||||
static int infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size);
|
||||
|
||||
struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
|
||||
struct vm_area_list *vma_area_list)
|
||||
{
|
||||
@ -1507,7 +1286,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
|
||||
parasite_ensure_args_size(dump_pages_args_size(vma_area_list));
|
||||
parasite_ensure_args_size(aio_rings_args_size(vma_area_list));
|
||||
|
||||
if (infect(ctl, item->nr_threads, parasite_args_size) < 0) {
|
||||
if (compel_infect(ctl, item->nr_threads, parasite_args_size) < 0) {
|
||||
parasite_cure_seized(ctl);
|
||||
return NULL;
|
||||
}
|
||||
@ -1519,72 +1298,6 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
|
||||
return ctl;
|
||||
}
|
||||
|
||||
static int infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size)
|
||||
{
|
||||
int ret;
|
||||
unsigned long p, map_exchange_size, parasite_size = 0;
|
||||
|
||||
if (!arch_can_dump_task(ctl))
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
if (seized_native(ctl))
|
||||
parasite_size = pie_size(parasite_native);
|
||||
#ifdef CONFIG_COMPAT
|
||||
else
|
||||
parasite_size = pie_size(parasite_compat);
|
||||
#endif
|
||||
|
||||
ctl->args_size = round_up(args_size, PAGE_SIZE);
|
||||
parasite_size += ctl->args_size;
|
||||
|
||||
map_exchange_size = parasite_size;
|
||||
map_exchange_size += RESTORE_STACK_SIGFRAME + PARASITE_STACK_SIZE;
|
||||
if (nr_threads > 1)
|
||||
map_exchange_size += PARASITE_STACK_SIZE;
|
||||
|
||||
ret = parasite_map_exchange(ctl, map_exchange_size);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
pr_info("Putting parasite blob into %p->%p\n", ctl->local_map, ctl->remote_map);
|
||||
|
||||
if (seized_native(ctl))
|
||||
init_parasite_ctl(ctl, native);
|
||||
#ifdef CONFIG_COMPAT
|
||||
else
|
||||
init_parasite_ctl(ctl, compat);
|
||||
#endif
|
||||
|
||||
p = parasite_size;
|
||||
|
||||
ctl->rsigframe = ctl->remote_map + p;
|
||||
ctl->sigframe = ctl->local_map + p;
|
||||
|
||||
p += RESTORE_STACK_SIGFRAME;
|
||||
p += PARASITE_STACK_SIZE;
|
||||
ctl->rstack = ctl->remote_map + p;
|
||||
|
||||
if (nr_threads > 1) {
|
||||
p += PARASITE_STACK_SIZE;
|
||||
ctl->r_thread_stack = ctl->remote_map + p;
|
||||
}
|
||||
|
||||
if (parasite_start_daemon(ctl))
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ptrace_stop_pie(pid_t pid, void *addr, enum trace_flags *tf)
|
||||
{
|
||||
int ret;
|
||||
|
Loading…
x
Reference in New Issue
Block a user