[CRIU] [PATCH 4/5] vdso: Make parasite_fixup_vdso being arch implemented
Cyrill Gorcunov
gorcunov at openvz.org
Fri May 31 02:28:44 EDT 2013
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.
Reported-by: Alexander Kartashov <alekskartashov at parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
arch/arm/include/asm/vdso.h | 4 ++
arch/arm/vdso.c | 9 ++++
arch/x86/include/asm/vdso.h | 4 ++
arch/x86/vdso.c | 123 ++++++++++++++++++++++++++++++++++++++++++++
parasite-syscall.c | 120 ------------------------------------------
5 files changed, 140 insertions(+), 120 deletions(-)
diff --git a/arch/arm/include/asm/vdso.h b/arch/arm/include/asm/vdso.h
index 6ffdd74..56d8007 100644
--- a/arch/arm/include/asm/vdso.h
+++ b/arch/arm/include/asm/vdso.h
@@ -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__ */
diff --git a/arch/arm/vdso.c b/arch/arm/vdso.c
index fa40fe2..26b539f 100644
--- a/arch/arm/vdso.c
+++ b/arch/arm/vdso.c
@@ -1,5 +1,8 @@
#include <sys/types.h>
+#include "asm/parasite-syscall.h"
+
+#include "parasite-syscall.h"
#include "vdso.h"
#include "log.h"
@@ -15,3 +18,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;
+}
diff --git a/arch/x86/include/asm/vdso.h b/arch/x86/include/asm/vdso.h
index 6ffdd74..56d8007 100644
--- a/arch/x86/include/asm/vdso.h
+++ b/arch/x86/include/asm/vdso.h
@@ -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__ */
diff --git a/arch/x86/vdso.c b/arch/x86/vdso.c
index 6fc00be..a4687ea 100644
--- a/arch/x86/vdso.c
+++ b/arch/x86/vdso.c
@@ -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;
+}
diff --git a/parasite-syscall.c b/parasite-syscall.c
index e548e30..9de45c2 100644
--- a/parasite-syscall.c
+++ b/parasite-syscall.c
@@ -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;
--
1.8.1.4
More information about the CRIU
mailing list