[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