Commit 0ae67a77 authored by Cyrill Gorcunov's avatar Cyrill Gorcunov Committed by Pavel Emelyanov

vdso: Escape double dumping of rt-vdso if proxy present

In case if we have created vdso proxy the rt-vdso should
not be dumped because it will be re-created on next restore
anyway. Thus with help of parasite service routine find
the rt-vdso and tear it off from VMAs list.
Signed-off-by: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 528106a5
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
#include "kerndat.h" #include "kerndat.h"
#include "stats.h" #include "stats.h"
#include "mem.h" #include "mem.h"
#include "vdso.h"
#include "page-pipe.h" #include "page-pipe.h"
#include "vdso.h" #include "vdso.h"
...@@ -1484,6 +1485,12 @@ static int dump_one_task(struct pstree_item *item) ...@@ -1484,6 +1485,12 @@ static int dump_one_task(struct pstree_item *item)
} }
} }
ret = parasite_fixup_vdso(parasite_ctl, pid, &vmas);
if (ret) {
pr_err("Can't fixup vdso VMAs (pid: %d)\n", pid);
goto err_cure_fdset;
}
ret = parasite_dump_misc_seized(parasite_ctl, &misc); ret = parasite_dump_misc_seized(parasite_ctl, &misc);
if (ret) { if (ret) {
pr_err("Can't dump misc (pid: %d)\n", pid); pr_err("Can't dump misc (pid: %d)\n", pid);
......
...@@ -84,4 +84,7 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret, ...@@ -84,4 +84,7 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret,
extern int __parasite_execute(struct parasite_ctl *ctl, pid_t pid, user_regs_struct_t *regs); extern int __parasite_execute(struct parasite_ctl *ctl, pid_t pid, user_regs_struct_t *regs);
extern bool arch_can_dump_task(pid_t pid); extern bool arch_can_dump_task(pid_t pid);
extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
struct vm_area_list *vma_area_list);
#endif /* __CR_PARASITE_SYSCALL_H__ */ #endif /* __CR_PARASITE_SYSCALL_H__ */
...@@ -35,6 +35,7 @@ enum { ...@@ -35,6 +35,7 @@ enum {
PARASITE_CMD_DRAIN_FDS, PARASITE_CMD_DRAIN_FDS,
PARASITE_CMD_GET_PROC_FD, PARASITE_CMD_GET_PROC_FD,
PARASITE_CMD_DUMP_TTY, PARASITE_CMD_DUMP_TTY,
PARASITE_CMD_CHECK_VDSO_MARK,
PARASITE_CMD_MAX, PARASITE_CMD_MAX,
}; };
...@@ -60,6 +61,13 @@ struct parasite_vma_entry ...@@ -60,6 +61,13 @@ struct parasite_vma_entry
int prot; int prot;
}; };
struct parasite_vdso_vma_entry {
unsigned long start;
unsigned long len;
unsigned long proxy_addr;
int is_marked;
};
struct parasite_dump_pages_args { struct parasite_dump_pages_args {
unsigned int nr_vmas; unsigned int nr_vmas;
unsigned int add_prot; unsigned int add_prot;
......
...@@ -99,6 +99,13 @@ struct vdso_mark { ...@@ -99,6 +99,13 @@ struct vdso_mark {
#define INIT_VDSO_MARK(m) \ #define INIT_VDSO_MARK(m) \
*(m) = (struct vdso_mark)VDSO_MARK_INIT *(m) = (struct vdso_mark)VDSO_MARK_INIT
static inline bool is_vdso_mark(void *addr)
{
struct vdso_mark *m = addr;
return m->signature == VDSO_MARK_SIGNATURE &&
m->proxy_addr != VDSO_BAD_ADDR;
}
extern struct vdso_symtable vdso_sym_rt; extern struct vdso_symtable vdso_sym_rt;
extern u64 vdso_pfn; extern u64 vdso_pfn;
......
...@@ -20,9 +20,11 @@ ...@@ -20,9 +20,11 @@
#include "parasite.h" #include "parasite.h"
#include "crtools.h" #include "crtools.h"
#include "namespaces.h" #include "namespaces.h"
#include "kerndat.h"
#include "pstree.h" #include "pstree.h"
#include "net.h" #include "net.h"
#include "mem.h" #include "mem.h"
#include "vdso.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -511,6 +513,125 @@ err: ...@@ -511,6 +513,125 @@ err:
return ret; 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(PARASITE_CMD_CHECK_VDSO_MARK, ctl)) {
pr_err("vdso: Parasite failed to poke for mark\n");
ret = -1;
goto err;
}
off = (vma->vma.start / PAGE_SIZE) * sizeof(u64);
if (lseek(fd, off, SEEK_SET) != off) {
pr_perror("Failed to seek address %lx\n", 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);
/*
* 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;
}
/*
* 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 parasite_get_proc_fd_seized(struct parasite_ctl *ctl)
{ {
int ret = -1, fd; int ret = -1, fd;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "syscall.h" #include "syscall.h"
#include "parasite.h" #include "parasite.h"
#include "vdso.h"
#include "log.h" #include "log.h"
#include <string.h> #include <string.h>
...@@ -415,6 +416,21 @@ static int parasite_cfg_log(struct parasite_log_args *args) ...@@ -415,6 +416,21 @@ static int parasite_cfg_log(struct parasite_log_args *args)
return ret; return ret;
} }
static int parasite_check_vdso_mark(struct parasite_vdso_vma_entry *args)
{
struct vdso_mark *m = (void *)args->start;
if (is_vdso_mark(m)) {
args->is_marked = 1;
args->proxy_addr = m->proxy_addr;
} else {
args->is_marked = 0;
args->proxy_addr = VDSO_BAD_ADDR;
}
return 0;
}
static int fini(void) static int fini(void)
{ {
int ret; int ret;
...@@ -463,6 +479,8 @@ int __used parasite_service(unsigned int cmd, void *args) ...@@ -463,6 +479,8 @@ int __used parasite_service(unsigned int cmd, void *args)
return parasite_get_proc_fd(); return parasite_get_proc_fd();
case PARASITE_CMD_DUMP_TTY: case PARASITE_CMD_DUMP_TTY:
return parasite_dump_tty(args); return parasite_dump_tty(args);
case PARASITE_CMD_CHECK_VDSO_MARK:
return parasite_check_vdso_mark(args);
} }
pr_err("Unknown command to parasite: %d\n", cmd); pr_err("Unknown command to parasite: %d\n", cmd);
......
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