1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
From cacddf19dad339f963b0b01f7174091b90c49e5d Mon Sep 17 00:00:00 2001
From: Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>
Date: Wed, 20 Jul 2022 14:36:28 +0300
Subject: [PATCH] cr-restore: rseq: dynamically handle *libc with rseq
Before this patch we assumed that CRIU is compiled against
the same GLibc as it runs with. But as we see from real
world examples like #1935 it's not always true.
The idea of this patch is to detect rseq configuration
for the main CRIU process and use it to unregister
rseq for all further child processes. It's correct,
because we restore pstree using clone*() syscalls,
don't use exec*() (!) syscalls, so rseq gets inherited
in the kernel and rseq configuration remains the same
for all children processes.
This will prevent issues like this:
https://github.com/checkpoint-restore/criu/issues/1935
Suggested-by: Florian Weimer <fweimer@redhat.com>
Signed-off-by: Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>
---
criu/cr-restore.c | 16 ++++++++--------
criu/include/kerndat.h | 2 ++
criu/kerndat.c | 25 +++++++++++++++++++++++--
3 files changed, 33 insertions(+), 10 deletions(-)
diff --git a/criu/cr-restore.c b/criu/cr-restore.c
index d11d28173a63..5b5b41dfc8bd 100644
--- a/criu/cr-restore.c
+++ b/criu/cr-restore.c
@@ -3103,14 +3103,14 @@ static void prep_libc_rseq_info(struct rst_rseq_param *rseq)
#else
static void prep_libc_rseq_info(struct rst_rseq_param *rseq)
{
- /*
- * TODO: handle built-in rseq on other libc'ies like musl
- * We can do that using get_rseq_conf kernel feature.
- *
- * For now we just assume that other libc libraries are
- * not registering rseq by default.
- */
- rseq->rseq_abi_pointer = 0;
+ if (!kdat.has_rseq || !kdat.has_ptrace_get_rseq_conf) {
+ rseq->rseq_abi_pointer = 0;
+ return;
+ }
+
+ rseq->rseq_abi_pointer = kdat.libc_rseq_conf.rseq_abi_pointer;
+ rseq->rseq_abi_size = kdat.libc_rseq_conf.rseq_abi_size;
+ rseq->signature = kdat.libc_rseq_conf.signature;
}
#endif
diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h
index 83d867e75bab..a3959c99260d 100644
--- a/criu/include/kerndat.h
+++ b/criu/include/kerndat.h
@@ -7,6 +7,7 @@
#include "asm/kerndat.h"
#include "util-vdso.h"
#include "hugetlb.h"
+#include <compel/ptrace.h>
struct stat;
@@ -82,6 +83,7 @@ struct kerndat_s {
bool has_openat2;
bool has_rseq;
bool has_ptrace_get_rseq_conf;
+ struct __ptrace_rseq_configuration libc_rseq_conf;
};
extern struct kerndat_s kdat;
diff --git a/criu/kerndat.c b/criu/kerndat.c
index bc5dccab1804..0f7d5fc8fb1d 100644
--- a/criu/kerndat.c
+++ b/criu/kerndat.c
@@ -923,6 +923,7 @@ static int kerndat_has_ptrace_get_rseq_conf(void)
pid_t pid;
int len;
struct __ptrace_rseq_configuration rseq;
+ int ret = 0;
pid = fork_and_ptrace_attach(NULL);
if (pid < 0)
@@ -930,6 +931,9 @@ static int kerndat_has_ptrace_get_rseq_conf(void)
len = ptrace(PTRACE_GET_RSEQ_CONFIGURATION, pid, sizeof(rseq), &rseq);
if (len != sizeof(rseq)) {
+ if (kdat.has_ptrace_get_rseq_conf)
+ ret = 1; /* we should update kdat */
+
kdat.has_ptrace_get_rseq_conf = false;
pr_info("ptrace(PTRACE_GET_RSEQ_CONFIGURATION) is not supported\n");
goto out;
@@ -940,16 +944,27 @@ static int kerndat_has_ptrace_get_rseq_conf(void)
* we need to pay attention to that and, possibly, make changes on the CRIU side.
*/
if (rseq.flags != 0) {
+ if (kdat.has_ptrace_get_rseq_conf)
+ ret = 1; /* we should update kdat */
+
kdat.has_ptrace_get_rseq_conf = false;
pr_err("ptrace(PTRACE_GET_RSEQ_CONFIGURATION): rseq.flags != 0\n");
} else {
+ if (!kdat.has_ptrace_get_rseq_conf)
+ ret = 1; /* we should update kdat */
+
kdat.has_ptrace_get_rseq_conf = true;
+
+ if (memcmp(&kdat.libc_rseq_conf, &rseq, sizeof(rseq)))
+ ret = 1; /* we should update kdat */
+
+ kdat.libc_rseq_conf = rseq;
}
out:
kill(pid, SIGKILL);
waitpid(pid, NULL, 0);
- return 0;
+ return ret;
}
int kerndat_sockopt_buf_lock(void)
@@ -1472,6 +1487,12 @@ int kerndat_try_load_new(void)
if (ret < 0)
return ret;
+ ret = kerndat_has_ptrace_get_rseq_conf();
+ if (ret < 0) {
+ pr_err("kerndat_has_ptrace_get_rseq_conf failed when initializing kerndat.\n");
+ return ret;
+ }
+
/* New information is found, we need to save to the cache */
if (ret)
kerndat_save_cache();
@@ -1657,7 +1678,7 @@ int kerndat_init(void)
pr_err("kerndat_has_rseq failed when initializing kerndat.\n");
ret = -1;
}
- if (!ret && kerndat_has_ptrace_get_rseq_conf()) {
+ if (!ret && (kerndat_has_ptrace_get_rseq_conf() < 0)) {
pr_err("kerndat_has_ptrace_get_rseq_conf failed when initializing kerndat.\n");
ret = -1;
}
--
2.45.2
|