criu: Adjust to glibc __rseq_size semantic change

On criu version 3.17:
When use "criu restore -d -D checkpoint" to restore, the error is:
1272: Error (criu/cr-restore.c:1498): 1295 killed by signal 11: Segmentation fault

The root casue is that the glibc updated and criu should adjust to glibc __rseq_size semantic change.

Signed-off-by: Guocai He <guocai.he.cn@windriver.com>
Signed-off-by: Bruce Ashfield <bruce.ashfield@gmail.com>
This commit is contained in:
Guocai He 2025-03-21 11:54:32 +08:00 committed by Bruce Ashfield
parent cf982c9fad
commit 55209831c2
2 changed files with 101 additions and 1 deletions

View File

@ -20,8 +20,8 @@ SRC_URI = "git://github.com/checkpoint-restore/criu.git;branch=master;protocol=h
file://0001-criu-Skip-documentation-install.patch \
file://0002-criu-Change-libraries-install-directory.patch \
file://0003-lib-Makefile-overwrite-install-lib-to-allow-multiarc.patch \
file://0004-criu-Adjust-to-glibc-__rseq_size-semantic-change.patch \
"
COMPATIBLE_HOST = "(x86_64|arm|aarch64).*-linux"
DEPENDS += "libnl libcap protobuf-c-native protobuf-c util-linux-native libbsd libnet"

View File

@ -0,0 +1,100 @@
From 9f2eb6b9c4642fdc8aba2712d21cbe75545e4ab4 Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Wed, 10 Jul 2024 18:34:50 +0200
Subject: [PATCH] criu: Adjust to glibc __rseq_size semantic change
In commit 2e456ccf0c34a056e3ccafac4a0c7effef14d918 ("Linux: Make
__rseq_size useful for feature detection (bug 31965)") glibc 2.40
changed the meaning of __rseq_size slightly: it is now the size
of the active/feature area (20 bytes initially), and not the size
of the entire initially defined struct (32 bytes including padding).
The reason for the change is that the size including padding does not
allow detection of newly added features while previously unused
padding is consumed.
The prep_libc_rseq_info change in criu/cr-restore.c is not necessary
on kernels which have full ptrace support for obtaining rseq
information because the code is not used. On older kernels, it is
a correctness fix because with size 20 (the new value), rseq
registeration would fail.
The two other changes are required to make rseq unregistration work
in tests.
Upstream-Status: Backport [https://github.com/checkpoint-restore/criu/commit/
089345f77a34d1bc7ef146d650636afcd3cdda21]
Signed-off-by: Florian Weimer <fweimer@redhat.com>
Signed-off-by: Guocai He <guocai.he.cn@windriver.com>
---
criu/cr-restore.c | 8 ++++++++
test/zdtm/static/rseq00.c | 7 +++++--
test/zdtm/transition/rseq01.c | 5 ++++-
3 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/criu/cr-restore.c b/criu/cr-restore.c
index 9853c0585..df2010a4d 100644
--- a/criu/cr-restore.c
+++ b/criu/cr-restore.c
@@ -3087,7 +3087,15 @@ static void prep_libc_rseq_info(struct rst_rseq_param *rseq)
}
rseq->rseq_abi_pointer = encode_pointer(__criu_thread_pointer() + __rseq_offset);
+ /*
+ * Current glibc reports the feature/active size in
+ * __rseq_size, not the size passed to the kernel.
+ * This could be 20, but older kernels expect 32 for
+ * the size argument even if only 20 bytes are used.
+ */
rseq->rseq_abi_size = __rseq_size;
+ if (rseq->rseq_abi_size < 32)
+ rseq->rseq_abi_size = 32;
rseq->signature = RSEQ_SIG;
}
#else
diff --git a/test/zdtm/static/rseq00.c b/test/zdtm/static/rseq00.c
index 471ad6a43..23b2d74ab 100644
--- a/test/zdtm/static/rseq00.c
+++ b/test/zdtm/static/rseq00.c
@@ -46,12 +46,15 @@ static inline void *__criu_thread_pointer(void)
static inline void unregister_glibc_rseq(void)
{
struct rseq *rseq = (struct rseq *)((char *)__criu_thread_pointer() + __rseq_offset);
+ unsigned int size = __rseq_size;
/* hack: mark glibc rseq structure as failed to register */
rseq->cpu_id = RSEQ_CPU_ID_REGISTRATION_FAILED;
/* unregister rseq */
- syscall(__NR_rseq, (void *)rseq, __rseq_size, 1, RSEQ_SIG);
+ if (__rseq_size < 32)
+ size = 32;
+ syscall(__NR_rseq, (void *)rseq, size, 1, RSEQ_SIG);
}
#else
static inline void unregister_glibc_rseq(void)
@@ -140,4 +143,4 @@ int main(int argc, char *argv[])
return 0;
}
-#endif /* #if defined(__x86_64__) */
\ No newline at end of file
+#endif /* #if defined(__x86_64__) */
diff --git a/test/zdtm/transition/rseq01.c b/test/zdtm/transition/rseq01.c
index b6d470785..de4355845 100644
--- a/test/zdtm/transition/rseq01.c
+++ b/test/zdtm/transition/rseq01.c
@@ -33,7 +33,10 @@ static inline void *thread_pointer(void)
static inline void unregister_old_rseq(void)
{
/* unregister rseq */
- syscall(__NR_rseq, (void *)((char *)thread_pointer() + __rseq_offset), __rseq_size, 1, RSEQ_SIG);
+ unsigned int size = __rseq_size;
+ if (__rseq_size < 32)
+ size = 32;
+ syscall(__NR_rseq, (void *)((char *)thread_pointer() + __rseq_offset), size, 1, RSEQ_SIG);
}
#else
static inline void unregister_old_rseq(void)
--
2.34.1