Commit 5e5b8215 authored by Cyrill Gorcunov's avatar Cyrill Gorcunov Committed by Pavel Emelyanov

vdso: Make parasite_fixup_vdso being arch implemented

parasite_fixup_vdso is not worth calling on arm at all,
moreover it might try to read pfn for addresses greater
than TASK_SIZE, leading to dump interruption. Lets make
it arch dependent.

[alekskartashov@: Fix compiling on arm]
Reported-by: 's avatarAlexander Kartashov <alekskartashov@parallels.com>
Signed-off-by: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
Tested-by: 's avatarAlexander Kartashov <alekskartashov@parallels.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent cad4fe36
......@@ -6,10 +6,14 @@
#include "protobuf/vma.pb-c.h"
struct vdso_symtable;
struct parasite_ctl;
struct vm_area_list;
extern int vdso_redirect_calls(void *base_to, void *base_from, struct vdso_symtable *to, struct vdso_symtable *from);
extern int vdso_fill_symtable(char *mem, size_t size,struct vdso_symtable *t);
extern int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size);
extern int vdso_proxify(char *who, struct vdso_symtable *sym_rt, VmaEntry *vma_entry, unsigned long vdso_rt_parked_at);
extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
struct vm_area_list *vma_area_list);
#endif /* __CR_ASM_VDSO_H__ */
#include <sys/types.h>
#include <unistd.h>
#include "compiler.h"
#include "asm/types.h"
#include "parasite-syscall.h"
#include "asm/parasite-syscall.h"
#include "vdso.h"
#include "log.h"
......@@ -15,3 +20,9 @@ int vdso_init(void)
{
return 0;
}
int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
struct vm_area_list *vma_area_list)
{
return 0;
}
......@@ -6,10 +6,14 @@
#include "protobuf/vma.pb-c.h"
struct vdso_symtable;
struct parasite_ctl;
struct vm_area_list;
extern int vdso_redirect_calls(void *base_to, void *base_from, struct vdso_symtable *to, struct vdso_symtable *from);
extern int vdso_fill_symtable(char *mem, size_t size,struct vdso_symtable *t);
extern int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size);
extern int vdso_proxify(char *who, struct vdso_symtable *sym_rt, VmaEntry *vma_entry, unsigned long vdso_rt_parked_at);
extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
struct vm_area_list *vma_area_list);
#endif /* __CR_ASM_VDSO_H__ */
......@@ -10,7 +10,10 @@
#include <sys/mman.h>
#include "asm/types.h"
#include "asm/parasite-syscall.h"
#include "parasite-syscall.h"
#include "parasite.h"
#include "compiler.h"
#include "crtools.h"
#include "kerndat.h"
......@@ -95,3 +98,123 @@ out:
close(fd);
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_daemon(PARASITE_CMD_CHECK_VDSO_MARK, ctl)) {
pr_err("vdso: Parasite failed to poke for mark\n");
ret = -1;
goto err;
}
/*
* 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;
}
off = (vma->vma.start / PAGE_SIZE) * sizeof(u64);
if (lseek(fd, off, SEEK_SET) != off) {
pr_perror("Failed to seek address %lx\n",
(long unsigned int)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);
/*
* 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;
}
......@@ -663,126 +663,6 @@ err:
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_daemon(PARASITE_CMD_CHECK_VDSO_MARK, ctl)) {
pr_err("vdso: Parasite failed to poke for mark\n");
ret = -1;
goto err;
}
/*
* 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;
}
off = (vma->vma.start / PAGE_SIZE) * sizeof(u64);
if (lseek(fd, off, SEEK_SET) != off) {
pr_perror("Failed to seek address %lx\n",
(long unsigned int)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);
/*
* 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 ret = -1, 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