[CRIU] [PATCH 2/3] ptrace: skip all sigstop (v2)
Andrey Vagin
avagin at openvz.org
Wed Nov 25 08:50:10 PST 2015
From: Andrew Vagin <avagin at virtuozzo.com>
A task can be stopped and has a queued SIGSTOP, in this case we need
to resume the task twice to skip "both" signals.
v2: detect SIGSTOP in shared and per-process queues
Signed-off-by: Andrew Vagin <avagin at virtuozzo.com>
---
ptrace.c | 84 +++++++++++++++++++++++++++++++++++++---------------------------
1 file changed, 49 insertions(+), 35 deletions(-)
diff --git a/ptrace.c b/ptrace.c
index 59c5955..9c2b3cc 100644
--- a/ptrace.c
+++ b/ptrace.c
@@ -102,6 +102,45 @@ int seize_catch_task(pid_t pid)
return ret;
}
+static int skip_sigstop(int pid, int nr_signals)
+{
+ int i, status, ret;
+
+ /*
+ * 1) SIGSTOP is queued, but isn't handled yet:
+ * SGISTOP can't be blocked, so we need to wait when the kernel
+ * handles this signal.
+ *
+ * Otherwise the process will be stopped immediatly after
+ * starting it.
+ *
+ * 2) A seized task was stopped:
+ * PTRACE_SEIZE doesn't affect signal or group stop state.
+ * Currently ptrace reported that task is in stopped state.
+ * We need to start task again, and it will be trapped
+ * immediately, because we sent PTRACE_INTERRUPT to it.
+ */
+ for (i = 0; i < nr_signals; i++) {
+ ret = ptrace(PTRACE_CONT, pid, 0, 0);
+ if (ret) {
+ pr_perror("Unable to start process");
+ return -1;
+ }
+
+ ret = wait4(pid, &status, __WALL, NULL);
+ if (ret < 0) {
+ pr_perror("SEIZE %d: can't wait task", pid);
+ return -1;
+ }
+
+ if (!WIFSTOPPED(status)) {
+ pr_err("SEIZE %d: task not stopped after seize\n", pid);
+ return -1;
+ }
+ }
+ return 0;
+}
+
/*
* This routine seizes task putting it into a special
* state where we can manipulate the task via ptrace
@@ -112,7 +151,7 @@ int seize_catch_task(pid_t pid)
int seize_wait_task(pid_t pid, pid_t ppid, struct proc_status_creds **creds)
{
siginfo_t si;
- int status;
+ int status, nr_sigstop;
int ret = 0, ret2, wait_errno = 0;
struct proc_status_creds cr;
@@ -204,42 +243,17 @@ try_again:
if (cr.seccomp_mode != SECCOMP_MODE_DISABLED && suspend_seccomp(pid) < 0)
goto err;
- if ((cr.sigpnd | cr.shdpnd) & (1 << (SIGSTOP - 1)) || si.si_signo == SIGSTOP) {
- /*
- * 1) SIGSTOP is queued, but isn't handled yet:
- * SGISTOP can't be blocked, so we need to wait when the kernel
- * handles this signal.
- *
- * Otherwise the process will be stopped immediatly after
- * starting it.
- *
- * 2) A seized task was stopped:
- * PTRACE_SEIZE doesn't affect signal or group stop state.
- * Currently ptrace reported that task is in stopped state.
- * We need to start task again, and it will be trapped
- * immediately, because we sent PTRACE_INTERRUPT to it.
- */
- ret = ptrace(PTRACE_CONT, pid, 0, 0);
- if (ret) {
- pr_perror("Unable to start process");
- goto err_stop;
- }
-
- ret = wait4(pid, &status, __WALL, NULL);
- if (ret < 0) {
- pr_perror("SEIZE %d: can't wait task", pid);
- goto err_stop;
- }
+ nr_sigstop = 0;
+ if (cr.sigpnd & (1 << (SIGSTOP - 1)))
+ nr_sigstop++;
+ if (cr.shdpnd & (1 << (SIGSTOP - 1)))
+ nr_sigstop++;
+ if (si.si_signo == SIGSTOP)
+ nr_sigstop++;
- if (ret != pid) {
- pr_err("SEIZE %d: wrong task attached (%d)\n", pid, ret);
+ if (nr_sigstop) {
+ if (skip_sigstop(pid, nr_sigstop))
goto err_stop;
- }
-
- if (!WIFSTOPPED(status)) {
- pr_err("SEIZE %d: task not stopped after seize\n", pid);
- goto err_stop;
- }
return TASK_STOPPED;
}
--
2.4.3
More information about the CRIU
mailing list