1 Star 0 Fork 38

EulerOSWander/criu

forked from src-openEuler/criu 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
0054-ptrace-trace-specific-syscall.patch 21.31 KB
一键复制 编辑 原始数据 按行查看 历史
river 提交于 2022-04-13 15:05 +08:00 . criu: backport kinds of features/bugfix
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
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, &regs, &ctl->orig);
+ ret = parasite_run(ctl->rpid, PTRACE_CONT, ip, 0, &regs, &ctl->orig, NULL);
if (!ret)
ret = parasite_trap(ctl, ctl->rpid, ret_regs ? ret_regs : &regs, &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, &regs, &ctl->orig))
+ if (parasite_run(pid, PTRACE_CONT, ctl->parasite_ip, ctl->rstack, &regs, &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, &regs, octx);
+ ret = parasite_run(pid, PTRACE_CONT, ctl->parasite_ip, stack, &regs, octx, NULL);
if (ret == 0)
ret = parasite_trap(ctl, pid, &regs, 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, &regs, &ctl->orig);
+ ret = parasite_run(pid, PTRACE_SYSCALL, addr, ctl->rstack, &regs, &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, &regs,
+ &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, &regs);
+ if (ret) {
+ pr_perror("ptrace");
+ return -1;
+ }
+
+ if (is_required_syscall(&regs, 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
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/euleroswander/criu.git
git@gitee.com:euleroswander/criu.git
euleroswander
criu
criu
master

搜索帮助