diff --git a/arch/x86/include/asm/vdso.h b/arch/x86/include/asm/vdso.h index 27c687344..0e72befc9 100644 --- a/arch/x86/include/asm/vdso.h +++ b/arch/x86/include/asm/vdso.h @@ -146,7 +146,7 @@ extern struct vdso_symtable vdso_sym_rt; extern u64 vdso_pfn; extern int vdso_init(void); -extern int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size); +extern int vdso_do_park(struct vdso_symtable *sym_rt, unsigned long park_at, unsigned long park_size); extern int vdso_fill_symtable(char *mem, size_t size, struct vdso_symtable *t); extern int vdso_proxify(char *who, struct vdso_symtable *sym_rt, VmaEntry *vdso_vma, VmaEntry *vvar_vma, diff --git a/arch/x86/vdso-pie.c b/arch/x86/vdso-pie.c index 007cc9c8d..05a78fb81 100644 --- a/arch/x86/vdso-pie.c +++ b/arch/x86/vdso-pie.c @@ -19,6 +19,7 @@ #include "vdso.h" #include "vma.h" #include "log.h" +#include "bug.h" #ifdef LOG_PREFIX # undef LOG_PREFIX @@ -246,7 +247,7 @@ err_oob: return -EFAULT; } -int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size) +static int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size) { unsigned long addr; @@ -262,6 +263,33 @@ int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size) return 0; } +/* Park runtime vDSO in some safe place where it can be accessible from restorer */ +int vdso_do_park(struct vdso_symtable *sym_rt, unsigned long park_at, unsigned long park_size) +{ + int ret; + + BUG_ON((vdso_vma_size(sym_rt) + vvar_vma_size(sym_rt)) < park_size); + + if (sym_rt->vvar_start != VDSO_BAD_ADDR) { + if (sym_rt->vma_start < sym_rt->vvar_start) { + ret = vdso_remap("rt-vdso", sym_rt->vma_start, + park_at, vdso_vma_size(sym_rt)); + park_at += vdso_vma_size(sym_rt); + ret |= vdso_remap("rt-vvar", sym_rt->vvar_start, + park_at, vvar_vma_size(sym_rt)); + } else { + ret = vdso_remap("rt-vvar", sym_rt->vvar_start, + park_at, vvar_vma_size(sym_rt)); + park_at += vvar_vma_size(sym_rt); + ret |= vdso_remap("rt-vdso", sym_rt->vma_start, + park_at, vdso_vma_size(sym_rt)); + } + } else + ret = vdso_remap("rt-vdso", sym_rt->vma_start, + park_at, vdso_vma_size(sym_rt)); + return ret; +} + int vdso_proxify(char *who, struct vdso_symtable *sym_rt, VmaEntry *vdso_vma, VmaEntry *vvar_vma, unsigned long vdso_rt_parked_at) diff --git a/include/vdso.h b/include/vdso.h index 50549d566..52949561c 100644 --- a/include/vdso.h +++ b/include/vdso.h @@ -15,6 +15,7 @@ #define vdso_init() (0) #define parasite_fixup_vdso(ctl, pid, vma_area_list) (0) #define vdso_vma_size(t) (0) +#define vdso_do_park(sym_rt, park_at, park_size) (0) #define vdso_remap(who, from, to, size) (0) #define vdso_proxify(who, sym_rt, vdso_vma, \ vvar_vma, vdso_rt_parked_at) (0) diff --git a/pie/restorer.c b/pie/restorer.c index 1ba14e779..7f8277670 100644 --- a/pie/restorer.c +++ b/pie/restorer.c @@ -701,16 +701,8 @@ long __export_restore_task(struct task_restore_args *args) pr_info("Switched to the restorer %d\n", my_pid); #ifdef CONFIG_VDSO - if (vdso_remap("rt-vdso", args->vdso_sym_rt.vma_start, - args->vdso_rt_parked_at, - vdso_vma_size(&args->vdso_sym_rt))) + if (vdso_do_park(&args->vdso_sym_rt, args->vdso_rt_parked_at, vdso_rt_size)) goto core_restore_end; - if (args->vdso_sym_rt.vvar_start != VVAR_BAD_ADDR) { - if (vdso_remap("rt-vvar", args->vdso_sym_rt.vvar_start, - args->vdso_rt_parked_at + vdso_vma_size(&args->vdso_sym_rt), - vvar_vma_size(&args->vdso_sym_rt))) - goto core_restore_end; - } #endif if (unmap_old_vmas((void *)args->premmapped_addr, args->premmapped_len,