[CRIU] [PATCH 4/8] vdso: share the PIE part of the vDSO proxy machinery between all architectures

Alexander Kartashov alekskartashov at parallels.com
Mon Mar 10 01:51:24 PDT 2014


This patch splits the file arch/x86/vdso-pie.c into machine-dependent
and machine-independent parts by moving the routines vdso_fill_symtable(),
vdso_remap(), and vdso_proxify() to the file pie/vdso.c.

The ARM version of the routines is moved to the source pie/vdso-stub.c
to provide the vDSO proxy stub implementation for architectures
that don't provide the vDSO.

Signed-off-by: Alexander Kartashov <alekskartashov at parallels.com>
Cc: Cyrill Gorcunov <gorcunov at openvz.org>
---
 Makefile                    |    4 +
 arch/arm/include/asm/vdso.h |    3 -
 arch/arm/vdso-pie.c         |   15 ---
 arch/x86/include/asm/vdso.h |    3 -
 arch/x86/vdso-pie.c         |  249 ---------------------------------------
 include/vdso.h              |    3 +
 pie/Makefile                |    1 +
 pie/vdso-stub.c             |   31 +++++
 pie/vdso.c                  |  272 +++++++++++++++++++++++++++++++++++++++++++
 9 files changed, 311 insertions(+), 270 deletions(-)
 create mode 100644 pie/vdso-stub.c
 create mode 100644 pie/vdso.c

diff --git a/Makefile b/Makefile
index 99ea752..7e192ad 100644
--- a/Makefile
+++ b/Makefile
@@ -180,6 +180,10 @@ PROGRAM-BUILTINS	+= built-in.o
 $(ARCH_DIR)/vdso-pie.o: pie
 	$(Q) $(MAKE) $(build)=pie $(ARCH_DIR)/vdso-pie.o
 PROGRAM-BUILTINS	+= $(ARCH_DIR)/vdso-pie.o
+pie/$(VDSO_O): pie
+	$(Q) $(MAKE) $(build)=pie pie/$(VDSO_O)
+PROGRAM-BUILTINS	+= pie/$(VDSO_O)
+
 
 $(PROGRAM): $(SYSCALL-LIB) $(ARCH-LIB) $(PROGRAM-BUILTINS)
 	$(E) "  LINK    " $@
diff --git a/arch/arm/include/asm/vdso.h b/arch/arm/include/asm/vdso.h
index 56d8007..a702471 100644
--- a/arch/arm/include/asm/vdso.h
+++ b/arch/arm/include/asm/vdso.h
@@ -10,9 +10,6 @@ struct parasite_ctl;
 struct vm_area_list;
 
 extern int vdso_redirect_calls(void *base_to, void *base_from, struct vdso_symtable *to, struct vdso_symtable *from);
-extern int vdso_fill_symtable(char *mem, size_t size,struct vdso_symtable *t);
-extern int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size);
-extern int vdso_proxify(char *who, struct vdso_symtable *sym_rt, VmaEntry *vma_entry, unsigned long vdso_rt_parked_at);
 extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
 			       struct vm_area_list *vma_area_list);
 
diff --git a/arch/arm/vdso-pie.c b/arch/arm/vdso-pie.c
index 1f094cb..5253d6e 100644
--- a/arch/arm/vdso-pie.c
+++ b/arch/arm/vdso-pie.c
@@ -15,18 +15,3 @@ int vdso_redirect_calls(void *base_to, void *base_from,
 {
 	return 0;
 }
-
-int vdso_fill_symtable(char *mem, size_t size, struct vdso_symtable *t)
-{
-	return 0;
-}
-
-int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size)
-{
-	return 0;
-}
-
-int vdso_proxify(char *who, struct vdso_symtable *sym_rt, VmaEntry *vma, unsigned long vdso_rt_parked_at)
-{
-	return 0;
-}
diff --git a/arch/x86/include/asm/vdso.h b/arch/x86/include/asm/vdso.h
index 56d8007..a702471 100644
--- a/arch/x86/include/asm/vdso.h
+++ b/arch/x86/include/asm/vdso.h
@@ -10,9 +10,6 @@ struct parasite_ctl;
 struct vm_area_list;
 
 extern int vdso_redirect_calls(void *base_to, void *base_from, struct vdso_symtable *to, struct vdso_symtable *from);
