Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/checkpoint-restore/criu.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrei Vagin <avagin@gmail.com>2022-08-08 02:27:22 +0300
committerAndrei Vagin <avagin@gmail.com>2022-08-15 08:23:49 +0300
commit373281f50dfa9069058aa0bfde05c4f4a40ddd8a (patch)
treeccaf1a767fbb94524bf62394f84a1c24f54228f3
parent24100795a3de6192cc2e17f15ceccd09145d71a4 (diff)
compel: set TRACESYSGOOD to distinguish breakpoints from syscalls
When delivering system call traps, set bit 7 in the signal number (i.e., deliver SIGTRAP|0x80). This makes it easy for the tracer to distinguish normal traps from those caused by a system call. Signed-off-by: Andrei Vagin <avagin@gmail.com>
-rw-r--r--compel/include/ptrace.h2
-rw-r--r--compel/include/uapi/infect.h4
-rw-r--r--compel/src/lib/infect.c27
-rw-r--r--compel/src/lib/ptrace.c2
-rw-r--r--criu/cr-restore.c13
5 files changed, 27 insertions, 21 deletions
diff --git a/compel/include/ptrace.h b/compel/include/ptrace.h
index bf2701e63..00013f937 100644
--- a/compel/include/ptrace.h
+++ b/compel/include/ptrace.h
@@ -5,6 +5,8 @@
#include <compel/asm/infect-types.h>
#include <compel/ptrace.h>
+#define PTRACE_SYSCALL_TRAP 0x80
+
#define PTRACE_SI_EVENT(_si_code) (((_si_code)&0xFFFF) >> 8)
extern int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs);
diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h
index 7073f343f..19d4da2b1 100644
--- a/compel/include/uapi/infect.h
+++ b/compel/include/uapi/infect.h
@@ -80,9 +80,9 @@ enum trace_flags {
TRACE_EXIT,
};
-extern int __must_check compel_stop_on_syscall(int tasks, int sys_nr, int sys_nr_compat, enum trace_flags trace);
+extern int __must_check compel_stop_on_syscall(int tasks, int sys_nr, int sys_nr_compat);
-extern int __must_check compel_stop_pie(pid_t pid, void *addr, enum trace_flags *tf, bool no_bp);
+extern int __must_check compel_stop_pie(pid_t pid, void *addr, bool no_bp);
extern int __must_check compel_unmap(struct parasite_ctl *ctl, unsigned long addr);
diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c
index b99f23b36..7d7865480 100644
--- a/compel/src/lib/infect.c
+++ b/compel/src/lib/infect.c
@@ -304,6 +304,11 @@ try_again:
goto try_again;
}
+ if (ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACESYSGOOD)) {
+ pr_perror("Unable to set PTRACE_O_TRACESYSGOOD for %d", pid);
+ return -1;
+ }
+
if (ss->seccomp_mode != SECCOMP_MODE_DISABLED && ptrace_suspend_seccomp(pid) < 0)
goto err;
@@ -1366,7 +1371,6 @@ 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(ctl))
@@ -1407,11 +1411,11 @@ static int parasite_fini_seized(struct parasite_ctl *ctl)
return -1;
/* Go to sigreturn as closer as we can */
- ret = compel_stop_pie(pid, ctl->sigreturn_addr, &flag, ctl->ictx.flags & INFECT_NO_BREAKPOINTS);
+ ret = compel_stop_pie(pid, ctl->sigreturn_addr, ctl->ictx.flags & INFECT_NO_BREAKPOINTS);
if (ret < 0)
return ret;
- if (compel_stop_on_syscall(1, __NR(rt_sigreturn, 0), __NR(rt_sigreturn, 1), flag))
+ if (compel_stop_on_syscall(1, __NR(rt_sigreturn, 0), __NR(rt_sigreturn, 1)))
return -1;
if (ptrace_flush_breakpoints(pid))
@@ -1546,7 +1550,7 @@ int compel_unmap(struct parasite_ctl *ctl, unsigned long addr)
if (ret)
goto err;
- ret = compel_stop_on_syscall(1, __NR(munmap, 0), __NR(munmap, 1), TRACE_ENTER);
+ ret = compel_stop_on_syscall(1, __NR(munmap, 0), __NR(munmap, 1));
/*
* Don't touch extended registers here: they were restored
@@ -1558,7 +1562,7 @@ err:
return ret;
}
-int compel_stop_pie(pid_t pid, void *addr, enum trace_flags *tf, bool no_bp)
+int compel_stop_pie(pid_t pid, void *addr, bool no_bp)
{
int ret;
@@ -1575,7 +1579,6 @@ int compel_stop_pie(pid_t pid, void *addr, enum trace_flags *tf, bool no_bp)
* PIE will stop on a breakpoint, next
* stop after that will be syscall enter.
*/
- *tf = TRACE_EXIT;
return 0;
}
@@ -1588,14 +1591,12 @@ int compel_stop_pie(pid_t pid, void *addr, enum trace_flags *tf, bool no_bp)
pr_perror("Unable to restart the %d process", pid);
return -1;
}
-
- *tf = TRACE_ENTER;
return 0;
}
static bool task_is_trapped(int status, pid_t pid)
{
- if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP)
+ if (WIFSTOPPED(status) && (WSTOPSIG(status) & ~PTRACE_SYSCALL_TRAP) == SIGTRAP)
return true;
pr_err("Task %d is in unexpected state: %x\n", pid, status);
@@ -1629,15 +1630,13 @@ static inline int is_required_syscall(user_regs_struct_t *regs, pid_t pid, const
* sys_nr - the required syscall number
* sys_nr_compat - the required compatible syscall number
*/
-int compel_stop_on_syscall(int tasks, const int sys_nr, const int sys_nr_compat, enum trace_flags trace)
+int compel_stop_on_syscall(int tasks, const int sys_nr, const int sys_nr_compat)
{
+ enum trace_flags trace = tasks > 1 ? TRACE_ALL : TRACE_ENTER;
user_regs_struct_t regs;
int status, ret;
pid_t pid;
- if (tasks > 1)
- trace = TRACE_ALL;
-
/* Stop all threads on the enter point in sys_rt_sigreturn */
while (tasks) {
pid = wait4(-1, &status, __WALL, NULL);
@@ -1651,6 +1650,8 @@ int compel_stop_on_syscall(int tasks, const int sys_nr, const int sys_nr_compat,
pr_debug("%d was trapped\n", pid);
+ if ((WSTOPSIG(status) & PTRACE_SYSCALL_TRAP) == 0)
+ goto goon;
if (trace == TRACE_EXIT) {
trace = TRACE_ENTER;
pr_debug("`- Expecting exit\n");
diff --git a/compel/src/lib/ptrace.c b/compel/src/lib/ptrace.c
index 49b685d70..717ee2839 100644
--- a/compel/src/lib/ptrace.c
+++ b/compel/src/lib/ptrace.c
@@ -23,7 +23,7 @@
int ptrace_suspend_seccomp(pid_t pid)
{
- if (ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_SUSPEND_SECCOMP) < 0) {
+ if (ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_SUSPEND_SECCOMP | PTRACE_O_TRACESYSGOOD) < 0) {
pr_perror("suspending seccomp failed");
return -1;
}
diff --git a/criu/cr-restore.c b/criu/cr-restore.c
index 919d10ab5..9a1b23999 100644
--- a/criu/cr-restore.c
+++ b/criu/cr-restore.c
@@ -1964,6 +1964,10 @@ static int attach_to_tasks(bool root_seized)
return -1;
}
+ if (ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACESYSGOOD)) {
+ pr_perror("Unable to set PTRACE_O_TRACESYSGOOD for %d", pid);
+ return -1;
+ }
/*
* Suspend seccomp if necessary. We need to do this because
* although seccomp is restored at the very end of the
@@ -2028,7 +2032,7 @@ static int restore_rseq_cs(void)
return 0;
}
-static int catch_tasks(bool root_seized, enum trace_flags *flag)
+static int catch_tasks(bool root_seized)
{
struct pstree_item *item;
@@ -2058,7 +2062,7 @@ static int catch_tasks(bool root_seized, enum trace_flags *flag)
return -1;
}
- ret = compel_stop_pie(pid, rsti(item)->breakpoint, flag, fault_injected(FI_NO_BREAKPOINTS));
+ ret = compel_stop_pie(pid, rsti(item)->breakpoint, fault_injected(FI_NO_BREAKPOINTS));
if (ret < 0)
return -1;
}
@@ -2225,7 +2229,6 @@ static void reap_zombies(void)
static int restore_root_task(struct pstree_item *init)
{
- enum trace_flags flag = TRACE_ALL;
int ret, fd, mnt_ns_fd = -1;
int root_seized = 0;
struct pstree_item *item;
@@ -2440,7 +2443,7 @@ skip_ns_bouncing:
timing_stop(TIME_RESTORE);
- if (catch_tasks(root_seized, &flag)) {
+ if (catch_tasks(root_seized)) {
pr_err("Can't catch all tasks\n");
goto out_kill_network_unlocked;
}
@@ -2450,7 +2453,7 @@ skip_ns_bouncing:
__restore_switch_stage(CR_STATE_COMPLETE);
- ret = compel_stop_on_syscall(task_entries->nr_threads, __NR(rt_sigreturn, 0), __NR(rt_sigreturn, 1), flag);
+ ret = compel_stop_on_syscall(task_entries->nr_threads, __NR(rt_sigreturn, 0), __NR(rt_sigreturn, 1));
if (ret) {
pr_err("Can't stop all tasks on rt_sigreturn\n");
goto out_kill_network_unlocked;