[PATCHv3,10/30] kdat: add compat_sigreturn feature

Submitted by Dmitry Safonov on June 28, 2016, 7:24 p.m.

Details

Message ID 20160628192423.14943-11-dsafonov@virtuozzo.com
State Accepted
Series "x86 Compatible C/R, part 2"
Commit 0e64b820608b0f9935c4e2db9b3de278a7b530dc
Headers show

Commit Message

Dmitry Safonov June 28, 2016, 7:24 p.m.
Cc: Cyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: Dmitry Safonov <dsafonov@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(-)

Patch hide | download patch | download mbox

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 015c3e0b756d..e1bf7ad043c6 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;
 	unsigned int has_xtlocks;
 };
diff --git a/criu/kerndat.c b/criu/kerndat.c
index 5793de180960..0bd6961ff8aa 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"
@@ -457,6 +458,16 @@  static int kerndat_iptables_has_xtlocks(void)
 	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;
@@ -480,6 +491,8 @@  int kerndat_init(void)
 		ret = kerndat_loginuid(true);
 	if (!ret)
 		ret = kerndat_iptables_has_xtlocks();
+	if (!ret)
+		ret = kerndat_compat_restore();
 
 	kerndat_lsm();
 
@@ -509,6 +522,8 @@  int kerndat_init_rst(void)
 		ret = kerndat_loginuid(false);
 	if (!ret)
 		ret = kerndat_iptables_has_xtlocks();
+	if (!ret)
+		ret = kerndat_compat_restore();
 
 	kerndat_lsm();