[CRIU] [PATCH 2/2] vdso/ia32: separate compat vdso helper

Dmitry Safonov dsafonov at virtuozzo.com
Tue Apr 18 10:04:09 PDT 2017


As helper unmaps 64-bit vDSO blob, it can call only raw syscalls.
Also by that reason it's code should be not instrumented with GCOV/ASAN.
Disable instrumentation by separating it into new object and filtering
gcov/asan cflags.

Fixes: #290
@avagin, it rarely reproduces, I failed to reproduce even once
(with gcov, on the same env00 test, with the same linux-next)
please, reopen #290 if you'll spot it afterward.

Reported-by: Andrei Vagin <avagin at openvz.org>
Signed-off-by: Dmitry Safonov <dsafonov at virtuozzo.com>
---
 criu/Makefile.crtools |  4 ++-
 criu/include/vdso.h   |  5 ++++
 criu/vdso-compat.c    | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++
 criu/vdso.c           | 66 ++---------------------------------------------
 4 files changed, 81 insertions(+), 65 deletions(-)
 create mode 100644 criu/vdso-compat.c

diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools
index e98837f1340d..03756ae294fe 100644
--- a/criu/Makefile.crtools
+++ b/criu/Makefile.crtools
@@ -91,7 +91,9 @@ ifeq ($(VDSO),y)
 obj-y			+= pie-util-vdso.o
 obj-y			+= vdso.o
 obj-y			+= pie-util-vdso-elf32.o
-CFLAGS_pie-util-vdso-elf32.o      += -DCONFIG_VDSO_32
+CFLAGS_pie-util-vdso-elf32.o	+= -DCONFIG_VDSO_32
+obj-$(CONFIG_COMPAT)	+= vdso-compat.o
+CFLAGS_REMOVE_vdso-compat.o	+= $(CFLAGS-ASAN) $(CFLAGS-GCOV)
 endif
 
 PROTOBUF_GEN := scripts/protobuf-gen.sh
diff --git a/criu/include/vdso.h b/criu/include/vdso.h
index 9b6010c03d64..e118ed7f33f6 100644
--- a/criu/include/vdso.h
+++ b/criu/include/vdso.h
@@ -18,6 +18,11 @@ extern int vdso_init(void);
 extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
 			       struct vm_area_list *vma_area_list);
 
+#ifdef CONFIG_COMPAT
+void compat_vdso_helper(struct vdso_symtable *native, int pipe_fd,
+		int err_fd, void *vdso_buf, size_t buf_size);
+#endif
+
 #else /* CONFIG_VDSO */
 
 #define vdso_init()						(0)
diff --git a/criu/vdso-compat.c b/criu/vdso-compat.c
new file mode 100644
index 000000000000..7669eb3df5d4
--- /dev/null
+++ b/criu/vdso-compat.c
@@ -0,0 +1,71 @@
+#include <sys/syscall.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "types.h"
+#include "parasite-syscall.h"
+#include "parasite.h"
+#include "vdso.h"
+
+static void exit_on(int ret, int err_fd, char *reason)
+{
+	if (ret) {
+		syscall(__NR_write, err_fd, reason, strlen(reason));
+		syscall(__NR_exit, ret);
+	}
+}
+/*
+ * Because of restrictions of ARCH_MAP_VDSO_* API, new vDSO blob
+ * can be mapped only if there is no vDSO blob present for a process.
+ * This is a helper process, it unmaps 64-bit vDSO and maps 32-bit vDSO.
+ * Then it copies vDSO blob to shared with CRIU mapping.
+ *
+ * The purpose is to fill compat vdso's symtable (vdso_compat_rt).
+ * It's an optimization to fill symtable only once at CRIU restore
+ * for all restored tasks.
+ *
+ * @native		- 64-bit vDSO blob (for easy unmap)
+ * @pipe_fd		- to get size of compat blob from /proc/.../maps
+ * @err_fd		- to print error messages
+ * @vdso_buf, buf_size	- shared with CRIU buffer
+ *
+ * WARN: This helper shouldn't call pr_err() or any syscall with
+ *	 Glibc's wrapper function - it may very likely blow up.
+ */
+void compat_vdso_helper(struct vdso_symtable *native, int pipe_fd,
+		int err_fd, void *vdso_buf, size_t buf_size)
+{
+	size_t vma_size;
+	void *vdso_addr;
+	long vdso_size;
+	long ret;
+
+	vma_size = native->vma_end - native->vma_start;
+	ret = syscall(__NR_munmap, native->vma_start, vma_size);
+	exit_on(ret, err_fd, "Error: Failed to unmap native vdso\n");
+
+	vma_size = native->vvar_end - native->vvar_start;
+	ret = syscall(__NR_munmap, native->vvar_start, vma_size);
+	exit_on(ret, err_fd, "Error: Failed to unmap native vvar\n");
+
+	ret = syscall(__NR_arch_prctl, ARCH_MAP_VDSO_32, native->vma_start);
+	if (ret < 0)
+		exit_on(ret, err_fd, "Error: ARCH_MAP_VDSO failed\n");
+
+	vdso_size = ret;
+	if (vdso_size > buf_size)
+		exit_on(-1, err_fd, "Error: Compatible vdso's size is bigger than reserved buf\n");
+
+	/* Stop so CRIU could parse smaps to find 32-bit vdso's size */
+	ret = syscall(__NR_kill, syscall(__NR_getpid), SIGSTOP);
+	exit_on(ret, err_fd, "Error: Can't stop myself with SIGSTOP (having a good time)\n");
+
+	ret = syscall(__NR_read, pipe_fd, &vdso_addr, sizeof(void *));
+	if (ret != sizeof(void *))
+		exit_on(-1, err_fd, "Error: Can't read size of mmaped vdso from pipe\n");
+
+	memcpy(vdso_buf, vdso_addr, vdso_size);
+
+	syscall(__NR_exit, 0);
+}
diff --git a/criu/vdso.c b/criu/vdso.c
index 770853514619..8bc7b5d3b951 100644
--- a/criu/vdso.c
+++ b/criu/vdso.c
@@ -330,68 +330,6 @@ static int vdso_fill_self_symtable(struct vdso_symtable *s)
 }
 
 #ifdef CONFIG_COMPAT
-static void exit_on(int ret, int err_fd, char *reason)
-{
-	if (ret) {
-		syscall(__NR_write, err_fd, reason, strlen(reason));
-		syscall(__NR_exit, ret);
-	}
-}
-/*
- * Because of restrictions of ARCH_MAP_VDSO_* API, new vDSO blob
- * can be mapped only if there is no vDSO blob present for a process.
- * This is a helper process, it unmaps 64-bit vDSO and maps 32-bit vDSO.
- * Then it copies vDSO blob to shared with CRIU mapping.
- *
- * The purpose is to fill compat vdso's symtable (vdso_compat_rt).
- * It's an optimization to fill symtable only once at CRIU restore
- * for all restored tasks.
- *
- * @native		- 64-bit vDSO blob (for easy unmap)
- * @pipe_fd		- to get size of compat blob from /proc/.../maps
- * @err_fd		- to print error messages
- * @vdso_buf, buf_size	- shared with CRIU buffer
- *
- * WARN: This helper shouldn't call pr_err() or any syscall with
- *	 Glibc's wrapper function - it may very likely blow up.
- */
-static void compat_vdso_helper(struct vdso_symtable *native, int pipe_fd,
-		int err_fd, void *vdso_buf, size_t buf_size)
-{
-	size_t vma_size;
-	void *vdso_addr;
-	long vdso_size;
-	long ret;
-
-	vma_size = native->vma_end - native->vma_start;
-	ret = syscall(__NR_munmap, native->vma_start, vma_size);
-	exit_on(ret, err_fd, "Error: Failed to unmap native vdso\n");
-
-	vma_size = native->vvar_end - native->vvar_start;
-	ret = syscall(__NR_munmap, native->vvar_start, vma_size);
-	exit_on(ret, err_fd, "Error: Failed to unmap native vvar\n");
-
-	ret = syscall(__NR_arch_prctl, ARCH_MAP_VDSO_32, native->vma_start);
-	if (ret < 0)
-		exit_on(ret, err_fd, "Error: ARCH_MAP_VDSO failed\n");
-
-	vdso_size = ret;
-	if (vdso_size > buf_size)
-		exit_on(-1, err_fd, "Error: Compatible vdso's size is bigger than reserved buf\n");
-
-	/* Stop so CRIU could parse smaps to find 32-bit vdso's size */
-	ret = syscall(__NR_kill, syscall(__NR_getpid), SIGSTOP);
-	exit_on(ret, err_fd, "Error: Can't stop myself with SIGSTOP (having a good time)\n");
-
-	ret = syscall(__NR_read, pipe_fd, &vdso_addr, sizeof(void *));
-	if (ret != sizeof(void *))
-		exit_on(-1, err_fd, "Error: Can't read size of mmaped vdso from pipe\n");
-
-	memcpy(vdso_buf, vdso_addr, vdso_size);
-
-	syscall(__NR_exit, 0);
-}
-
 static int vdso_mmap_compat(struct vdso_symtable *native,
 		struct vdso_symtable *compat, void *vdso_buf, size_t buf_size)
 {
@@ -503,13 +441,13 @@ out_unmap:
 	return ret;
 }
 
-#else
+#else /* CONFIG_COMPAT */
 static int vdso_fill_compat_symtable(struct vdso_symtable *native,
 		struct vdso_symtable *compat)
 {
 	return 0;
 }
-#endif
+#endif /* CONFIG_COMPAT */
 
 int vdso_init(void)
 {
-- 
2.12.2



More information about the CRIU mailing list