mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-18 00:58:31 +00:00
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: Dmitry Safonov <dsafonov@virtuozzo.com> Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
This commit is contained in:
parent
33b5b417da
commit
e101026bdf
1 changed files with 63 additions and 58 deletions
121
criu/vdso.c
121
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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue