[CRIU] [PATCH 4/5] vdso: Make parasite_fixup_vdso being arch implemented

Cyrill Gorcunov gorcunov at openvz.org
Fri May 31 02:28:44 EDT 2013


parasite_fixup_vdso is not worth calling on arm at all,
moreover it might try to read pfn for addresses greater
than TASK_SIZE, leading to dump interruption. Lets make
it arch dependent.

Reported-by: Alexander Kartashov <alekskartashov at parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 arch/arm/include/asm/vdso.h |   4 ++
 arch/arm/vdso.c             |   9 ++++
 arch/x86/include/asm/vdso.h |   4 ++
 arch/x86/vdso.c             | 123 ++++++++++++++++++++++++++++++++++++++++++++
 parasite-syscall.c          | 120 ------------------------------------------
 5 files changed, 140 insertions(+), 120 deletions(-)

diff --git a/arch/arm/include/asm/vdso.h b/arch/arm/include/asm/vdso.h
index 6ffdd74..56d8007 100644
--- a/arch/arm/include/asm/vdso.h
+++ b/arch/arm/include/asm/vdso.h
@@ -6,10 +6,14 @@
 #include "protobuf/vma.pb-c.h"
 
 struct vdso_symtable;
+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);
 
 #endif /* __CR_ASM_VDSO_H__ */
diff --git a/arch/arm/vdso.c b/arch/arm/vdso.c
index fa40fe2..26b539f 100644
--- a/arch/arm/vdso.c
+++ b/arch/arm/vdso.c
@@ -1,5 +1,8 @@
 #include <sys/types.h>
 
+#include "asm/parasite-syscall.h"
+
+#include "parasite-syscall.h"
 #include "vdso.h"
 #include "log.h"
 
@@ -15,3 +18,9 @@ int vdso_init(void)
 {
 	return 0;
 }
+
+int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
+			struct vm_area_list *vma_area_list)
+{
+	return 0;
+}
diff --git a/arch/x86/include/asm/vdso.h b/arch/x86/include/asm/vdso.h
index 6ffdd74..56d8007 100644
--- a/arch/x86/include/asm/vdso.h
+++ b/arch/x86/include/asm/vdso.h
@@ -6,10 +6,14 @@
 #include "protobuf/vma.pb-c.h"
 
 struct vdso_symtable;
+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);
 
 #endif /* __CR_ASM_VDSO_H__ */
diff --git a/arch/x86/vdso.c b/arch/x86/vdso.c
index 6fc00be..a4687ea 100644
--- a/arch/x86/vdso.c
+++ b/arch/x86/vdso.c
@@ -10,7 +10,10 @@
 #include <sys/mman.h>
 
 #include "asm/types.h"
+#include "asm/parasite-syscall.h"
 
+#include "parasite-syscall.h"
+#include "parasite.h"
 #include "compiler.h"
 #include "crtools.h"
 #include "kerndat.h"
@@ -95,3 +98,123 @@ out:
 	close(fd);
 	return ret;
 }
