[CRIU] [PATCH 04/11] vdso: Don't miss rt-vvar while searching

Dmitry Safonov dsafonov at virtuozzo.com
Mon Jul 17 15:39:55 MSK 2017


As rt-vvar can be placed lower (by address) than rt-vdso,
it likely will go earlier in vma_area_list.
That means that at the moment, when we've found rt-vdso,
we already passed rt-vvar and rt_vvar_marked pointer
will not be initialized.

Search for rt-vvar during the second vma list traverse,
so we will always find it if it's present.

Signed-off-by: Dmitry Safonov <dsafonov at virtuozzo.com>
---
 criu/vdso.c | 121 +++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 63 insertions(+), 58 deletions(-)

diff --git a/criu/vdso.c b/criu/vdso.c
index ffe97b95e28f..30c22aabd6ce 100644
--- a/criu/vdso.c
+++ b/criu/vdso.c
@@ -106,9 +106,70 @@ static bool not_vvar_or_vdso(struct vma_area *vma)
 	if (vma->e->flags & MAP_GROWSDOWN)
 		return true;
 
+	BUILD_BUG_ON(!(VDSO_PROT & VVAR_PROT));
+	if ((vma->e->prot & VVAR_PROT) != VVAR_PROT)
+		return true;
+
 	return false;
 }
 
+static void drop_rt_vdso(struct vm_area_list *vma_area_list,
+	unsigned long orig_vdso_addr, unsigned long orig_vvar_addr,
+	unsigned long rt_vvar_addr, struct vma_area *rt_vdso_marked)
+{
+	struct vma_area *rt_vvar_marked = NULL;
+	struct vma_area *vma;
+
+	if (!rt_vdso_marked)
+		return;
+
+	/*
+	 * There is marked vdso, it means such vdso is autogenerated
+	 * and must be dropped from vma list.
+	 */
+	pr_debug("vdso: Found marked at %lx (orig vDSO at %lx VVAR at %lx)\n",
+		(long)rt_vdso_marked->e->start, orig_vdso_addr, orig_vvar_addr);
+
+	/*
+	 * Don't forget to restore the proxy vdso/vvar status, since
+	 * they're unknown to the kernel.
+	 * Also BTW search for rt-vvar to remove it later.
+	 */
+	list_for_each_entry(vma, &vma_area_list->h, list) {
+		if (vma->e->start == orig_vdso_addr) {
+			vma->e->status |= VMA_AREA_REGULAR | VMA_AREA_VDSO;
+			pr_debug("vdso: Restore orig vDSO status at %lx\n",
+					(long)vma->e->start);
+		} else if (vma->e->start == orig_vvar_addr) {
+			vma->e->status |= VMA_AREA_REGULAR | VMA_AREA_VVAR;
+			pr_debug("vdso: Restore orig VVAR status at %lx\n",
+					(long)vma->e->start);
+		} else if (rt_vvar_addr != VVAR_BAD_ADDR &&
+				rt_vvar_addr == vma->e->start) {
+			BUG_ON(rt_vvar_marked);
+			if (not_vvar_or_vdso(vma)) {
+				pr_warn("Mark in rt-vdso points to vma, that doesn't look like vvar - skipping unmap\n");
+				continue;
+			}
+			rt_vvar_marked = vma;
+		}
+	}
+
+	pr_debug("vdso: Droppping marked vdso at %lx\n",
+			(long)rt_vdso_marked->e->start);
+	list_del(&rt_vdso_marked->list);
+	xfree(rt_vdso_marked);
+	vma_area_list->nr--;
+
+	if (rt_vvar_marked) {
+		pr_debug("vdso: Droppping marked vvar at %lx\n",
+				(long)rt_vvar_marked->e->start);
+		list_del(&rt_vvar_marked->list);
+		xfree(rt_vvar_marked);
+		vma_area_list->nr--;
+	}
+}
+
 /*
  * The VMAs list might have proxy vdso/vvar areas left
  * from previous dump/restore cycle so we need to detect
@@ -122,7 +183,6 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
 	unsigned long orig_vvar_addr = VVAR_BAD_ADDR;
 	unsigned long rt_vvar_addr = VVAR_BAD_ADDR;
 	struct vma_area *rt_vdso_marked = NULL;
-	struct vma_area *rt_vvar_marked = NULL;
 	struct parasite_vdso_vma_entry *args;
 	int fd = -1, exit_code = -1;
 	enum vdso_check_t vcheck;
@@ -143,24 +203,6 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
 		if (not_vvar_or_vdso(vma))
 			continue;
 
-		/*
-		 * It might be possible VVAR area from marked
-		 * vDSO zone, we need to detect it earlier than
-		 * VDSO_PROT test because VVAR_PROT is a subset
-		 * of it but don't yield continue here,
-		 * sigh... what a mess.
-		 */
-		BUILD_BUG_ON(!(VDSO_PROT & VVAR_PROT));
-
-		if ((vma->e->prot & VVAR_PROT) == VVAR_PROT) {
-			if (rt_vvar_addr != VVAR_BAD_ADDR &&
-			    rt_vvar_addr == vma->e->start) {
-				BUG_ON(rt_vvar_marked);
-				rt_vvar_marked = vma;
-				continue;
-			}
-		}
-
 		if ((vma->e->prot & VDSO_PROT) != VDSO_PROT)
 			continue;
 
@@ -223,45 +265,8 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
 		}
 	}
 
-	/*
-	 * There is marked vdso, it means such vdso is autogenerated
-	 * and must be dropped from vma list.
-	 */
-	if (rt_vdso_marked) {
-		pr_debug("vdso: Found marked at %lx (orig vDSO at %lx VVAR at %lx)\n",
-			 (long)rt_vdso_marked->e->start,
-			 (long)orig_vdso_addr, (long)orig_vvar_addr);
-
-		/*
-		 * Don't forget to restore the proxy vdso/vvar status, since
-		 * it's unknown to the kernel.
-		 */
-		list_for_each_entry(vma, &vma_area_list->h, list) {
-			if (vma->e->start == orig_vdso_addr) {
-				vma->e->status |= VMA_AREA_REGULAR | VMA_AREA_VDSO;
-				pr_debug("vdso: Restore orig vDSO status at %lx\n",
-					 (long)vma->e->start);
-			} else if (vma->e->start == orig_vvar_addr) {
-				vma->e->status |= VMA_AREA_REGULAR | VMA_AREA_VVAR;
-				pr_debug("vdso: Restore orig VVAR status at %lx\n",
-					 (long)vma->e->start);
-			}
-		}
-
-		pr_debug("vdso: Droppping marked vdso at %lx\n",
-			 (long)rt_vdso_marked->e->start);
-		list_del(&rt_vdso_marked->list);
-		xfree(rt_vdso_marked);
-		vma_area_list->nr--;
-
-		if (rt_vvar_marked) {
-			pr_debug("vdso: Droppping marked vvar at %lx\n",
-				 (long)rt_vvar_marked->e->start);
-			list_del(&rt_vvar_marked->list);
-			xfree(rt_vvar_marked);
-			vma_area_list->nr--;
-		}
-	}
+	drop_rt_vdso(vma_area_list, orig_vdso_addr, orig_vvar_addr,
+			rt_vvar_addr, rt_vdso_marked);
 	exit_code = 0;
 err:
 	close_safe(&fd);
-- 
2.13.1



More information about the CRIU mailing list