[CRIU] [PATCH 4/8] parasite: block signals for each parasite command
Andrey Vagin
avagin at openvz.org
Thu Jul 11 05:46:51 EDT 2013
Pending signals should be saved, so signals should be blocked.
Signals are blocked for EACH command, because a chance of destroying a
process state should be a small as possible.
If crtools is killed between two commands, a dumped process will run
continue.
Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
arch/arm/crtools.c | 2 +-
arch/x86/crtools.c | 2 +-
include/parasite-syscall.h | 3 +-
parasite-syscall.c | 137 +++++++++++++++++----------------------------
4 files changed, 54 insertions(+), 90 deletions(-)
diff --git a/arch/arm/crtools.c b/arch/arm/crtools.c
index 2ca59d1..bbc5cf9 100644
--- a/arch/arm/crtools.c
+++ b/arch/arm/crtools.c
@@ -75,7 +75,7 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret,
parasite_setup_regs(ctl->syscall_ip, 0, ®s);
err = __parasite_execute_trap(ctl, ctl->pid.real, ®s,
- &ctl->regs_orig, 0);
+ &ctl->regs_orig, &ctl->sig_blocked);
if (err)
return err;
diff --git a/arch/x86/crtools.c b/arch/x86/crtools.c
index 9b7cca5..c8c9433 100644
--- a/arch/x86/crtools.c
+++ b/arch/x86/crtools.c
@@ -102,7 +102,7 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret,
parasite_setup_regs(ctl->syscall_ip, 0, ®s);
err = __parasite_execute_trap(ctl, ctl->pid.real, ®s,
- &ctl->regs_orig, 0);
+ &ctl->regs_orig, &ctl->sig_blocked);
if (err)
return err;
diff --git a/include/parasite-syscall.h b/include/parasite-syscall.h
index 3157e27..fb1236d 100644
--- a/include/parasite-syscall.h
+++ b/include/parasite-syscall.h
@@ -29,7 +29,6 @@ struct parasite_ctl {
user_regs_struct_t regs_orig; /* original registers */
k_rtsigset_t sig_blocked;
- bool use_sig_blocked;
void *rstack; /* thread leader stack*/
struct rt_sigframe *sigframe;
@@ -105,7 +104,7 @@ extern int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret,
extern int __parasite_execute_trap(struct parasite_ctl *ctl, pid_t pid,
user_regs_struct_t *regs,
user_regs_struct_t *regs_orig,
- bool signals_blocked);
+ k_rtsigset_t *sigmask);
extern bool arch_can_dump_task(pid_t pid);
extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
diff --git a/parasite-syscall.c b/parasite-syscall.c
index 48b4328..2b9877c 100644
--- a/parasite-syscall.c
+++ b/parasite-syscall.c
@@ -69,13 +69,19 @@ static struct vma_area *get_vma_by_ip(struct list_head *vma_area_list, unsigned
int __parasite_execute_trap(struct parasite_ctl *ctl, pid_t pid,
user_regs_struct_t *regs,
user_regs_struct_t *regs_orig,
- bool signals_blocked)
+ k_rtsigset_t *sigmask)
{
+ k_rtsigset_t blockall;
siginfo_t siginfo;
int status;
int ret = -1;
-again:
+ ksigfillset(&blockall);
+ if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), &blockall)) {
+ pr_perror("Can't block signals");
+ return -1;
+ }
+
if (ptrace(PTRACE_SETREGS, pid, NULL, regs)) {
pr_perror("Can't set registers (pid: %d)", pid);
goto err;
@@ -112,75 +118,11 @@ again:
}
if (WSTOPSIG(status) != SIGTRAP || siginfo.si_code != ARCH_SI_TRAP) {
-retry_signal:
pr_debug("** delivering signal %d si_code=%d\n",
siginfo.si_signo, siginfo.si_code);
- if (signals_blocked) {
- pr_err("Unexpected %d task interruption, aborting\n", pid);
- goto err;
- }
-
- /* FIXME: jerr(siginfo.si_code > 0, err_restore); */
-
- /*
- * 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, regs_orig)) {
- pr_perror("Can't set registers (pid: %d)", pid);
- goto err;
- }
-
- if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL)) {
- pr_perror("Can't interrupt (pid: %d)", pid);
- goto err;
- }
-
- if (ptrace(PTRACE_CONT, pid, NULL, (void *)(unsigned long)siginfo.si_signo)) {
- pr_perror("Can't continue (pid: %d)", pid);
- goto err;
- }
-
- if (wait4(pid, &status, __WALL, NULL) != pid) {
- pr_perror("Waited pid mismatch (pid: %d)", pid);
- goto err;
- }
-
- if (!WIFSTOPPED(status)) {
- pr_err("Task is still running (pid: %d)\n", pid);
- goto err;
- }
-
- if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo)) {
- pr_perror("Can't get siginfo (pid: %d)", pid);
- goto err;
- }
-
- if (SI_EVENT(siginfo.si_code) != PTRACE_EVENT_STOP)
- goto retry_signal;
-
- /*
- * Signal is delivered, so we should update
- * original registers.
- */
- {
- user_regs_struct_t r;
- if (ptrace(PTRACE_GETREGS, pid, NULL, &r)) {
- pr_perror("Can't obtain registers (pid: %d)", pid);
- goto err;
- }
- *regs_orig = r;
- }
-
- goto again;
+ pr_err("Unexpected %d task interruption, aborting\n", pid);
+ goto err;
}
/*
@@ -189,6 +131,10 @@ retry_signal:
*/
ret = 0;
err:
+ if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), &sigmask)) {
+ pr_perror("Can't block signals");
+ ret = -1;
+ }
return ret;
}
@@ -201,7 +147,8 @@ void *parasite_args_s(struct parasite_ctl *ctl, int args_size)
static int parasite_execute_trap_by_pid(unsigned int cmd,
struct parasite_ctl *ctl, pid_t pid,
user_regs_struct_t *regs_orig,
- void *stack, bool use_sig_blocked)
+ void *stack,
+ k_rtsigset_t *sigmask)
{
user_regs_struct_t regs = *regs_orig;
int ret;
@@ -210,7 +157,7 @@ static int parasite_execute_trap_by_pid(unsigned int cmd,
parasite_setup_regs(ctl->parasite_ip, stack, ®s);
- ret = __parasite_execute_trap(ctl, pid, ®s, regs_orig, use_sig_blocked);
+ ret = __parasite_execute_trap(ctl, pid, ®s, regs_orig, sigmask);
if (ret == 0)
ret = (int)REG_RES(regs);
@@ -228,8 +175,9 @@ static int parasite_execute_trap_by_pid(unsigned int cmd,
static int parasite_execute_trap(unsigned int cmd, struct parasite_ctl *ctl)
{
- return parasite_execute_trap_by_pid(cmd, ctl, ctl->pid.real, &ctl->regs_orig,
- ctl->rstack, ctl->use_sig_blocked);
+ return parasite_execute_trap_by_pid(cmd, ctl, ctl->pid.real,
+ &ctl->regs_orig, ctl->rstack,
+ &ctl->sig_blocked);
}
static int __parasite_send_cmd(int sockfd, struct ctl_msg *m)
@@ -444,9 +392,6 @@ static int parasite_init(struct parasite_ctl *ctl, pid_t pid, struct pstree_item
goto err;
}
- ctl->sig_blocked = args->sig_blocked;
- ctl->use_sig_blocked = true;
-
sock = accept_tsock();
if (sock < 0)
goto err;
@@ -462,6 +407,9 @@ static int parasite_daemonize(struct parasite_ctl *ctl)
pid_t pid = ctl->pid.real;
user_regs_struct_t regs;
struct ctl_msg m = { };
+ k_rtsigset_t blockall;
+
+ ksigfillset(&blockall);
*ctl->addr_cmd = PARASITE_CMD_DAEMONIZE;
@@ -473,6 +421,11 @@ static int parasite_daemonize(struct parasite_ctl *ctl)
goto err;
}
+ if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), &blockall)) {
+ pr_perror("Can't block signals");
+ goto err;
+ }
+
if (ptrace(PTRACE_CONT, pid, NULL, NULL)) {
pr_perror("Can't continue (pid: %d)\n", pid);
ptrace(PTRACE_SETREGS, pid, NULL, ctl->regs_orig);
@@ -492,6 +445,9 @@ static int parasite_daemonize(struct parasite_ctl *ctl)
return 0;
err:
+ if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), ctl->sig_blocked))
+ pr_perror("Can't block signals");
+
return -1;
}
@@ -507,6 +463,14 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
args = parasite_args(ctl, struct parasite_dump_thread);
+ ret = ptrace(PTRACE_GETSIGMASK, pid, sizeof(k_rtsigset_t),
+ &core->thread_core->blk_sigset);
+ if (ret) {
+ pr_perror("ptrace can't get signal blocking mask for %d", pid);
+ return -1;
+ }
+ core->thread_core->has_blk_sigset = true;
+
ret = ptrace(PTRACE_GETREGS, pid, NULL, ®s_orig);
if (ret) {
pr_perror("Can't obtain registers (pid: %d)", pid);
@@ -515,7 +479,8 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
ret = parasite_execute_trap_by_pid(PARASITE_CMD_INIT_THREAD, ctl,
pid, ®s_orig,
- ctl->r_thread_stack, false);
+ ctl->r_thread_stack,
+ (k_rtsigset_t *) &core->thread_core->blk_sigset);
if (ret) {
pr_err("Can't init thread in parasite %d\n", pid);
return -1;
@@ -527,17 +492,14 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
if (parasite_execute_trap_by_pid(PARASITE_CMD_FINI_THREAD, ctl,
pid, ®s_orig,
- ctl->r_thread_stack, true)) {
+ ctl->r_thread_stack,
+ (k_rtsigset_t *) &core->thread_core->blk_sigset)) {
pr_err("Can't init thread in parasite %d\n", pid);
return -1;
}
if (ret)
return -1;
- memcpy(&core->thread_core->blk_sigset,
- &args->blocked, sizeof(k_rtsigset_t));
- core->thread_core->has_blk_sigset = true;
-
BUG_ON(!core->thread_core->sas);
copy_sas(core->thread_core->sas, &args->sas);
@@ -859,8 +821,6 @@ static int parasite_fini_seized(struct parasite_ctl *ctl)
}
}
- ctl->use_sig_blocked = false;
-
ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
if (ret) {
pr_perror("ptrace");
@@ -957,6 +917,11 @@ struct parasite_ctl *parasite_prep_ctl(pid_t pid, struct vm_area_list *vma_area_
ctl->tsock = -1;
+ if (ptrace(PTRACE_GETSIGMASK, pid, sizeof(k_rtsigset_t), &ctl->sig_blocked)) {
+ pr_perror("ptrace doesn't support PTRACE_GETSIGMASK\n");
+ goto err;
+ }
+
if (ptrace(PTRACE_GETREGS, pid, NULL, &ctl->regs_orig)) {
pr_err("Can't obtain registers (pid: %d)\n", pid);
goto err;
@@ -1065,6 +1030,9 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
map_exchange_size += RESTORE_STACK_SIGFRAME + PARASITE_STACK_SIZE;
if (item->nr_threads > 1)
map_exchange_size += PARASITE_STACK_SIZE;
+
+ memcpy(&item->core[0]->tc->blk_sigset, &ctl->sig_blocked, sizeof(k_rtsigset_t));
+
ret = parasite_map_exchange(ctl, map_exchange_size);
if (ret)
goto err_restore;
@@ -1110,9 +1078,6 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
goto err_restore;
}
- memcpy(&item->core[0]->tc->blk_sigset,
- &ctl->sig_blocked, sizeof(k_rtsigset_t));
-
if (construct_sigframe(ctl->sigframe, ctl->rsigframe, item->core[0]))
goto err_restore;
--
1.8.3.1
More information about the CRIU
mailing list