Commit e101026b authored by Dmitry Safonov's avatar Dmitry Safonov Committed by Andrei Vagin

vdso: Don't miss rt-vvar while searching

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: 's avatarDmitry Safonov <dsafonov@virtuozzo.com>
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
parent 33b5b417
...@@ -106,9 +106,70 @@ static bool not_vvar_or_vdso(struct vma_area *vma) ...@@ -106,9 +106,70 @@ static bool not_vvar_or_vdso(struct vma_area *vma)
if (vma->e->flags & MAP_GROWSDOWN) if (vma->e->flags & MAP_GROWSDOWN)
return true; return true;
BUILD_BUG_ON(!(VDSO_PROT & VVAR_PROT));
if ((vma->e->prot & VVAR_PROT) != VVAR_PROT)
return true;
return false; 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 * The VMAs list might have proxy vdso/vvar areas left
* from previous dump/restore cycle so we need to detect * 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, ...@@ -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 orig_vvar_addr = VVAR_BAD_ADDR;
unsigned long rt_vvar_addr = VVAR_BAD_ADDR; unsigned long rt_vvar_addr = VVAR_BAD_ADDR;
struct vma_area *rt_vdso_marked = NULL; struct vma_area *rt_vdso_marked = NULL;
struct vma_area *rt_vvar_marked = NULL;
struct parasite_vdso_vma_entry *args; struct parasite_vdso_vma_entry *args;
int fd = -1, exit_code = -1; int fd = -1, exit_code = -1;
enum vdso_check_t vcheck; enum vdso_check_t vcheck;
...@@ -143,24 +203,6 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, ...@@ -143,24 +203,6 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
if (not_vvar_or_vdso(vma)) if (not_vvar_or_vdso(vma))
continue; 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) if ((vma->e->prot & VDSO_PROT) != VDSO_PROT)
continue; continue;
...@@ -223,45 +265,8 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, ...@@ -223,45 +265,8 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
} }
} }
/* drop_rt_vdso(vma_area_list, orig_vdso_addr, orig_vvar_addr,
* There is marked vdso, it means such vdso is autogenerated rt_vvar_addr, rt_vdso_marked);
* 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--;
}
}
exit_code = 0; exit_code = 0;
err: err:
close_safe(&fd); close_safe(&fd);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment