[CRIU] [PATCH 10/11] vdso/kdat: Add test for preserving "[vdso]" hint after mremap()
Dmitry Safonov
dsafonov at virtuozzo.com
Mon Jul 17 15:40:01 MSK 2017
If it does preserve, we can omit checking pagemap for dumpee or
filling symtable in parasite.
Signed-off-by: Dmitry Safonov <dsafonov at virtuozzo.com>
---
criu/include/kerndat.h | 1 +
criu/include/vdso.h | 2 ++
criu/kerndat.c | 3 ++
criu/vdso.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 81 insertions(+)
diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h
index 2667758906b7..8675e0a88f4f 100644
--- a/criu/include/kerndat.h
+++ b/criu/include/kerndat.h
@@ -62,6 +62,7 @@ struct kerndat_s {
unsigned long files_stat_max_files;
bool has_pid_for_children_ns;
bool can_map_vdso;
+ bool vdso_hint_reliable;
#ifdef CONFIG_VDSO
struct vdso_symtable vdso_sym;
#ifdef CONFIG_COMPAT
diff --git a/criu/include/vdso.h b/criu/include/vdso.h
index b6110e442e04..3c4c0ecbdd17 100644
--- a/criu/include/vdso.h
+++ b/criu/include/vdso.h
@@ -16,6 +16,7 @@ extern struct vdso_maps vdso_maps_compat;
extern int vdso_init_dump(void);
extern int vdso_init_restore(void);
extern int kerndat_vdso_fill_symtable(void);
+extern int kerndat_vdso_preserves_hint(void);
extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
struct vm_area_list *vma_area_list);
@@ -30,6 +31,7 @@ extern void compat_vdso_helper(struct vdso_maps *native, int pipe_fd,
#define vdso_init_dump() (0)
#define vdso_init_restore() (0)
#define kerndat_vdso_fill_symtable() (0)
+#define kerndat_vdso_preserves_hint() (0)
#define parasite_fixup_vdso(ctl, pid, vma_area_list) (0)
#endif /* CONFIG_VDSO */
diff --git a/criu/kerndat.c b/criu/kerndat.c
index 5ad5256a6d96..142e67e7b495 100644
--- a/criu/kerndat.c
+++ b/criu/kerndat.c
@@ -1059,6 +1059,9 @@ int kerndat_init(void)
/* Needs kdat.compat_cr filled before */
if (!ret)
ret = kerndat_vdso_fill_symtable();
+ /* Depends on kerndat_vdso_fill_symtable() */
+ if (!ret)
+ ret = kerndat_vdso_preserves_hint();
if (!ret)
ret = kerndat_detect_stack_guard_gap();
if (!ret)
diff --git a/criu/vdso.c b/criu/vdso.c
index 64046bc169d9..013a9a6c2c0a 100644
--- a/criu/vdso.c
+++ b/criu/vdso.c
@@ -621,3 +621,78 @@ int kerndat_vdso_fill_symtable(void)
return 0;
}
+
+/*
+ * On x86 pre-v3.16 kernels can lose "[vdso]" hint
+ * in /proc/.../maps file after mremap()'ing vdso vma.
+ * Depends on kerndat_vdso_fill_symtable() - assuming that
+ * vdso_maps and vdso_maps_compat are filled.
+ */
+int kerndat_vdso_preserves_hint(void)
+{
+ struct vdso_maps vdso_maps_after;
+ int status, ret = -1;
+ pid_t child;
+
+ kdat.vdso_hint_reliable = 0;
+
+ if (vdso_maps.vdso_start == VDSO_BAD_ADDR)
+ return 0;
+
+ child = fork();
+ if (child < 0) {
+ pr_perror("fork() failed");
+ return -1;
+ }
+
+ if (child == 0) {
+ unsigned long vdso_addr = vdso_maps.vdso_start;
+ unsigned long vdso_size = vdso_maps.sym.vdso_size;
+ void *new_addr;
+
+ new_addr = mmap(0, vdso_size, PROT_NONE,
+ MAP_ANON | MAP_PRIVATE, -1, 0);
+ if (new_addr == MAP_FAILED)
+ exit(1);
+
+ child = getpid();
+ new_addr = (void *)syscall(SYS_mremap, vdso_addr, vdso_size,
+ vdso_size, MREMAP_MAYMOVE | MREMAP_FIXED, new_addr);
+ if (new_addr == MAP_FAILED)
+ syscall(SYS_exit, 2);
+ syscall(SYS_kill, child, SIGSTOP);
+ syscall(SYS_exit, 3);
+ }
+
+ waitpid(child, &status, WUNTRACED);
+ if (WIFEXITED(status)) {
+ int ret = WEXITSTATUS(status);
+
+ pr_err("Child unexpectedly exited with %d\n", ret);
+ goto out;
+ } else if (WIFSIGNALED(status)) {
+ int sig = WTERMSIG(status);
+
+ pr_err("Child unexpectedly signaled with %d: %s\n",
+ sig, strsignal(sig));
+ goto out;
+ } else if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP) {
+ pr_err("Child is unstoppable or was stopped by other means\n");
+ goto out_kill;
+ }
+
+ if (vdso_parse_maps(child, &vdso_maps_after)) {
+ pr_err("Failed parsing maps for child helper\n");
+ goto out_kill;
+ }
+
+ if (vdso_maps_after.vdso_start != VDSO_BAD_ADDR)
+ kdat.vdso_hint_reliable = 1;
+
+ ret = 0;
+out_kill:
+ kill(child, SIGKILL);
+ waitpid(child, &status, 0);
+out:
+ return ret;
+}
--
2.13.1
More information about the CRIU
mailing list