-extern int vdso_fill_symtable(char *mem, size_t size,struct vdso_symtable *t);
-extern int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size);
-extern int vdso_proxify(char *who, struct vdso_symtable *sym_rt, VmaEntry *vma_entry, unsigned long vdso_rt_parked_at);
 extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
 			       struct vm_area_list *vma_area_list);
 
diff --git a/arch/x86/vdso-pie.c b/arch/x86/vdso-pie.c
index 64362e0..9e36a2c 100644
--- a/arch/x86/vdso-pie.c
+++ b/arch/x86/vdso-pie.c
@@ -57,253 +57,4 @@ int vdso_redirect_calls(void *base_to, void *base_from,
 	return 0;
 }
 
-static unsigned int get_symbol_index(char *symbol, char *symbols[], size_t size)
-{
-	unsigned int i;
-
-	for (i = 0; symbol && i < size; i++) {
-		if (!builtin_strcmp(symbol, symbols[i]))
-			return i;
-	}
-
-	return VDSO_SYMBOL_MAX;
-}
-
-/* Check if pointer is out-of-bound */
-static bool __ptr_oob(void *ptr, void *start, size_t size)
-{
-	void *end = (void *)((unsigned long)start + size);
-	return ptr > end || ptr < start;
-}
-
-int vdso_fill_symtable(char *mem, size_t size, struct vdso_symtable *t)
-{
-	Elf64_Ehdr *ehdr = (void *)mem;
-	Elf64_Shdr *shdr, *shdr_strtab;
-	Elf64_Shdr *shdr_dynsym;
-	Elf64_Shdr *shdr_dynstr;
-	Elf64_Phdr *phdr;
-	Elf64_Shdr *text;
-	Elf64_Sym *sym;
-
-	char *section_names, *dynsymbol_names;
-
-	unsigned long base = VDSO_BAD_ADDR;
-	unsigned int i, j, k;
-
-	/*
-	 * Elf header bytes. For detailed
-	 * description see Elf specification.
-	 */
-	char vdso_ident[] = {
-		0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	};
-
-	char *vdso_x86_symbols[VDSO_SYMBOL_MAX] = {
-		[VDSO_SYMBOL_GETTIMEOFDAY]	= VDSO_SYMBOL_GETTIMEOFDAY_NAME,
-		[VDSO_SYMBOL_GETCPU]		= VDSO_SYMBOL_GETCPU_NAME,
-		[VDSO_SYMBOL_CLOCK_GETTIME]	= VDSO_SYMBOL_CLOCK_GETTIME_NAME,
-		[VDSO_SYMBOL_TIME]		= VDSO_SYMBOL_TIME_NAME,
-	};
-
-	BUILD_BUG_ON(sizeof(vdso_ident) != sizeof(ehdr->e_ident));
-
-	pr_debug("Parsing at %lx %lx\n",
-		 (long)mem, (long)mem + (long)size);
-
-	/*
-	 * Make sure it's a file we support.
-	 */
-	if (builtin_memcmp(ehdr->e_ident, vdso_ident, sizeof(vdso_ident))) {
-		pr_debug("Elf header magic mismatch\n");
-		goto err;
-	}
-
-	/*
-	 * Figure out base virtual address.
-	 */
-	phdr = (void *)&mem[ehdr->e_phoff];
-	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
-		if (__ptr_oob(phdr, mem, size))
-			goto err;
-		if (phdr->p_type == PT_LOAD) {
-			base = phdr->p_vaddr;
-			break;
-		}
-	}
-	if (base != VDSO_BAD_ADDR) {
-		pr_debug("Base address %lx\n", base);
-	} else {
-		pr_debug("No base address found\n");
-		goto err;
-	}
-
-	/*
-	 * Where the section names lays.
-	 */
-	if (ehdr->e_shstrndx == SHN_UNDEF) {
-		pr_err("Section names are not found\n");
-		goto err;
-	}
-
-	shdr = (void *)&mem[ehdr->e_shoff];
-	shdr_strtab = &shdr[ehdr->e_shstrndx];
-	if (__ptr_oob(shdr_strtab, mem, size))
-		goto err;
-
-	section_names = (void *)&mem[shdr_strtab->sh_offset];
-	shdr_dynsym = shdr_dynstr = text = NULL;
-
-	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
-		if (__ptr_oob(shdr, mem, size))
-			goto err;
-		if (__ptr_oob(&section_names[shdr->sh_name], mem, size))
-			goto err;
-
-#if 0
-		pr_debug("section: %2d -> %s\n",
-			 i, &section_names[shdr->sh_name]);
-#endif
-
-		if (shdr->sh_type == SHT_DYNSYM &&
-		    builtin_strcmp(&section_names[shdr->sh_name],
-				   ".dynsym") == 0) {
-			shdr_dynsym = shdr;
-		} else if (shdr->sh_type == SHT_STRTAB &&
-			   builtin_strcmp(&section_names[shdr->sh_name],
-					  ".dynstr") == 0) {
-			shdr_dynstr = shdr;
-		} else if (shdr->sh_type == SHT_PROGBITS &&
-			   builtin_strcmp(&section_names[shdr->sh_name],
-					  ".text") == 0) {
-			text = shdr;
-		}
-	}
-
-	if (!shdr_dynsym || !shdr_dynstr || !text) {
-		pr_debug("No required sections found\n");
-		goto err;
-	}
-
-	dynsymbol_names = (void *)&mem[shdr_dynstr->sh_offset];
-	if (__ptr_oob(dynsymbol_names, mem, size)	||
-	    __ptr_oob(shdr_dynsym, mem, size)		||
-	    __ptr_oob(text, mem, size))
-		goto err;
-
-	/*
-	 * Walk over global symbols and choose ones we need.
-	 */
-	j = shdr_dynsym->sh_size / sizeof(*sym);
-	sym = (void *)&mem[shdr_dynsym->sh_offset];
-
-	for (i = 0; i < j; i++, sym++) {
-		if (__ptr_oob(sym, mem, size))
-			goto err;
-
-		if (ELF64_ST_BIND(sym->st_info) != STB_GLOBAL ||
-		    ELF64_ST_TYPE(sym->st_info) != STT_FUNC)
-			continue;
-
-		if (__ptr_oob(&dynsymbol_names[sym->st_name], mem, size))
-			goto err;
-
-		k = get_symbol_index(&dynsymbol_names[sym->st_name],
-				     vdso_x86_symbols,
-				     ARRAY_SIZE(vdso_x86_symbols));
-		if (k != VDSO_SYMBOL_MAX) {
-			builtin_memcpy(t->symbols[k].name, vdso_x86_symbols[k],
-				       sizeof(t->symbols[k].name));
-			t->symbols[k].offset = (unsigned long)sym->st_value - base;
-#if 0
-			pr_debug("symbol: %#-16lx %2d %s\n",
-				 t->symbols[k].offset, sym->st_shndx, t->symbols[k].name);
-#endif
-		}
-	}
-	return 0;
-err:
-	return -1;
-}
-
-int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size)
-{
-	unsigned long addr;
-
-	pr_debug("Remap %s %lx -> %lx\n", who, from, to);
-
-	addr = sys_mremap(from, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, to);
-	if (addr != to) {
-		pr_err("Unable to remap %lx -> %lx %lx\n",
-		       from, to, addr);
-		return -1;
-	}
 
-	return 0;
-}
-
-int vdso_proxify(char *who, struct vdso_symtable *sym_rt, VmaEntry *vma, unsigned long vdso_rt_parked_at)
-{
-	struct vdso_symtable s = VDSO_SYMTABLE_INIT;
-	size_t size = vma_entry_len(vma);
-	bool remap_rt = true;
-
-	/*
-	 * Find symbols in dumpee vdso.
-	 */
-	if (vdso_fill_symtable((void *)vma->start, size, &s))
-		return -1;
-
-	if (size == vdso_vma_size(sym_rt)) {
-		int i;
-
-		for (i = 0; i < ARRAY_SIZE(s.symbols); i++) {
-			if (s.symbols[i].offset != sym_rt->symbols[i].offset) {
-				remap_rt = false;
-				break;
-			}
-		}
-	} else
-		remap_rt = false;
-
-	/*
-	 * Easy case -- the vdso from image has same offsets and size
-	 * as runtime, so we simply remap runtime vdso to dumpee position
-	 * without generating any proxy.
-	 */
-	if (remap_rt) {
-		pr_info("Runtime vdso matches dumpee, remap inplace\n");
-
-		if (sys_munmap((void *)vma->start, size)) {
-			pr_err("Failed to unmap %s\n", who);
-			return -1;
-		}
-
-		return vdso_remap(who, vdso_rt_parked_at, vma->start, size);
-	}
-
-	/*
-	 * Now complex case -- we need to proxify calls. We redirect
-	 * calls from dumpee vdso to runtime vdso, making dumpee
-	 * to operate as proxy vdso.
-	 */
-	pr_info("Runtime vdso mismatches dumpee, generate proxy\n");
-
-	if (vdso_redirect_calls((void *)vdso_rt_parked_at,
-				(void *)vma->start,
-				sym_rt, &s)) {
-		pr_err("Failed to proxify dumpee contents\n");
-		return -1;
-	}
-
-	/*
-	 * Put a special mark into runtime vdso, thus at next checkpoint
-	 * routine we could detect this vdso and do not dump it, since
-	 * it's auto-generated every new session if proxy required.
-	 */
-	sys_mprotect((void *)vdso_rt_parked_at,  vdso_vma_size(sym_rt), PROT_WRITE);
-	vdso_put_mark((void *)vdso_rt_parked_at, vma->start);
-	sys_mprotect((void *)vdso_rt_parked_at,  vdso_vma_size(sym_rt), VDSO_PROT);
-	return 0;
-}
diff --git a/include/vdso.h b/include/vdso.h
index 3f2f01f..8c748ab 100644
--- a/include/vdso.h
+++ b/include/vdso.h
@@ -110,5 +110,8 @@ static inline void vdso_put_mark(void *where, unsigned long proxy_addr)
 extern struct vdso_symtable vdso_sym_rt;
 extern u64 vdso_pfn;
 extern int vdso_init(void);
+extern int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size);
+extern int vdso_fill_symtable(char *mem, size_t size, struct vdso_symtable *t);
+extern int vdso_proxify(char *who, struct vdso_symtable *sym_rt, VmaEntry *vma_entry, unsigned long vdso_rt_parked_at);
 
 #endif /* __CR_VDSO_H__ */
diff --git a/pie/Makefile b/pie/Makefile
index 5902804..cf59bfc 100644
--- a/pie/Makefile
+++ b/pie/Makefile
@@ -10,6 +10,7 @@ parasite-asm-e		+= $(ARCH_DIR)/parasite-head.o
 parasite-libs-e		+= $(SYSCALL-LIB)
 
 restorer-obj-y		+= restorer.o
+restorer-obj-y		+= $(VDSO_O)
 restorer-obj-e		+= $(ARCH_DIR)/restorer.o
 restorer-obj-e		+= $(ARCH_DIR)/vdso-pie.o
 restorer-libs-e		+= $(SYSCALL-LIB)
diff --git a/pie/vdso-stub.c b/pie/vdso-stub.c
new file mode 100644
index 0000000..3739371
--- /dev/null
+++ b/pie/vdso-stub.c
@@ -0,0 +1,31 @@
+#include <elf.h>
+
+#include <sys/mman.h>
+
+#include "compiler.h"
+#include "vdso.h"
+#include "syscall.h"
+#include "log.h"
+
+#include "asm/string.h"
+
+
+#ifdef LOG_PREFIX
+# undef LOG_PREFIX
+#endif
+#define LOG_PREFIX "vdso: "
+
+int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size)
+{
+	return 0;
+}
+
+int vdso_fill_symtable(char *mem, size_t size, struct vdso_symtable *t)
+{
+	return 0;
+}
+
+int vdso_proxify(char *who, struct vdso_symtable *sym_rt, VmaEntry *vma, unsigned long vdso_rt_parked_at)
+{
+	return 0;
+}
diff --git a/pie/vdso.c b/pie/vdso.c
new file mode 100644
index 0000000..1dcda48
--- /dev/null
+++ b/pie/vdso.c
@@ -0,0 +1,272 @@
+#include <elf.h>
+
+#include <sys/mman.h>
+
+#include "compiler.h"
+#include "vdso.h"
+#include "syscall.h"
+#include "log.h"
+#include "vma.h"
+
+#include "asm/string.h"
+
+
+#ifdef LOG_PREFIX
+# undef LOG_PREFIX
+#endif
+#define LOG_PREFIX "vdso: "
+
+int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size)
+{
+	unsigned long addr;
+
+	pr_debug("Remap %s %lx -> %lx\n", who, from, to);
+
+	addr = sys_mremap(from, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, to);
+	if (addr != to) {
+		pr_err("Unable to remap %lx -> %lx %lx\n",
+		       from, to, addr);
+		return -1;
+	}
+
+	return 0;
+}
+
+static unsigned int get_symbol_index(char *symbol, char *symbols[], size_t size)
+{
+	unsigned int i;
+
+	for (i = 0; symbol && i < size; i++) {
+		if (!builtin_strcmp(symbol, symbols[i]))
+			return i;
+	}
+
+	return VDSO_SYMBOL_MAX;
+}
+
+
+/* Check if pointer is out-of-bound */
+static bool __ptr_oob(void *ptr, void *start, size_t size)
+{
+	void *end = (void *)((unsigned long)start + size);
+	return ptr > end || ptr < start;
+}
+
+int vdso_fill_symtable(char *mem, size_t size, struct vdso_symtable *t)
+{
+	Elf64_Ehdr *ehdr = (void *)mem;
+	Elf64_Shdr *shdr, *shdr_strtab;
+	Elf64_Shdr *shdr_dynsym;
+	Elf64_Shdr *shdr_dynstr;
+	Elf64_Phdr *phdr;
+	Elf64_Shdr *text;
+	Elf64_Sym *sym;
+
+	char *section_names, *dynsymbol_names;
+
+	unsigned long base = VDSO_BAD_ADDR;
+	unsigned int i, j, k;
+
+	/*
+	 * Elf header bytes. For detailed
+	 * description see Elf specification.
+	 */
+	char vdso_ident[] = {
+		0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	};
+
+	char *vdso_x86_symbols[VDSO_SYMBOL_MAX] = {
+		[VDSO_SYMBOL_GETTIMEOFDAY]	= VDSO_SYMBOL_GETTIMEOFDAY_NAME,
+		[VDSO_SYMBOL_GETCPU]		= VDSO_SYMBOL_GETCPU_NAME,
+		[VDSO_SYMBOL_CLOCK_GETTIME]	= VDSO_SYMBOL_CLOCK_GETTIME_NAME,
+		[VDSO_SYMBOL_TIME]		= VDSO_SYMBOL_TIME_NAME,
+	};
+
+	BUILD_BUG_ON(sizeof(vdso_ident) != sizeof(ehdr->e_ident));
+
+	pr_debug("Parsing at %lx %lx\n",
+		 (long)mem, (long)mem + (long)size);
+
+	/*
+	 * Make sure it's a file we support.
+	 */
+	if (builtin_memcmp(ehdr->e_ident, vdso_ident, sizeof(vdso_ident))) {
+		pr_debug("Elf header magic mismatch\n");
+		goto err;
+	}
+
+	/*
+	 * Figure out base virtual address.
+	 */
+	phdr = (void *)&mem[ehdr->e_phoff];
+	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
+		if (__ptr_oob(phdr, mem, size))
+			goto err;
+		if (phdr->p_type == PT_LOAD) {
+			base = phdr->p_vaddr;
+			break;
+		}
+	}
+	if (base != VDSO_BAD_ADDR) {
+		pr_debug("Base address %lx\n", base);
+	} else {
+		pr_debug("No base address found\n");
+		goto err;
+	}
+
+	/*
+	 * Where the section names lays.
+	 */
+	if (ehdr->e_shstrndx == SHN_UNDEF) {
+		pr_err("Section names are not found\n");
+		goto err;
+	}
+
+	shdr = (void *)&mem[ehdr->e_shoff];
+	shdr_strtab = &shdr[ehdr->e_shstrndx];
+	if (__ptr_oob(shdr_strtab, mem, size))
+	{
+		pr_err("shdr_strtab is outside the vDSO\n");
+		goto err;
+	}
+
+	section_names = (void *)&mem[shdr_strtab->sh_offset];
+	shdr_dynsym = shdr_dynstr = text = NULL;
+
+	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
+		if (__ptr_oob(shdr, mem, size))
+			goto err;
+		if (__ptr_oob(&section_names[shdr->sh_name], mem, size))
+			goto err;
+
+#if 0
+		pr_debug("section: %2d -> %s\n",
+			 i, &section_names[shdr->sh_name]);
+#endif
+
+		if (shdr->sh_type == SHT_DYNSYM &&
+		    builtin_strcmp(&section_names[shdr->sh_name],
+				   ".dynsym") == 0) {
+			shdr_dynsym = shdr;
+		} else if (shdr->sh_type == SHT_STRTAB &&
+			   builtin_strcmp(&section_names[shdr->sh_name],
+					  ".dynstr") == 0) {
+			shdr_dynstr = shdr;
+		} else if (shdr->sh_type == SHT_PROGBITS &&
+			   builtin_strcmp(&section_names[shdr->sh_name],
+					  ".text") == 0) {
+			text = shdr;
+		}
+	}
+
+	if (!shdr_dynsym || !shdr_dynstr || !text) {
+		pr_debug("No required sections found\n");
+		goto err;
+	}
+
+	dynsymbol_names = (void *)&mem[shdr_dynstr->sh_offset];
+	if (__ptr_oob(dynsymbol_names, mem, size)	||
+	    __ptr_oob(shdr_dynsym, mem, size)		||
+	    __ptr_oob(text, mem, size))
+		goto err;
+
+	/*
+	 * Walk over global symbols and choose ones we need.
+	 */
+	j = shdr_dynsym->sh_size / sizeof(*sym);
+	sym = (void *)&mem[shdr_dynsym->sh_offset];
+
+	for (i = 0; i < j; i++, sym++) {
+		if (__ptr_oob(sym, mem, size))
+			goto err;
+
+		if (ELF64_ST_BIND(sym->st_info) != STB_GLOBAL ||
+		    ELF64_ST_TYPE(sym->st_info) != STT_FUNC)
+			continue;
+
+		if (__ptr_oob(&dynsymbol_names[sym->st_name], mem, size))
+			goto err;
+
+		k = get_symbol_index(&dynsymbol_names[sym->st_name],
+				     vdso_x86_symbols,
+				     ARRAY_SIZE(vdso_x86_symbols));
+		if (k != VDSO_SYMBOL_MAX) {
+			builtin_memcpy(t->symbols[k].name, vdso_x86_symbols[k],
+				       sizeof(t->symbols[k].name));
+			t->symbols[k].offset = (unsigned long)sym->st_value - base;
+#if 0
+			pr_debug("symbol: %#-16lx %2d %s\n",
+				 t->symbols[k].offset, sym->st_shndx, t->symbols[k].name);
+#endif
+		}
+	}
+	return 0;
+err:
+	return -1;
+}
+
+int vdso_proxify(char *who, struct vdso_symtable *sym_rt, VmaEntry *vma, unsigned long vdso_rt_parked_at)
+{
+	struct vdso_symtable s = VDSO_SYMTABLE_INIT;
+	size_t size = vma_entry_len(vma);
+	bool remap_rt = true;
+
+	/*
+	 * Find symbols in dumpee vdso.
+	 */
+	if (vdso_fill_symtable((void *)vma->start, size, &s))
+		return -1;
+
+	if (size == vdso_vma_size(sym_rt)) {
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(s.symbols); i++) {
+			if (s.symbols[i].offset != sym_rt->symbols[i].offset) {
+				remap_rt = false;
+				break;
+			}
+		}
+	} else
+		remap_rt = false;
+
+	/*
+	 * Easy case -- the vdso from image has same offsets and size
+	 * as runtime, so we simply remap runtime vdso to dumpee position
+	 * without generating any proxy.
+	 */
+	if (remap_rt) {
+		pr_info("Runtime vdso matches dumpee, remap inplace\n");
+
+		if (sys_munmap((void *)vma->start, size)) {
+			pr_err("Failed to unmap %s\n", who);
+			return -1;
+		}
+
+		return vdso_remap(who, vdso_rt_parked_at, vma->start, size);
+	}
+
+	/*
+	 * Now complex case -- we need to proxify calls. We redirect
+	 * calls from dumpee vdso to runtime vdso, making dumpee
+	 * to operate as proxy vdso.
+	 */
+	pr_info("Runtime vdso mismatches dumpee, generate proxy\n");
+
+	if (vdso_redirect_calls((void *)vdso_rt_parked_at,
+				(void *)vma->start,
+				sym_rt, &s)) {
+		pr_err("Failed to proxify dumpee contents\n");
+		return -1;
+	}
+
+	/*
+	 * Put a special mark into runtime vdso, thus at next checkpoint
+	 * routine we could detect this vdso and do not dump it, since
+	 * it's auto-generated every new session if proxy required.
+	 */
+	sys_mprotect((void *)vdso_rt_parked_at,  vdso_vma_size(sym_rt), PROT_WRITE);
+	vdso_put_mark((void *)vdso_rt_parked_at, vma->start);
+	sys_mprotect((void *)vdso_rt_parked_at,  vdso_vma_size(sym_rt), VDSO_PROT);
+	return 0;
+}
-- 
1.7.9.5



More information about the CRIU mailing list