代码拉取完成,页面将自动刷新
同步操作将从 src-openEuler/criu 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
From 47412ba0d9ce6283071973387bf5b34bf876bb9a Mon Sep 17 00:00:00 2001
From: "fu.lin" <fulin10@huawei.com>
Date: Wed, 1 Dec 2021 09:44:07 +0800
Subject: [PATCH 54/72] ptrace: trace specific syscall
criu use `ptrace(PTRACE_SYSCALL)` to watch whether the tracee steps in
correct status, it isn't necessory to stop tracee at every syscall.
Therefore, customizing `ptrace(PTRACE_SYSCALL_NR)` to make tracee stop at
the specific syscall can save time (1000 threads consume about 140ms).
ptrace syntax:
long ptrace(PTRACE_SYSCALL_NR, pid_t pid, void *addr, void *data);
The argument `addr` is unused in original `ptrace(PTRACE_SYSCALL)`,
Here `ptrace(PTRACE_SYSCALL_NR)` use `addr` parameter to give the
specific sysno which is wanted to trace.
use `criu check` to generate `/run/criu.kdat` before the first usage of
criu, or auto-check during `criu {dump, restore}`.
Conflict:NA
Reference:https://gitee.com/src-openeuler/criu/pulls/25
Signed-off-by: fu.lin <fulin10@huawei.com>
---
compel/Makefile | 1 +
compel/include/uapi/bisect.h | 30 +++++++
compel/include/uapi/infect.h | 15 +++-
compel/src/lib/bisect.c | 92 +++++++++++++++++++
compel/src/lib/infect.c | 167 ++++++++++++++++++++++++++++++++---
criu/cr-dump.c | 2 +-
criu/cr-restore.c | 97 +++++++++++++++++++-
criu/include/kerndat.h | 1 +
criu/kerndat.c | 61 +++++++++++++
9 files changed, 450 insertions(+), 16 deletions(-)
create mode 100644 compel/include/uapi/bisect.h
create mode 100644 compel/src/lib/bisect.c
diff --git a/compel/Makefile b/compel/Makefile
index b79aee6..2168a26 100644
--- a/compel/Makefile
+++ b/compel/Makefile
@@ -27,6 +27,7 @@ lib-y += src/lib/infect-rpc.o
lib-y += src/lib/infect-util.o
lib-y += src/lib/infect.o
lib-y += src/lib/ptrace.o
+lib-y += src/lib/bisect.o
ifeq ($(ARCH),x86)
lib-y += arch/$(ARCH)/src/lib/thread_area.o
diff --git a/compel/include/uapi/bisect.h b/compel/include/uapi/bisect.h
new file mode 100644
index 0000000..55ebcbd
--- /dev/null
+++ b/compel/include/uapi/bisect.h
@@ -0,0 +1,30 @@
+#ifndef __COMPEL_BISECT_H__
+#define __COMPEL_BISECT_H__
+
+#include <sys/types.h>
+
+enum tf {
+ TRACE_INTERRUPT,
+ TRACE_SYSCALL_ENTER,
+ TRACE_SYSCALL_EXIT,
+};
+
+struct trace_flag {
+ pid_t key;
+ enum tf flag;
+};
+
+struct bisect_meta {
+ int size;
+ int used;
+ void *data; /* data pointer array */
+ void *__data; /* data array */
+};
+
+struct trace_flag *tf_bisect(struct bisect_meta *meta, pid_t key);
+struct trace_flag *tf_insert(struct bisect_meta *meta, pid_t key);
+int tf_create(struct bisect_meta *meta, int len);
+void tf_destroy(struct bisect_meta *meta);
+void tf_clear(struct bisect_meta *meta);
+
+#endif /* __COMPEL_BISECT_H__ */
diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h
index 389878e..a23782e 100644
--- a/compel/include/uapi/infect.h
+++ b/compel/include/uapi/infect.h
@@ -8,11 +8,16 @@
#include <compel/ksigset.h>
#include <compel/handle-elf.h>
#include <compel/task-state.h>
+#include <compel/bisect.h>
#include "common/compiler.h"
#define PARASITE_START_AREA_MIN (4096)
+#ifndef PTRACE_SYSCALL_NR
+# define PTRACE_SYSCALL_NR 0xff00
+#endif
+
extern int __must_check compel_interrupt_task(int pid);
struct seize_task_status {
@@ -41,7 +46,7 @@ extern int __must_check compel_infect(struct parasite_ctl *ctl, unsigned long nr
extern struct parasite_thread_ctl __must_check *compel_prepare_thread(struct parasite_ctl *ctl, int pid);
extern void compel_release_thread(struct parasite_thread_ctl *);
-extern int __must_check compel_stop_daemon(struct parasite_ctl *ctl);
+extern int __must_check compel_stop_daemon(struct parasite_ctl *ctl, bool customize);
extern int __must_check compel_cure_remote(struct parasite_ctl *ctl);
extern int __must_check compel_cure_local(struct parasite_ctl *ctl);
extern int __must_check compel_cure(struct parasite_ctl *ctl);
@@ -83,6 +88,14 @@ extern int __must_check compel_stop_pie(pid_t pid, void *addr, enum trace_flags
extern int __must_check compel_unmap(struct parasite_ctl *ctl, unsigned long addr);
+extern int __must_check compel_stop_on_syscall_customize(int tasks,
+ const int sys_nr, const int exit_sys_nr, struct bisect_meta *meta);
+
+extern int __must_check compel_stop_pie_customize(pid_t pid,
+ const int sys_nr, struct trace_flag *tf);
+
+extern int __must_check compel_unmap_customize(struct parasite_ctl *ctl, unsigned long addr);
+
extern int compel_mode_native(struct parasite_ctl *ctl);
extern k_rtsigset_t *compel_task_sigmask(struct parasite_ctl *ctl);
diff --git a/compel/src/lib/bisect.c b/compel/src/lib/bisect.c
new file mode 100644
index 0000000..807a5a9
--- /dev/null
+++ b/compel/src/lib/bisect.c
@@ -0,0 +1,92 @@
+#include <stddef.h>
+
+#include "log.h"
+#include "common/xmalloc.h"
+#include "bisect.h"
+
+struct trace_flag *tf_bisect(struct bisect_meta *meta, pid_t key)
+{
+ struct trace_flag **tfs = meta->data;
+ int lo = 0, hi = meta->used, mid;
+
+ if (meta->used <= 0)
+ return NULL;
+
+ while (lo < hi) {
+ mid = (int)((lo + hi) / 2);
+ if (tfs[mid]->key == key) {
+ return tfs[mid];
+ } else if (tfs[mid]->key > key) {
+ hi = mid;
+ } else {
+ lo = mid + 1;
+ }
+ }
+
+ return NULL;
+}
+
+/* used in cr-restore */
+struct trace_flag *tf_insert(struct bisect_meta *meta, pid_t key)
+{
+ struct trace_flag **tfs = meta->data;
+ struct trace_flag *tf = &((struct trace_flag *)meta->__data)[meta->used];
+ int i = 0, j = 0;
+
+ if (meta->used == meta->size)
+ return NULL;
+
+ for (i = 0; i < meta->used; i++) {
+ if (tfs[i]->key >= key) /* impossible condition: `tfs[i]->key == key` */
+ break;
+ }
+
+ j = meta->used;
+ meta->used += 1;
+
+ while (j > i) {
+ tfs[j] = tfs[j-1];
+ j -= 1;
+ }
+
+ tfs[i] = tf;
+ tf->key = key;
+
+ return tf;
+}
+
+int tf_create(struct bisect_meta *meta, int len)
+{
+ struct trace_flag *tfs;
+ struct trace_flag **tfs_ptr;
+
+ tfs = xzalloc(sizeof(*tfs) * len);
+ if (tfs == NULL)
+ return -1;
+
+ tfs_ptr = xmalloc(sizeof(*tfs_ptr) * len);
+ if (tfs_ptr == NULL)
+ goto err;
+
+ meta->size = len;
+ meta->used = 0;
+ meta->__data = tfs;
+ meta->data = tfs_ptr;
+
+ return 0;
+err:
+ xfree(tfs);
+ return -1;
+}
+
+void tf_destroy(struct bisect_meta *meta)
+{
+ xfree(meta->__data);
+ xfree(meta->data);
+}
+
+void tf_clear(struct bisect_meta *meta)
+{
+ meta->used = 0;
+ __builtin_memset(meta->data, 0, sizeof(struct trace_flag **)*meta->size);
+}
diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c
index 6a13cc1..f9b8832 100644
--- a/compel/src/lib/infect.c
+++ b/compel/src/lib/infect.c
@@ -449,7 +449,7 @@ static int restore_child_handler(struct parasite_ctl *ctl)
}
static int parasite_run(pid_t pid, int cmd, unsigned long ip, void *stack, user_regs_struct_t *regs,
- struct thread_ctx *octx)
+ struct thread_ctx *octx, void *addr)
{
k_rtsigset_t block;
@@ -470,7 +470,7 @@ static int parasite_run(pid_t pid, int cmd, unsigned long ip, void *stack, user_
goto err_regs;
}
- if (ptrace(cmd, pid, NULL, NULL)) {
+ if (ptrace(cmd, pid, addr, NULL)) {
pr_perror("Can't run parasite at %d", pid);
goto err_cont;
}
@@ -575,7 +575,7 @@ int compel_execute_syscall(struct parasite_ctl *ctl, user_regs_struct_t *regs, c
return -1;
}
- err = parasite_run(pid, PTRACE_CONT, ctl->ictx.syscall_ip, 0, regs, &ctl->orig);
+ err = parasite_run(pid, PTRACE_CONT, ctl->ictx.syscall_ip, 0, regs, &ctl->orig, NULL);
if (!err)
err = parasite_trap(ctl, pid, regs, &ctl->orig, false);
@@ -592,7 +592,7 @@ int compel_run_at(struct parasite_ctl *ctl, unsigned long ip, user_regs_struct_t
user_regs_struct_t regs = ctl->orig.regs;
int ret;
- ret = parasite_run(ctl->rpid, PTRACE_CONT, ip, 0, ®s, &ctl->orig);
+ ret = parasite_run(ctl->rpid, PTRACE_CONT, ip, 0, ®s, &ctl->orig, NULL);
if (!ret)
ret = parasite_trap(ctl, ctl->rpid, ret_regs ? ret_regs : ®s, &ctl->orig, false);
return ret;
@@ -641,7 +641,7 @@ static int parasite_init_daemon(struct parasite_ctl *ctl)
goto err;
regs = ctl->orig.regs;
- if (parasite_run(pid, PTRACE_CONT, ctl->parasite_ip, ctl->rstack, ®s, &ctl->orig))
+ if (parasite_run(pid, PTRACE_CONT, ctl->parasite_ip, ctl->rstack, ®s, &ctl->orig, NULL))
goto err;
futex_wait_while_eq(&args->daemon_connected, 0);
@@ -1303,7 +1303,7 @@ static bool task_in_parasite(struct parasite_ctl *ctl, user_regs_struct_t *regs)
return addr >= ctl->remote_map && addr < ctl->remote_map + ctl->map_length;
}
-static int parasite_fini_seized(struct parasite_ctl *ctl)
+static int parasite_fini_seized(struct parasite_ctl *ctl, bool customize)
{
pid_t pid = ctl->rpid;
user_regs_struct_t regs;
@@ -1348,6 +1348,34 @@ static int parasite_fini_seized(struct parasite_ctl *ctl)
if (ret)
return -1;
+ /* use customize ptrace */
+ if (customize) {
+ struct trace_flag tf = { .key = pid, .flag = TRACE_SYSCALL_ENTER };
+ struct trace_flag *tf_ptr[] = { &tf };
+ struct bisect_meta meta = {
+ .size = 1,
+ .used = 1,
+ .__data = &tf,
+ .data = tf_ptr,
+ };
+
+ ret = compel_stop_pie_customize(pid, __NR(rt_sigreturn, 0), &tf);
+ if (ret < 0)
+ return ret;
+
+ /* The process is going to execute the required syscall, the
+ * original syscall should be forgot(set `-1`) in
+ * `syscall_trace_enter()` handler in kernel when no other
+ * else operation in tracer.
+ *
+ * Note: -1 means NO_SYSCALL which is defined in
+ * `arch/arm64/include/asm/ptrace.h`.
+ */
+ return compel_stop_on_syscall_customize(1,
+ __NR(rt_sigreturn, 0),
+ -1, &meta);
+ }
+
/* Go to sigreturn as closer as we can */
ret = compel_stop_pie(pid, ctl->sigreturn_addr, &flag, ctl->ictx.flags & INFECT_NO_BREAKPOINTS);
if (ret < 0)
@@ -1368,7 +1396,7 @@ static int parasite_fini_seized(struct parasite_ctl *ctl)
return 0;
}
-int compel_stop_daemon(struct parasite_ctl *ctl)
+int compel_stop_daemon(struct parasite_ctl *ctl, bool customize)
{
if (ctl->daemonized) {
/*
@@ -1378,7 +1406,7 @@ int compel_stop_daemon(struct parasite_ctl *ctl)
if (ctl->tsock < 0)
return -1;
- if (parasite_fini_seized(ctl)) {
+ if (parasite_fini_seized(ctl, customize)) {
close_safe(&ctl->tsock);
return -1;
}
@@ -1394,7 +1422,7 @@ int compel_cure_remote(struct parasite_ctl *ctl)
long ret;
int err;
- if (compel_stop_daemon(ctl))
+ if (compel_stop_daemon(ctl, false))
return -1;
if (!ctl->remote_map)
@@ -1461,7 +1489,7 @@ int compel_run_in_thread(struct parasite_thread_ctl *tctl, unsigned int cmd)
*ctl->cmd = cmd;
- ret = parasite_run(pid, PTRACE_CONT, ctl->parasite_ip, stack, ®s, octx);
+ ret = parasite_run(pid, PTRACE_CONT, ctl->parasite_ip, stack, ®s, octx, NULL);
if (ret == 0)
ret = parasite_trap(ctl, pid, ®s, octx, true);
if (ret == 0)
@@ -1484,7 +1512,7 @@ int compel_unmap(struct parasite_ctl *ctl, unsigned long addr)
pid_t pid = ctl->rpid;
int ret = -1;
- ret = parasite_run(pid, PTRACE_SYSCALL, addr, ctl->rstack, ®s, &ctl->orig);
+ ret = parasite_run(pid, PTRACE_SYSCALL, addr, ctl->rstack, ®s, &ctl->orig, NULL);
if (ret)
goto err;
@@ -1500,6 +1528,45 @@ err:
return ret;
}
+int compel_unmap_customize(struct parasite_ctl *ctl, unsigned long addr)
+{
+ user_regs_struct_t regs = ctl->orig.regs;
+ pid_t pid = ctl->rpid;
+ int ret = -1;
+ struct trace_flag tf = { .key = pid, .flag = TRACE_SYSCALL_ENTER };
+ struct trace_flag *tf_ptr[] = { &tf };
+ struct bisect_meta meta = {
+ .size = 1,
+ .used = 1,
+ .__data = &tf,
+ .data = tf_ptr,
+ };
+
+ /*
+ * Here it parasite code. Unlike trap code `compel_stop_pie()`, it
+ * won't let tracee forget the original syscall. In such way, tracer
+ * just trace the syscall called by tracee. The log likes the following
+ * if tracee forget syscall:
+ *
+ * [ 817.638332] set pid 1877 ptrace sysno 215
+ * [ 817.638343] syscall_trace_enter: pid 1877 ptrace_sysno 0 current_sysno 215
+ * [ 817.638363] (00.006280) Error (compel/src/lib/infect.c:1582): 1877 (native) is going to execute the syscall 215, required is 215
+ * [ 817.638368] set pid 1877 ptrace sysno 0
+ * [ 817.638402] syscall_trace_exit: pid 1877 ptrace_sysno 0 current_sysno 215
+ */
+ ret = parasite_run(pid, PTRACE_SYSCALL_NR, addr, ctl->rstack, ®s,
+ &ctl->orig, (void *)(long)__NR(munmap, 0));
+ if (ret)
+ goto err;
+
+ ret = compel_stop_on_syscall_customize(1, __NR(munmap, 0), 0, &meta);
+
+ if (restore_thread_ctx(pid, &ctl->orig, false))
+ ret = -1;
+err:
+ return ret;
+}
+
int compel_stop_pie(pid_t pid, void *addr, enum trace_flags *tf, bool no_bp)
{
int ret;
@@ -1535,6 +1602,17 @@ int compel_stop_pie(pid_t pid, void *addr, enum trace_flags *tf, bool no_bp)
return 0;
}
+int compel_stop_pie_customize(pid_t pid, const int sys_nr, struct trace_flag *tf)
+{
+ if (ptrace(PTRACE_SYSCALL_NR, pid, sys_nr, NULL)) {
+ pr_perror("Unable to restart the %d process", pid);
+ return -1;
+ }
+
+ tf->flag = TRACE_SYSCALL_ENTER;
+ return 0;
+}
+
static bool task_is_trapped(int status, pid_t pid)
{
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP)
@@ -1642,6 +1720,73 @@ int compel_stop_on_syscall(int tasks, const int sys_nr, const int sys_nr_compat,
return 0;
}
+int compel_stop_on_syscall_customize(int tasks, const int sys_nr,
+ const int exit_sys_nr, struct bisect_meta *meta)
+{
+ struct trace_flag *tf;
+ user_regs_struct_t regs;
+ int status, ret;
+ pid_t pid;
+
+ while (tasks) {
+ pid = wait4(-1, &status, __WALL, NULL);
+ if (pid == -1) {
+ pr_perror("wait4 failed");
+ return -1;
+ }
+
+ tf = tf_bisect(meta, pid);
+ if (tf == NULL) {
+ pr_warn("Unexpected task %d, state %d signal %d: %s\n",
+ pid, WEXITSTATUS(status),
+ WTERMSIG(status), strsignal(WTERMSIG(status)));
+ continue;
+ }
+
+ if (!task_is_trapped(status, pid))
+ return -1;
+
+ switch (tf->flag) {
+ case TRACE_SYSCALL_ENTER:
+ pr_debug("%d was trapped\n", pid);
+ pr_debug("`- Expecting exit\n");
+
+ ret = ptrace_get_regs(pid, ®s);
+ if (ret) {
+ pr_perror("ptrace");
+ return -1;
+ }
+
+ if (is_required_syscall(®s, pid, sys_nr, sys_nr)) {
+ ret = ptrace(PTRACE_SYSCALL_NR, pid, exit_sys_nr, NULL);
+ if (ret) {
+ pr_perror("ptrace");
+ return -1;
+ }
+ tf->flag = TRACE_SYSCALL_EXIT;
+ } else {
+ pr_warn("Impossible condition, check the system, try our best to restore...\n");
+ ret = ptrace(PTRACE_SYSCALL_NR, pid, sys_nr, NULL);
+ if (ret) {
+ pr_perror("ptrace");
+ return -1;
+ }
+ }
+ break;
+ case TRACE_SYSCALL_EXIT:
+ pr_debug("%d was stopped\n", pid);
+ tasks--;
+ break;
+
+ default:
+ pr_err("pid %d invalid status: %d\n", pid, tf->flag);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
int compel_mode_native(struct parasite_ctl *ctl)
{
return user_regs_native(&ctl->orig.regs);
diff --git a/criu/cr-dump.c b/criu/cr-dump.c
index ee826c0..9253e91 100644
--- a/criu/cr-dump.c
+++ b/criu/cr-dump.c
@@ -1708,7 +1708,7 @@ static int dump_one_task(struct pstree_item *item, InventoryEntry *parent_ie)
goto err_cure;
}
- ret = compel_stop_daemon(parasite_ctl);
+ ret = compel_stop_daemon(parasite_ctl, kdat.has_customize_ptrace);
if (ret) {
pr_err("Can't stop daemon in parasite (pid: %d)\n", pid);
goto err_cure;
diff --git a/criu/cr-restore.c b/criu/cr-restore.c
index d19768d..b0b3d30 100644
--- a/criu/cr-restore.c
+++ b/criu/cr-restore.c
@@ -2181,6 +2181,64 @@ static int catch_tasks(bool root_seized, enum trace_flags *flag)
return 0;
}
+static int cache_tasks_customize(bool root_seized, struct bisect_meta *meta)
+{
+ struct pstree_item *item;
+ struct trace_flag *tf;
+
+ for_each_pstree_item(item) {
+ int status, i, ret;
+ pid_t pid;
+
+ if (!task_alive(item))
+ continue;
+
+ if (item->nr_threads == 1) {
+ item->threads[0].real = item->pid->real;
+ } else {
+ if (parse_threads(item->pid->real, &item->threads, &item->nr_threads))
+ return -1;
+ }
+
+ for (i = 0; i < item->nr_threads; i++) {
+ pid = item->threads[i].real;
+
+ if (ptrace(PTRACE_INTERRUPT, pid, 0, 0)) {
+ pr_perror("Can't interrupt the %d task", pid);
+ return -1;
+ }
+
+ tf = tf_insert(meta, pid);
+ if (tf == NULL) {
+ pr_err("Can't find trace flag for %d, used %d\n",
+ pid, meta->used);
+ return -1;
+ }
+ tf->flag = TRACE_INTERRUPT;
+ }
+
+ for (i = 0; i < item->nr_threads; i++) {
+ pid = wait4(-1, &status, __WALL, NULL);
+
+ tf = tf_bisect(meta, pid);
+ if (tf == NULL) {
+ pr_err("Can't find trace flag for %d, used %d\n",
+ pid, meta->used);
+ return -1;
+ }
+
+ ret = compel_stop_pie_customize(pid,
+ __NR(rt_sigreturn, 0),
+ tf);
+ if (ret < 0)
+ return -1;
+
+ }
+ }
+
+ return 0;
+}
+
static int clear_breakpoints(void)
{
struct pstree_item *item;
@@ -2207,6 +2265,7 @@ static void finalize_restore(void)
pid_t pid = item->pid->real;
struct parasite_ctl *ctl;
unsigned long restorer_addr;
+ int retval;
if (!task_alive(item))
continue;
@@ -2217,7 +2276,12 @@ static void finalize_restore(void)
continue;
restorer_addr = (unsigned long)rsti(item)->munmap_restorer;
- if (compel_unmap(ctl, restorer_addr))
+ if (!kdat.has_customize_ptrace)
+ retval = compel_unmap(ctl, restorer_addr);
+ else
+ retval = compel_unmap_customize(ctl, restorer_addr);
+
+ if (retval)
pr_err("Failed to unmap restorer from %d\n", pid);
xfree(ctl);
@@ -2333,11 +2397,18 @@ static void reap_zombies(void)
static int restore_root_task(struct pstree_item *init)
{
+ struct bisect_meta tfs_meta;
enum trace_flags flag = TRACE_ALL;
int ret, fd, mnt_ns_fd = -1;
int root_seized = 0;
struct pstree_item *item;
+ if (kdat.has_customize_ptrace
+ && tf_create(&tfs_meta, task_entries->nr_threads) != 0) {
+ pr_err("Can't alloc memory, tf_create failed\n");
+ return -1;
+ }
+
ret = run_scripts(ACT_PRE_RESTORE);
if (ret != 0) {
pr_err("Aborting restore due to pre-restore script ret code %d\n", ret);
@@ -2551,7 +2622,12 @@ skip_ns_bouncing:
timing_stop(TIME_RESTORE);
- if (catch_tasks(root_seized, &flag)) {
+ if (!kdat.has_customize_ptrace)
+ ret = catch_tasks(root_seized, &flag);
+ else
+ ret = cache_tasks_customize(root_seized, &tfs_meta);
+
+ if (ret) {
pr_err("Can't catch all tasks\n");
goto out_kill_network_unlocked;
}
@@ -2561,7 +2637,15 @@ 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);
+ if (!kdat.has_customize_ptrace) {
+ ret = compel_stop_on_syscall(task_entries->nr_threads,
+ __NR(rt_sigreturn, 0),
+ __NR(rt_sigreturn, 1), flag);
+ } else {
+ ret = compel_stop_on_syscall_customize(task_entries->nr_threads,
+ __NR(rt_sigreturn, 0),
+ -1, &tfs_meta);
+ }
if (ret) {
pr_err("Can't stop all tasks on rt_sigreturn\n");
goto out_kill_network_unlocked;
@@ -2600,6 +2684,9 @@ skip_ns_bouncing:
reap_zombies();
}
+ if (kdat.has_customize_ptrace)
+ tf_destroy(&tfs_meta);
+
return 0;
out_kill_network_unlocked:
@@ -2631,6 +2718,10 @@ out:
stop_usernsd();
__restore_switch_stage(CR_STATE_FAIL);
pr_err("Restoring FAILED.\n");
+
+ if (kdat.has_customize_ptrace)
+ tf_destroy(&tfs_meta);
+
return -1;
}
diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h
index 3979939..8034db9 100644
--- a/criu/include/kerndat.h
+++ b/criu/include/kerndat.h
@@ -77,6 +77,7 @@ struct kerndat_s {
bool has_rseq;
bool has_ptrace_get_rseq_conf;
bool has_unix_sk_repair;
+ bool has_customize_ptrace;
};
extern struct kerndat_s kdat;
diff --git a/criu/kerndat.c b/criu/kerndat.c
index 6d6aac1..630814e 100644
--- a/criu/kerndat.c
+++ b/criu/kerndat.c
@@ -1289,6 +1289,66 @@ static void kerndat_has_unix_sk_repair(void)
return;
}
+static void kerndat_has_customize_ptrace(void)
+{
+ pid_t tracee = fork();
+ int status;
+ int retval;
+
+ if (tracee == 0) {
+ /* ensure */
+ prctl(PR_SET_PDEATHSIG, SIGKILL);
+
+ while (true)
+ sleep(1);
+ } else if (tracee > 0) {
+ pr_debug("fork task %d as tracee\n", tracee);
+ retval = ptrace(PTRACE_ATTACH, tracee, 0, 0);
+ if (retval < 0) {
+ pr_perror("Unexpect error from ptrace(PTRACE_ATTACH)");
+ return;
+ }
+
+ retval = wait4(-1, &status, __WALL, NULL);
+ if (retval == -1)
+ pr_perror("Unexpect error from wait");
+ else if (retval != tracee || !(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP))
+ pr_err("Task %d (expect %d) is unexpect, status: %d,"
+ " stoped: %d signal: %d(%s)\n",
+ retval, tracee, status,
+ WIFSTOPPED(status), WSTOPSIG(status),
+ strsignal(WTERMSIG(status)));
+ else {
+ retval = ptrace(PTRACE_SYSCALL_NR, tracee, 0, 0);
+ if (retval == 0)
+ kdat.has_customize_ptrace = true;
+ else
+ pr_perror("Unexpect error from ptrace(PTRACE_SYSCALL_NR)");
+ }
+
+ if (kill(tracee, SIGKILL) != 0) {
+ pr_perror("kill tracee %d failed", tracee);
+ return;
+ }
+
+ /*
+ * To prevent wait4 unexpect task when criu.kdat is generated
+ * in dump process.
+ */
+ retval = waitpid(tracee, &status, 0);
+ if (retval == -1)
+ pr_err("waitpid() failed");
+ else
+ pr_debug("tracee %d exited, status %d, signal %d(%s)\n",
+ WEXITSTATUS(status), WTERMSIG(status),
+ WTERMSIG(status), strsignal(WTERMSIG(status)));
+ } else {
+ pr_perror("Unexpected error from fork\n");
+ }
+
+ return;
+}
+
int kerndat_init(void)
{
int ret;
@@ -1451,6 +1511,7 @@ int kerndat_init(void)
}
kerndat_has_unix_sk_repair();
+ kerndat_has_customize_ptrace();
kerndat_lsm();
kerndat_mmap_min_addr();
--
2.34.1
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。