+
+/*
+ * Find out proxy vdso vma and drop it from the list. Also
+ * fix vdso status on vmas if wrong status found.
+ */
+int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
+			struct vm_area_list *vma_area_list)
+{
+	unsigned long proxy_addr = VDSO_BAD_ADDR;
+	struct parasite_vdso_vma_entry *args;
+	struct vma_area *marked = NULL;
+	struct vma_area *vma;
+	int fd, ret = -1;
+	off_t off;
+	u64 pfn;
+
+	args = parasite_args(ctl, struct parasite_vdso_vma_entry);
+	fd = open_proc(pid, "pagemap");
+	if (fd < 0)
+		return -1;
+
+	list_for_each_entry(vma, &vma_area_list->h, list) {
+		if (!vma_area_is(vma, VMA_AREA_REGULAR))
+			continue;
+
+		if ((vma->vma.prot & VDSO_PROT) != VDSO_PROT)
+			continue;
+
+		/*
+		 * I need to poke every potentially marked vma,
+		 * otherwise if task never called for vdso functions
+		 * page frame number won't be reported.
+		 */
+		args->start = vma->vma.start;
+		args->len = vma_area_len(vma);
+
+		if (parasite_execute_daemon(PARASITE_CMD_CHECK_VDSO_MARK, ctl)) {
+			pr_err("vdso: Parasite failed to poke for mark\n");
+			ret = -1;
+			goto err;
+		}
+
+		/*
+		 * Defer handling marked vdso.
+		 */
+		if (unlikely(args->is_marked)) {
+			BUG_ON(args->proxy_addr == VDSO_BAD_ADDR);
+			BUG_ON(marked);
+			marked = vma;
+			proxy_addr = args->proxy_addr;
+			continue;
+		}
+
+		off = (vma->vma.start / PAGE_SIZE) * sizeof(u64);
+		if (lseek(fd, off, SEEK_SET) != off) {
+			pr_perror("Failed to seek address %lx\n",
+				  (long unsigned int)vma->vma.start);
+			ret = -1;
+			goto err;
+		}
+
+		ret = read(fd, &pfn, sizeof(pfn));
+		if (ret < 0 || ret != sizeof(pfn)) {
+			pr_perror("Can't read pme for pid %d", pid);
+			ret = -1;
+			goto err;
+		}
+
+		pfn = PME_PFRAME(pfn);
+		BUG_ON(!pfn);
+
+		/*
+		 * Set proper VMA statuses.
+		 */
+		if (pfn == vdso_pfn) {
+			if (!vma_area_is(vma, VMA_AREA_VDSO)) {
+				pr_debug("vdso: Restore status by pfn at %lx\n",
+					 (long)vma->vma.start);
+				vma->vma.status |= VMA_AREA_VDSO;
+			}
+		} else {
+			if (vma_area_is(vma, VMA_AREA_VDSO)) {
+				pr_debug("vdso: Drop mishinted status at %lx\n",
+					 (long)vma->vma.start);
+				vma->vma.status &= ~VMA_AREA_VDSO;
+			}
+		}
+	}
+
+	/*
+	 * There is marked vdso, it means such vdso is autogenerated
+	 * and must be dropped from vma list.
+	 */
+	if (marked) {
+		pr_debug("vdso: Found marked at %lx (proxy at %lx)\n",
+			 (long)marked->vma.start, (long)proxy_addr);
+
+		/*
+		 * Don't forget to restore the proxy vdso status, since
+		 * it's being not recognized by the kernel as vdso.
+		 */
+		list_for_each_entry(vma, &vma_area_list->h, list) {
+			if (vma->vma.start == proxy_addr) {
+				vma->vma.status |= VMA_AREA_REGULAR | VMA_AREA_VDSO;
+				pr_debug("vdso: Restore proxy status at %lx\n",
+					 (long)vma->vma.start);
+				break;
+			}
+		}
+
+		pr_debug("vdso: Droppping marked vdso at %lx\n",
+			 (long)vma->vma.start);
+		list_del(&marked->list);
+		xfree(marked);
+	}
+	ret = 0;
+err:
+	close(fd);
+	return ret;
+}
diff --git a/parasite-syscall.c b/parasite-syscall.c
index e548e30..9de45c2 100644
--- a/parasite-syscall.c
+++ b/parasite-syscall.c
@@ -663,126 +663,6 @@ err:
 	return ret;
 }
 
