From f84bab6b29146ef7fb9867af0324efb90596e12c Mon Sep 17 00:00:00 2001
From: bb-cat <ningyu9@huawei.com>
Date: Wed, 2 Mar 2022 15:30:18 +0800
Subject: [PATCH 05/72] cr-check: Add ptrace rseq conf dump feature Add
 "get_rseq_conf" feature corresponding to the
 ptrace(PTRACE_GET_RSEQ_CONFIGURATION) support.

Signed-off-by: Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>
---
 compel/include/uapi/ptrace.h | 12 +++++++++++
 criu/cr-check.c              | 11 ++++++++++
 criu/include/kerndat.h       |  1 +
 criu/kerndat.c               | 41 ++++++++++++++++++++++++++++++++++++
 4 files changed, 65 insertions(+)

diff --git a/compel/include/uapi/ptrace.h b/compel/include/uapi/ptrace.h
index c5291d2..bfe28c7 100644
--- a/compel/include/uapi/ptrace.h
+++ b/compel/include/uapi/ptrace.h
@@ -65,6 +65,18 @@ typedef struct {
 	uint64_t flags; /* Output: filter's flags */
 } seccomp_metadata_t;
 
+#ifndef PTRACE_GET_RSEQ_CONFIGURATION
+#define PTRACE_GET_RSEQ_CONFIGURATION	0x420f
+
+struct ptrace_rseq_configuration {
+	__u64 rseq_abi_pointer;
+	__u32 rseq_abi_size;
+	__u32 signature;
+	__u32 flags;
+	__u32 pad;
+};
+#endif
+
 #ifdef PTRACE_EVENT_STOP
 #if PTRACE_EVENT_STOP == 7 /* Bad value from Linux 3.1-3.3, fixed in 3.4 */
 #undef PTRACE_EVENT_STOP
diff --git a/criu/cr-check.c b/criu/cr-check.c
index d41ef8f..ba87511 100644
--- a/criu/cr-check.c
+++ b/criu/cr-check.c
@@ -794,6 +794,15 @@ static int check_ptrace_dump_seccomp_filters(void)
 	return ret;
 }
 
+static int check_ptrace_get_rseq_conf(void)
+{
+	if (!kdat.has_ptrace_get_rseq_conf) {
+		pr_warn("ptrace(PTRACE_GET_RSEQ_CONFIGURATION) isn't supported. C/R of processes which are using rseq() won't work.\n");
+		return -1;
+	}
+	return 0;
+}
+
 static int check_mem_dirty_track(void)
 {
 	if (!kdat.has_dirty_track) {
@@ -1435,6 +1444,7 @@ int cr_check(void)
 		ret |= check_ns_pid();
 		ret |= check_apparmor_stacking();
 		ret |= check_network_lock_nftables();
+		ret |= check_ptrace_get_rseq_conf();
 	}
 
 	/*
@@ -1547,6 +1557,7 @@ static struct feature_list feature_list[] = {
 	{ "ns_pid", check_ns_pid },
 	{ "apparmor_stacking", check_apparmor_stacking },
 	{ "network_lock_nftables", check_network_lock_nftables },
+	{ "get_rseq_conf", check_ptrace_get_rseq_conf },
 	{ NULL, NULL },
 };
 
diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h
index 44a6976..05abeda 100644
--- a/criu/include/kerndat.h
+++ b/criu/include/kerndat.h
@@ -75,6 +75,7 @@ struct kerndat_s {
 	bool has_nspid;
 	bool has_nftables_concat;
 	bool has_rseq;
+	bool has_ptrace_get_rseq_conf;
 };
 
 extern struct kerndat_s kdat;
diff --git a/criu/kerndat.c b/criu/kerndat.c
index f5a4490..4841387 100644
--- a/criu/kerndat.c
+++ b/criu/kerndat.c
@@ -4,6 +4,8 @@
 #include <sys/file.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
 #include <sys/mman.h>
 #include <errno.h>
 #include <sys/syscall.h>
@@ -36,6 +38,7 @@
 #include "sockets.h"
 #include "net.h"
 #include "tun.h"
+#include <compel/ptrace.h>
 #include <compel/plugins/std/syscall-codes.h>
 #include "netfilter.h"
 #include "fsnotify.h"
@@ -830,6 +833,40 @@ static int kerndat_has_rseq(void)
 	return 0;
 }
 
+static int kerndat_has_ptrace_get_rseq_conf(void)
+{
+	pid_t pid;
+	int len;
+	struct ptrace_rseq_configuration rseq;
+
+	pid = fork_and_ptrace_attach(NULL);
+	if (pid < 0)
+		return -1;
+
+	len = ptrace(PTRACE_GET_RSEQ_CONFIGURATION, pid, sizeof(rseq), &rseq);
+	if (len != sizeof(rseq)) {
+		kdat.has_ptrace_get_rseq_conf = false;
+		pr_info("ptrace(PTRACE_GET_RSEQ_CONFIGURATION) is not supported\n");
+		goto out;
+	}
+
+	/*
+	 * flags is always zero from the kernel side, if it will be changed
+	 * we need to pay attention to that and, possibly, make changes on the CRIU side.
+	 */
+	if (rseq.flags != 0) {
+		kdat.has_ptrace_get_rseq_conf = false;
+		pr_err("ptrace(PTRACE_GET_RSEQ_CONFIGURATION): rseq.flags != 0\n");
+	} else {
+		kdat.has_ptrace_get_rseq_conf = true;
+	}
+
+out:
+	kill(pid, SIGKILL);
+	waitpid(pid, NULL, 0);
+	return 0;
+}
+
 #define KERNDAT_CACHE_FILE     KDAT_RUNDIR "/criu.kdat"
 #define KERNDAT_CACHE_FILE_TMP KDAT_RUNDIR "/.criu.kdat"
 
@@ -1378,6 +1415,10 @@ int kerndat_init(void)
 		pr_err("kerndat_has_rseq failed when initializing kerndat.\n");
 		ret = -1;
 	}
+	if (!ret && kerndat_has_ptrace_get_rseq_conf()) {
+		pr_err("kerndat_has_ptrace_get_rseq_conf failed when initializing kerndat.\n");
+		ret = -1;
+	}
 	kerndat_lsm();
 	kerndat_mmap_min_addr();
 	kerndat_files_stat();
-- 
2.34.1

