From d43ad9913c19afa6d80cb8124015d47361152db8 Mon Sep 17 00:00:00 2001
From: bb-cat <ningyu9@huawei.com>
Date: Wed, 2 Mar 2022 15:00:43 +0800
Subject: [PATCH 10/16] clone-noasan: unregister rseq at the thread start for
 new glibc Fresh glibc does rseq registration by default during
 start_thread(). [ see
 https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=95e114a0919d844d8fe07839cb6538b7f5ee920e
 ]

This cause process crashes during memory restore procedure, because
memory which corresponds to the struct rseq will be overwritten.

See also
("nptl: Add public rseq symbols and <sys/rseq.h>")
https://sourceware.org/git?p=glibc.git;a=commit;h=c901c3e764d7c7079f006b4e21e877d5036eb4f5
("nptl: Add <thread_pointer.h> for defining __thread_pointer")
https://sourceware.org/git?p=glibc.git;a=commit;h=8dbeb0561eeb876f557ac9eef5721912ec074ea5

Signed-off-by: Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>
---
 criu/clone-noasan.c | 42 +++++++++++++++++++++++++++++++--
 1 file changed, 40 insertions(+), 2 deletions(-)

diff --git a/criu/clone-noasan.c b/criu/clone-noasan.c
index d657ea2..5f8dd1b 100644
--- a/criu/clone-noasan.c
+++ b/criu/clone-noasan.c
@@ -2,6 +2,13 @@
 #include <sched.h>
 #include <unistd.h>
 
+#ifdef __has_include
+#if __has_include ("sys/rseq.h")
+#include <sys/rseq.h>
+#include "asm/thread_pointer.h"
+#endif
+#endif
+
 #include <compel/plugins/std/syscall-codes.h>
 
 #include "sched.h"
@@ -34,16 +41,45 @@
  *	... wait for process to finish ...
  *	unlock_last_pid
  */
+
+#if defined(RSEQ_SIG)
+static inline void unregister_glibc_rseq(void)
+{
+	/* unregister rseq */
+	syscall(__NR_rseq, (void *)((char *)__criu_thread_pointer() + __rseq_offset), __rseq_size, 1, RSEQ_SIG);
+}
+#else
+static inline void unregister_glibc_rseq(void)
+{
+}
+#endif
+
+struct call_fn_args {
+	int (*fn)(void *);
+	void *arg;
+};
+
+int call_fn(void *arg)
+{
+	struct call_fn_args *cargs = arg;
+	unregister_glibc_rseq();
+	return cargs->fn(cargs->arg);
+}
+
 int clone_noasan(int (*fn)(void *), int flags, void *arg)
 {
 	void *stack_ptr = (void *)round_down((unsigned long)&stack_ptr - 1024, 16);
+	struct call_fn_args a = {
+		.fn = fn,
+		.arg = arg,
+	};
 
 	BUG_ON((flags & CLONE_VM) && !(flags & CLONE_VFORK));
 	/*
 	 * Reserve some bytes for clone() internal needs
 	 * and use as stack the address above this area.
 	 */
-	return clone(fn, stack_ptr, flags, arg);
+	return clone(call_fn, stack_ptr, flags, (void *)&a);
 }
 
 int clone3_with_pid_noasan(int (*fn)(void *), void *arg, int flags, int exit_signal, pid_t pid)
@@ -78,7 +114,9 @@ int clone3_with_pid_noasan(int (*fn)(void *), void *arg, int flags, int exit_sig
 	c_args.set_tid = ptr_to_u64(&pid);
 	c_args.set_tid_size = 1;
 	pid = syscall(__NR_clone3, &c_args, sizeof(c_args));
-	if (pid == 0)
+	if (pid == 0) {
+		unregister_glibc_rseq();
 		exit(fn(arg));
+	}
 	return pid;
 }
-- 
2.30.0