-/*
- * Find out proxy vdso vma and drop it from the list. Also
- * fix vdso status on vmas if wrong status found.
- */
-int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
-			struct vm_area_list *vma_area_list)
-{
-	unsigned long proxy_addr = VDSO_BAD_ADDR;
-	struct parasite_vdso_vma_entry *args;
-	struct vma_area *marked = NULL;
-	struct vma_area *vma;
-	int fd, ret = -1;
-	off_t off;
-	u64 pfn;
-
-	args = parasite_args(ctl, struct parasite_vdso_vma_entry);
-	fd = open_proc(pid, "pagemap");
-	if (fd < 0)
-		return -1;
-
-	list_for_each_entry(vma, &vma_area_list->h, list) {
-		if (!vma_area_is(vma, VMA_AREA_REGULAR))
-			continue;
-
-		if ((vma->vma.prot & VDSO_PROT) != VDSO_PROT)
-			continue;
-
-		/*
-		 * I need to poke every potentially marked vma,
-		 * otherwise if task never called for vdso functions
-		 * page frame number won't be reported.
-		 */
-		args->start = vma->vma.start;
-		args->len = vma_area_len(vma);
-
-		if (parasite_execute_daemon(PARASITE_CMD_CHECK_VDSO_MARK, ctl)) {
-			pr_err("vdso: Parasite failed to poke for mark\n");
-			ret = -1;
-			goto err;
-		}
-
-		/*
-		 * Defer handling marked vdso.
-		 */
-		if (unlikely(args->is_marked)) {
-			BUG_ON(args->proxy_addr == VDSO_BAD_ADDR);
-			BUG_ON(marked);
-			marked = vma;
-			proxy_addr = args->proxy_addr;
-			continue;
-		}
-
-		off = (vma->vma.start / PAGE_SIZE) * sizeof(u64);
-		if (lseek(fd, off, SEEK_SET) != off) {
-			pr_perror("Failed to seek address %lx\n",
-				  (long unsigned int)vma->vma.start);
-			ret = -1;
-			goto err;
-		}
-
-		ret = read(fd, &pfn, sizeof(pfn));
-		if (ret < 0 || ret != sizeof(pfn)) {
-			pr_perror("Can't read pme for pid %d", pid);
-			ret = -1;
-			goto err;
-		}
-
-		pfn = PME_PFRAME(pfn);
-		BUG_ON(!pfn);
-
-		/*
-		 * Set proper VMA statuses.
-		 */
-		if (pfn == vdso_pfn) {
-			if (!vma_area_is(vma, VMA_AREA_VDSO)) {
-				pr_debug("vdso: Restore status by pfn at %lx\n",
-					 (long)vma->vma.start);
-				vma->vma.status |= VMA_AREA_VDSO;
-			}
-		} else {
-			if (vma_area_is(vma, VMA_AREA_VDSO)) {
-				pr_debug("vdso: Drop mishinted status at %lx\n",
-					 (long)vma->vma.start);
-				vma->vma.status &= ~VMA_AREA_VDSO;
-			}
-		}
-	}
-
-	/*
-	 * There is marked vdso, it means such vdso is autogenerated
-	 * and must be dropped from vma list.
-	 */
-	if (marked) {
-		pr_debug("vdso: Found marked at %lx (proxy at %lx)\n",
-			 (long)marked->vma.start, (long)proxy_addr);
-
-		/*
-		 * Don't forget to restore the proxy vdso status, since
-		 * it's being not recognized by the kernel as vdso.
-		 */
-		list_for_each_entry(vma, &vma_area_list->h, list) {
-			if (vma->vma.start == proxy_addr) {
-				vma->vma.status |= VMA_AREA_REGULAR | VMA_AREA_VDSO;
-				pr_debug("vdso: Restore proxy status at %lx\n",
-					 (long)vma->vma.start);
-				break;
-			}
-		}
-
-		pr_debug("vdso: Droppping marked vdso at %lx\n",
-			 (long)vma->vma.start);
-		list_del(&marked->list);
-		xfree(marked);
-	}
-	ret = 0;
-err:
-	close(fd);
-	return ret;
-}
-
 int parasite_get_proc_fd_seized(struct parasite_ctl *ctl)
 {
 	int ret = -1, fd;
-- 
1.8.1.4



More information about the CRIU mailing list