[CRIU] [PATCHv2 10/30] kdat: add compat_sigreturn feature

Dmitry Safonov dsafonov at virtuozzo.com
Fri Jun 24 08:08:15 PDT 2016


Cc: Cyrill Gorcunov <gorcunov at openvz.org>
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                  | 36 ++++++++++++++++++++++++++++++--
 criu/arch/x86/include/asm/restorer.h     |  7 +++++++
 criu/include/kerndat.h                   |  1 +
 criu/kerndat.c                           | 15 +++++++++++++
 7 files changed, 60 insertions(+), 2 deletions(-)

diff --git a/criu/arch/aarch64/include/asm/restorer.h b/criu/arch/aarch64/include/asm/restorer.h
index 9bf4268bb74e..19f459a0b08f 100644
--- a/criu/arch/aarch64/include/asm/restorer.h
+++ b/criu/arch/aarch64/include/asm/restorer.h
@@ -98,6 +98,7 @@ struct rt_sigframe {
 #define RT_SIGFRAME_FPU(rt_sigframe)					\
 	(&RT_SIGFRAME_AUX_CONTEXT(rt_sigframe)->fpsimd)
 #define RT_SIGFRAME_OFFSET(rt_sigframe) 0
+#define kdat_compat_sigreturn_test()			0
 
 
 int restore_gpregs(struct rt_sigframe *f, UserAarch64RegsEntry *r);
diff --git a/criu/arch/arm/include/asm/restorer.h b/criu/arch/arm/include/asm/restorer.h
index 34c2783323ef..e17a80e7a971 100644
--- a/criu/arch/arm/include/asm/restorer.h
+++ b/criu/arch/arm/include/asm/restorer.h
@@ -131,6 +131,7 @@ struct rt_sigframe {
 #define RT_SIGFRAME_FPU(rt_sigframe)					\
 	(&RT_SIGFRAME_AUX_SIGFRAME(rt_sigframe)->vfp)
 #define RT_SIGFRAME_OFFSET(rt_sigframe) 0
+#define kdat_compat_sigreturn_test()			0
 
 
 int restore_gpregs(struct rt_sigframe *f, UserArmRegsEntry *r);
diff --git a/criu/arch/ppc64/include/asm/restorer.h b/criu/arch/ppc64/include/asm/restorer.h
index 8c1473eb9b0a..e1c08ef17eeb 100644
--- a/criu/arch/ppc64/include/asm/restorer.h
+++ b/criu/arch/ppc64/include/asm/restorer.h
@@ -105,6 +105,7 @@ struct rt_sigframe {
 #define RT_SIGFRAME_REGIP(rt_sigframe) ((long unsigned int)(rt_sigframe)->uc.uc_mcontext.gp_regs[PT_NIP])
 #define RT_SIGFRAME_HAS_FPU(rt_sigframe) (1)
 #define RT_SIGFRAME_FPU(rt_sigframe) (&(rt_sigframe)->uc.uc_mcontext)
+#define kdat_compat_sigreturn_test()			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 2a768bcc4b27..58757b2830dc 100644
--- a/criu/arch/x86/crtools.c
+++ b/criu/arch/x86/crtools.c
@@ -3,6 +3,8 @@
 #include <elf.h>
 #include <sys/user.h>
 #include <sys/mman.h>
+#include <sys/syscall.h>
+#include <sys/auxv.h>
 
 #include "asm/processor-flags.h"
 #include "asm/parasite-syscall.h"
@@ -20,6 +22,7 @@
 #include "cpu.h"
 #include "errno.h"
 #include "syscall-codes.h"
+#include "kerndat.h"
 
 #include "protobuf.h"
 #include "images/core.pb-c.h"
@@ -67,6 +70,31 @@ void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *
 			~(X86_EFLAGS_TF | X86_EFLAGS_DF | X86_EFLAGS_IF));
 }
 
+#ifdef CONFIG_X86_64
+/* Remaps 64-bit vDSO on the same addr, where it already is */
+int kdat_compat_sigreturn_test(void)
+{
+	unsigned long auxval;
+	int ret;
+
+	errno = 0;
+	auxval = getauxval(AT_SYSINFO_EHDR);
+	if (!auxval || errno == ENOENT) {
+		pr_err("Failed to get auxval, err: %lu\n", auxval);
+		return 0;
+	}
+	/*
+	 * Mapping vDSO on very low unaligned address (1).
+	 * We will get ENOMEM or EPERM if ARCH_MAP_VDSO_* exist,
+	 * and ENOSYS if patches aren't in kernel.
+	 */
+	ret = syscall(SYS_arch_prctl, ARCH_MAP_VDSO_32, 1);
+	if (ret == -1 && errno == ENOSYS)
+		return 0;
+	return 1;
+}
+#endif /* CONFIG_X86_64 */
+
 int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs);
 int arch_task_compatible(pid_t pid)
 {
@@ -102,8 +130,12 @@ static bool ldt_task_selectors(pid_t pid)
 
 bool arch_can_dump_task(pid_t pid)
 {
-	/* FIXME: remove it */
-	if (arch_task_compatible(pid)) {
+	int ret = arch_task_compatible(pid);
+
+	if (ret < 0)
+		return false;
+
+	if (ret && !kdat.has_compat_sigreturn) {
 		pr_err("Can't dump task %d running in 32-bit mode\n", pid);
 		return false;
 	}
diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h
index 6ae4245bb800..66931e1d46fc 100644
--- a/criu/arch/x86/include/asm/restorer.h
+++ b/criu/arch/x86/include/asm/restorer.h
@@ -250,6 +250,12 @@ do {									\
 		     :						\
 		     : "r"(ret)					\
 		     : "memory")
+
+#ifndef ARCH_MAP_VDSO_32
+# define ARCH_MAP_VDSO_32		0x2002
+#endif
+
+extern int kdat_compat_sigreturn_test(void);
 #else /* !CONFIG_X86_64 */
 
 #define ARCH_RT_SIGRETURN(new_sp, rt_sigframe)				\
@@ -286,6 +292,7 @@ do {									\
 	(unsigned long)(rt_sigframe)->uc.uc_mcontext.ip
 #define RT_SIGFRAME_FPU(rt_sigframe) (&(rt_sigframe)->fpu_state)
 #define RT_SIGFRAME_HAS_FPU(rt_sigframe) (RT_SIGFRAME_FPU(rt_sigframe)->has_fpu)
+#define kdat_compat_sigreturn_test()			0
 #endif /* !CONFIG_X86_64 */
 
 static inline void
diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h
index 15f8622352c2..1569592d7d8a 100644
--- a/criu/include/kerndat.h
+++ b/criu/include/kerndat.h
@@ -33,6 +33,7 @@ struct kerndat_s {
 	unsigned long task_size;
 	bool ipv6;
 	bool has_loginuid;
+	bool has_compat_sigreturn;
 	enum pagemap_func pmap;
 };
 
diff --git a/criu/kerndat.c b/criu/kerndat.c
index 8127b6e26f2b..1db1efc55082 100644
--- a/criu/kerndat.c
+++ b/criu/kerndat.c
@@ -16,6 +16,7 @@
 #include "compiler.h"
 #include "sysctl.h"
 #include "asm/types.h"
+#include "asm/restorer.h"
 #include "cr_options.h"
 #include "util.h"
 #include "lsm.h"
@@ -446,6 +447,16 @@ int kerndat_loginuid(bool only_dump)
 	return 0;
 }
 
+static int kerndat_compat_restore(void)
+{
+	int ret = kdat_compat_sigreturn_test();
+
+	if (ret < 0) /* failure */
+		return ret;
+	kdat.has_compat_sigreturn = !!ret;
+	return 0;
+}
+
 int kerndat_init(void)
 {
 	int ret;
@@ -467,6 +478,8 @@ int kerndat_init(void)
 		ret = get_ipv6();
 	if (!ret)
 		ret = kerndat_loginuid(true);
+	if (!ret)
+		ret = kerndat_compat_restore();
 
 	kerndat_lsm();
 
@@ -494,6 +507,8 @@ int kerndat_init_rst(void)
 		ret = get_ipv6();
 	if (!ret)
 		ret = kerndat_loginuid(false);
+	if (!ret)
+		ret = kerndat_compat_restore();
 
 	kerndat_lsm();
 
-- 
2.9.0



More information about the CRIU mailing list