[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