Commit 3a53b589 authored by Pavel Emelyanov's avatar Pavel Emelyanov Committed by Andrei Vagin

infect: Move parasite_stop_daemon and parasite_cure_* into infect.c

Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
parent e156ab5a
...@@ -1187,7 +1187,7 @@ static int pre_dump_one_task(struct pstree_item *item) ...@@ -1187,7 +1187,7 @@ static int pre_dump_one_task(struct pstree_item *item)
if (ret) if (ret)
goto err_cure; goto err_cure;
if (parasite_cure_remote(parasite_ctl)) if (compel_cure_remote(parasite_ctl))
pr_err("Can't cure (pid: %d) from parasite\n", pid); pr_err("Can't cure (pid: %d) from parasite\n", pid);
err_free: err_free:
free_mappings(&vmas); free_mappings(&vmas);
...@@ -1195,7 +1195,7 @@ err: ...@@ -1195,7 +1195,7 @@ err:
return ret; return ret;
err_cure: err_cure:
if (parasite_cure_seized(parasite_ctl)) if (compel_cure(parasite_ctl))
pr_err("Can't cure (pid: %d) from parasite\n", pid); pr_err("Can't cure (pid: %d) from parasite\n", pid);
goto err_free; goto err_free;
} }
...@@ -1370,7 +1370,7 @@ static int dump_one_task(struct pstree_item *item) ...@@ -1370,7 +1370,7 @@ static int dump_one_task(struct pstree_item *item)
goto err_cure; goto err_cure;
} }
ret = parasite_stop_daemon(parasite_ctl); ret = compel_stop_daemon(parasite_ctl);
if (ret) { if (ret) {
pr_err("Can't cure (pid: %d) from parasite\n", pid); pr_err("Can't cure (pid: %d) from parasite\n", pid);
goto err; goto err;
...@@ -1382,7 +1382,7 @@ static int dump_one_task(struct pstree_item *item) ...@@ -1382,7 +1382,7 @@ static int dump_one_task(struct pstree_item *item)
goto err; goto err;
} }
ret = parasite_cure_seized(parasite_ctl); ret = compel_cure(parasite_ctl);
if (ret) { if (ret) {
pr_err("Can't cure (pid: %d) from parasite\n", pid); pr_err("Can't cure (pid: %d) from parasite\n", pid);
goto err; goto err;
...@@ -1411,7 +1411,7 @@ err: ...@@ -1411,7 +1411,7 @@ err:
err_cure: err_cure:
close_cr_imgset(&cr_imgset); close_cr_imgset(&cr_imgset);
err_cure_imgset: err_cure_imgset:
parasite_cure_seized(parasite_ctl); compel_cure(parasite_ctl);
goto err; goto err;
} }
...@@ -1488,7 +1488,7 @@ static int cr_pre_dump_finish(int ret) ...@@ -1488,7 +1488,7 @@ static int cr_pre_dump_finish(int ret)
timing_stop(TIME_MEMWRITE); timing_stop(TIME_MEMWRITE);
destroy_page_pipe(mem_pp); destroy_page_pipe(mem_pp);
parasite_cure_local(ctl); compel_cure_local(ctl);
} }
free_pstree(root_item); free_pstree(root_item);
......
...@@ -191,7 +191,7 @@ int cr_exec(int pid, char **opt) ...@@ -191,7 +191,7 @@ int cr_exec(int pid, char **opt)
exit_code = 0; exit_code = 0;
out_cure: out_cure:
parasite_cure_seized(ctl); compel_cure(ctl);
out_unseize: out_unseize:
unseize_task(pid, prev_state, prev_state); unseize_task(pid, prev_state, prev_state);
out: out:
......
...@@ -30,4 +30,8 @@ extern struct parasite_ctl *compel_prepare(int pid); ...@@ -30,4 +30,8 @@ extern struct parasite_ctl *compel_prepare(int pid);
extern int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size); extern int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size);
extern int compel_prepare_thread(int pid, struct thread_ctx *ctx); extern int compel_prepare_thread(int pid, struct thread_ctx *ctx);
extern int compel_stop_daemon(struct parasite_ctl *ctl);
extern int compel_cure_remote(struct parasite_ctl *ctl);
extern int compel_cure_local(struct parasite_ctl *ctl);
extern int compel_cure(struct parasite_ctl *ctl);
#endif #endif
...@@ -90,9 +90,6 @@ extern int parasite_drain_fds_seized(struct parasite_ctl *ctl, ...@@ -90,9 +90,6 @@ extern int parasite_drain_fds_seized(struct parasite_ctl *ctl,
int *lfds, struct fd_opts *flags); int *lfds, struct fd_opts *flags);
extern int parasite_get_proc_fd_seized(struct parasite_ctl *ctl); extern int parasite_get_proc_fd_seized(struct parasite_ctl *ctl);
extern int parasite_cure_remote(struct parasite_ctl *ctl);
extern int parasite_cure_local(struct parasite_ctl *ctl);
extern int parasite_cure_seized(struct parasite_ctl *ctl);
extern struct parasite_ctl *parasite_infect_seized(pid_t pid, extern struct parasite_ctl *parasite_infect_seized(pid_t pid,
struct pstree_item *item, struct pstree_item *item,
struct vm_area_list *vma_area_list); struct vm_area_list *vma_area_list);
...@@ -129,7 +126,6 @@ enum trace_flags { ...@@ -129,7 +126,6 @@ enum trace_flags {
TRACE_EXIT, TRACE_EXIT,
}; };
extern int parasite_stop_daemon(struct parasite_ctl *ctl);
extern int parasite_stop_on_syscall(int tasks, int sys_nr, extern int parasite_stop_on_syscall(int tasks, int sys_nr,
int sys_nr_compat, enum trace_flags trace); int sys_nr_compat, enum trace_flags trace);
extern int parasite_unmap(struct parasite_ctl *ctl, unsigned long addr); extern int parasite_unmap(struct parasite_ctl *ctl, unsigned long addr);
......
...@@ -318,6 +318,23 @@ static int setup_child_handler(struct parasite_ctl *ctl) ...@@ -318,6 +318,23 @@ static int setup_child_handler(struct parasite_ctl *ctl)
return 0; return 0;
} }
static int restore_child_handler()
{
struct sigaction sa = {
.sa_handler = SIG_DFL, /* XXX -- should be original? */
.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, int parasite_run(pid_t pid, int cmd, unsigned long ip, void *stack,
user_regs_struct_t *regs, struct thread_ctx *octx) user_regs_struct_t *regs, struct thread_ctx *octx)
{ {
...@@ -574,3 +591,158 @@ err: ...@@ -574,3 +591,158 @@ err:
return NULL; return NULL;
} }
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;
}
static int parasite_fini_seized(struct parasite_ctl *ctl)
{
pid_t pid = ctl->rpid;
user_regs_struct_t regs;
int status, ret = 0;
enum trace_flags flag;
/* stop getting chld from parasite -- we're about to step-by-step it */
if (restore_child_handler())
return -1;
/* Start to trace syscalls for each thread */
if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL)) {
pr_perror("Unable to interrupt the process");
return -1;
}
pr_debug("Waiting for %d to trap\n", pid);
if (wait4(pid, &status, __WALL, NULL) != pid) {
pr_perror("Waited pid mismatch (pid: %d)", pid);
return -1;
}
pr_debug("Daemon %d exited trapping\n", pid);
if (!WIFSTOPPED(status)) {
pr_err("Task is still running (pid: %d)\n", pid);
return -1;
}
ret = ptrace_get_regs(pid, &regs);
if (ret) {
pr_perror("Unable to get registers");
return -1;
}
if (!task_in_parasite(ctl, &regs)) {
pr_err("The task is not in parasite code\n");
return -1;
}
ret = __parasite_execute_daemon(PARASITE_CMD_FINI, ctl);
close_safe(&ctl->tsock);
if (ret)
return -1;
/* Go to sigreturn as closer as we can */
ret = ptrace_stop_pie(pid, ctl->sigreturn_addr, &flag);
if (ret < 0)
return ret;
if (parasite_stop_on_syscall(1, __NR(rt_sigreturn, 0),
__NR(rt_sigreturn, 1), flag))
return -1;
if (ptrace_flush_breakpoints(pid))
return -1;
/*
* 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.
*/
return 0;
}
int compel_stop_daemon(struct parasite_ctl *ctl)
{
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;
if (parasite_fini_seized(ctl)) {
close_safe(&ctl->tsock);
return -1;
}
}
ctl->daemonized = false;
return 0;
}
int compel_cure_remote(struct parasite_ctl *ctl)
{
if (compel_stop_daemon(ctl))
return -1;
if (!ctl->remote_map)
return 0;
/* Unseizing task with parasite -- it does it himself */
if (ctl->addr_cmd) {
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))
return -1;
} else {
unsigned long ret;
syscall_seized(ctl, __NR(munmap, !seized_native(ctl)), &ret,
(unsigned long)ctl->remote_map, ctl->map_length,
0, 0, 0, 0);
if (ret) {
pr_err("munmap for remote map %p, %lu returned %lu\n",
ctl->remote_map, ctl->map_length, ret);
return -1;
}
}
return 0;
}
int compel_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->rpid);
ret = -1;
}
}
free(ctl);
return ret;
}
int compel_cure(struct parasite_ctl *ctl)
{
int ret;
ret = compel_cure_remote(ctl);
if (!ret)
ret = compel_cure_local(ctl);
return ret;
}
...@@ -356,23 +356,6 @@ static void sigchld_handler(int signal, siginfo_t *siginfo, void *data) ...@@ -356,23 +356,6 @@ static void sigchld_handler(int signal, siginfo_t *siginfo, void *data)
exit(1); exit(1);
} }
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;
}
static int alloc_groups_copy_creds(CredsEntry *ce, struct parasite_dump_creds *c) static int alloc_groups_copy_creds(CredsEntry *ce, struct parasite_dump_creds *c)
{ {
BUILD_BUG_ON(sizeof(ce->groups[0]) != sizeof(c->groups[0])); BUILD_BUG_ON(sizeof(ce->groups[0]) != sizeof(c->groups[0]));
...@@ -766,79 +749,6 @@ int parasite_get_proc_fd_seized(struct parasite_ctl *ctl) ...@@ -766,79 +749,6 @@ int parasite_get_proc_fd_seized(struct parasite_ctl *ctl)
/* This is officially the 50000'th line in the CRIU source code */ /* This is officially the 50000'th line in the CRIU source code */
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;
}
static int parasite_fini_seized(struct parasite_ctl *ctl)
{
pid_t pid = ctl->rpid;
user_regs_struct_t regs;
int status, ret = 0;
enum trace_flags flag;
/* stop getting chld from parasite -- we're about to step-by-step it */
if (restore_child_handler())
return -1;
/* Start to trace syscalls for each thread */
if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL)) {
pr_perror("Unable to interrupt the process");
return -1;
}
pr_debug("Waiting for %d to trap\n", pid);
if (wait4(pid, &status, __WALL, NULL) != pid) {
pr_perror("Waited pid mismatch (pid: %d)", pid);
return -1;
}
pr_debug("Daemon %d exited trapping\n", pid);
if (!WIFSTOPPED(status)) {
pr_err("Task is still running (pid: %d)\n", pid);
return -1;
}
ret = ptrace_get_regs(pid, &regs);
if (ret) {
pr_perror("Unable to get registers");
return -1;
}
if (!task_in_parasite(ctl, &regs)) {
pr_err("The task is not in parasite code\n");
return -1;
}
ret = __parasite_execute_daemon(PARASITE_CMD_FINI, ctl);
close_safe(&ctl->tsock);
if (ret)
return -1;
/* Go to sigreturn as closer as we can */
ret = ptrace_stop_pie(pid, ctl->sigreturn_addr, &flag);
if (ret < 0)
return ret;
if (parasite_stop_on_syscall(1, __NR(rt_sigreturn, 0),
__NR(rt_sigreturn, 1), flag))
return -1;
if (ptrace_flush_breakpoints(pid))
return -1;
/*
* 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.
*/
return 0;
}
static bool task_is_trapped(int status, pid_t pid) static bool task_is_trapped(int status, pid_t pid)
{ {
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP)
...@@ -950,88 +860,6 @@ goon: ...@@ -950,88 +860,6 @@ goon:
return 0; return 0;
} }
int parasite_stop_daemon(struct parasite_ctl *ctl)
{
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;
if (parasite_fini_seized(ctl)) {
close_safe(&ctl->tsock);
return -1;
}
}
ctl->daemonized = false;
return 0;
}
int parasite_cure_remote(struct parasite_ctl *ctl)
{
if (parasite_stop_daemon(ctl))
return -1;
if (!ctl->remote_map)
return 0;
/* Unseizing task with parasite -- it does it himself */
if (ctl->addr_cmd) {
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))
return -1;
} else {
unsigned long ret;
syscall_seized(ctl, __NR(munmap, !seized_native(ctl)), &ret,
(unsigned long)ctl->remote_map, ctl->map_length,
0, 0, 0, 0);
if (ret) {
pr_err("munmap for remote map %p, %lu returned %lu\n",
ctl->remote_map, ctl->map_length, ret);
return -1;
}
}
return 0;
}
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->rpid);
ret = -1;
}
}
free(ctl);
return ret;
}
int parasite_cure_seized(struct parasite_ctl *ctl)
{
int ret;
ret = parasite_cure_remote(ctl);
if (!ret)
ret = parasite_cure_local(ctl);
return ret;
}
/* /*
* parasite_unmap() is used for unmapping parasite and restorer blobs. * parasite_unmap() is used for unmapping parasite and restorer blobs.
* A blob can contain code for unmapping itself, so the porcess is * A blob can contain code for unmapping itself, so the porcess is
...@@ -1242,7 +1070,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ...@@ -1242,7 +1070,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
parasite_ensure_args_size(aio_rings_args_size(vma_area_list)); parasite_ensure_args_size(aio_rings_args_size(vma_area_list));
if (compel_infect(ctl, item->nr_threads, parasite_args_size) < 0) { if (compel_infect(ctl, item->nr_threads, parasite_args_size) < 0) {
parasite_cure_seized(ctl); compel_cure(ctl);
return NULL; return NULL;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment