[CRIU] [PATCH 01/11] kdat: Add test for presence of vdso mapping API

Dmitry Safonov dsafonov at virtuozzo.com
Mon Jul 17 15:39:52 MSK 2017


Previously, arch_prctl(ARCH_MAP_VDSO_32) was only used by
CONFIG_COMPAT to map compatible vdso blob for 32-bit restoree.
But we can make it more generic:
Omitting mremap() for moving vdso to rt-vdso zone in restorer
and afterward on needed position in restoree.
Also omitting reading /proc/self/maps to find vdso/vvar
addresses (to park afterward in restorer).

TLDR; under this kdat feature we can get rid of a buch of mremap()'s
for each restoree and from parsing /proc/self/maps in vdso_init_restore().

The API is present from v4.9 kernel.

Signed-off-by: Dmitry Safonov <dsafonov at virtuozzo.com>
---
 criu/arch/aarch64/include/asm/restorer.h |  1 +
 criu/arch/arm/include/asm/restorer.h     |  1 +
 criu/arch/ppc64/include/asm/restorer.h   |  1 +
 criu/arch/x86/crtools.c                  | 65 ++++++++++++++++++++------------
 criu/arch/x86/include/asm/restorer.h     |  1 +
 criu/cr-check.c                          | 10 +++++
 criu/include/kerndat.h                   |  1 +
 criu/kerndat.c                           | 11 ++++--
 8 files changed, 64 insertions(+), 27 deletions(-)

diff --git a/criu/arch/aarch64/include/asm/restorer.h b/criu/arch/aarch64/include/asm/restorer.h
index 78cc9bd39532..000d3f8bab61 100644
--- a/criu/arch/aarch64/include/asm/restorer.h
+++ b/criu/arch/aarch64/include/asm/restorer.h
@@ -53,6 +53,7 @@
 
 
 #define kdat_compatible_cr()			0
+#define kdat_can_map_vdso()			0
 
 int restore_gpregs(struct rt_sigframe *f, UserAarch64RegsEntry *r);
 int restore_nonsigframe_gpregs(UserAarch64RegsEntry *r);
diff --git a/criu/arch/arm/include/asm/restorer.h b/criu/arch/arm/include/asm/restorer.h
index 8748281fc024..3da166a44d54 100644
--- a/criu/arch/arm/include/asm/restorer.h
+++ b/criu/arch/arm/include/asm/restorer.h
@@ -54,6 +54,7 @@
 
 
 #define kdat_compatible_cr()			0
+#define kdat_can_map_vdso()			0
 
 int restore_gpregs(struct rt_sigframe *f, UserArmRegsEntry *r);
 int restore_nonsigframe_gpregs(UserArmRegsEntry *r);
diff --git a/criu/arch/ppc64/include/asm/restorer.h b/criu/arch/ppc64/include/asm/restorer.h
index e3d2d291eb54..ad9c39a7886b 100644
--- a/criu/arch/ppc64/include/asm/restorer.h
+++ b/criu/arch/ppc64/include/asm/restorer.h
@@ -49,6 +49,7 @@
 		: "memory","0","3","4","5","6","7","14","15")
 
 #define kdat_compatible_cr()			0
+#define kdat_can_map_vdso()			0
 
 int restore_gpregs(struct rt_sigframe *f, UserPpc64RegsEntry *r);
 int restore_nonsigframe_gpregs(UserPpc64RegsEntry *r);
diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c
index 90b809b5e1c4..af5a315adae3 100644
--- a/criu/arch/x86/crtools.c
+++ b/criu/arch/x86/crtools.c
@@ -30,33 +30,48 @@
 #include "images/core.pb-c.h"
 #include "images/creds.pb-c.h"
 
-#ifdef CONFIG_COMPAT
-static int has_arch_map_vdso(void)
+int kdat_can_map_vdso(void)
 {
-	unsigned long auxval;
-	int ret;
-
-	errno = 0;
-	auxval = getauxval(AT_SYSINFO_EHDR);
-	if (!auxval) {
-		if (errno == ENOENT) { /* No vDSO - OK */
-			pr_warn("No SYSINFO_EHDR - no vDSO\n");
-			return 1;
-		} else { /* That can't happen, according to man */
-			pr_err("Failed to get auxval: errno %d\n", errno);
-			return -1;
-		}
-	}
+	pid_t child;
+	int stat;
+
 	/*
-	 * Mapping vDSO while have not unmap it yet:
-	 * this is restricted by API if ARCH_MAP_VDSO_* is supported.
+	 * Running under fork so if vdso_64 is disabled - don't create
+	 * it for criu accidentally.
 	 */
-	ret = syscall(SYS_arch_prctl, ARCH_MAP_VDSO_32, 1);
-	if (ret == -1 && errno == EEXIST)
-		return 1;
-	return 0;
+	child = fork();
+	if (child < 0)
+		return -1;
+
+	if (child == 0) {
+		int ret;
+
+		ret = syscall(SYS_arch_prctl, ARCH_MAP_VDSO_32, 0);
+		if (ret == 0)
+			exit(1);
+		/*
+		 * Mapping vDSO while have not unmap it yet:
+		 * this is restricted by API if ARCH_MAP_VDSO_* is supported.
+		 */
+		if (ret == -1 && errno == EEXIST)
+			exit(1);
+		exit(0);
+	}
+
+	if (waitpid(child, &stat, 0) != child) {
+		pr_err("Failed to wait for arch_prctl() test");
+		kill(child, SIGKILL);
+		return -1;
+	}
+
+	if (!WIFEXITED(stat))
+		return -1;
+
+	return WEXITSTATUS(stat);
+
 }
 
+#ifdef CONFIG_COMPAT
 void *mmap_ia32(void *addr, size_t len, int prot,
 		int flags, int fildes, off_t off)
 {
@@ -151,13 +166,15 @@ static int has_32bit_mmap_bug(void)
 
 int kdat_compatible_cr(void)
 {
-	if (!has_arch_map_vdso())
+	if (!kdat.can_map_vdso)
 		return 0;
+
 	if (has_32bit_mmap_bug())
 		return 0;
+
 	return 1;
 }
-#else
+#else /* !CONFIG_COMPAT */
 int kdat_compatible_cr(void)
 {
 	return 0;
diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h
index e7199f68434b..04509ff2fefe 100644
--- a/criu/arch/x86/include/asm/restorer.h
+++ b/criu/arch/x86/include/asm/restorer.h
@@ -77,6 +77,7 @@ static inline int set_compat_robust_list(uint32_t head_ptr, uint32_t len)
 #endif
 
 extern int kdat_compatible_cr(void);
+extern int kdat_can_map_vdso(void);
 
 static inline void
 __setup_sas_compat(struct ucontext_ia32* uc, ThreadSasEntry *sas)
diff --git a/criu/cr-check.c b/criu/cr-check.c
index 399214172345..512ea878119d 100644
--- a/criu/cr-check.c
+++ b/criu/cr-check.c
@@ -1124,6 +1124,14 @@ static int check_pid_for_children_ns(void)
 	return 0;
 }
 
+static int check_can_map_vdso(void)
+{
+	if (kdat_can_map_vdso() == 1)
+		return 0;
+	pr_warn("Do not have API to map vDSO - will use mremap() to restore vDSO\n");
+	return -1;
+}
+
 static int (*chk_feature)(void);
 
 /*
@@ -1232,6 +1240,7 @@ int cr_check(void)
 		ret |= check_ns_get_userns();
 		ret |= check_ns_get_parent();
 		ret |= check_pid_for_children_ns();
+		ret |= check_can_map_vdso();
 	}
 
 	/*
@@ -1316,6 +1325,7 @@ static struct feature_list feature_list[] = {
 	{ "ns_get_userns", check_ns_get_userns },
 	{ "ns_get_parent", check_ns_get_parent },
 	{ "pid_for_children_ns", check_pid_for_children_ns},
+	{ "can_map_vdso", check_can_map_vdso},
 	{ NULL, NULL },
 };
 
diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h
index ff10228c36a0..2667758906b7 100644
--- a/criu/include/kerndat.h
+++ b/criu/include/kerndat.h
@@ -61,6 +61,7 @@ struct kerndat_s {
 	unsigned int sysctl_nr_open;
 	unsigned long files_stat_max_files;
 	bool has_pid_for_children_ns;
+	bool can_map_vdso;
 #ifdef CONFIG_VDSO
 	struct vdso_symtable	vdso_sym;
 #ifdef CONFIG_COMPAT
diff --git a/criu/kerndat.c b/criu/kerndat.c
index 85f4256547a5..5ad5256a6d96 100644
--- a/criu/kerndat.c
+++ b/criu/kerndat.c
@@ -651,11 +651,16 @@ int kerndat_nsid(void)
 
 static int kerndat_compat_restore(void)
 {
-	int ret = kdat_compatible_cr();
+	int ret;
 
-	if (ret < 0) /* failure */
+	ret = kdat_can_map_vdso();
+	if (ret < 0)
 		return ret;
-	kdat.compat_cr = !!ret;
+	kdat.can_map_vdso = !!ret;
+
+	/* depends on kdat.can_map_vdso result */
+	kdat.compat_cr = kdat_compatible_cr();
+
 	return 0;
 }
 
-- 
2.13.1



More information about the CRIU mailing list