mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-08-03 07:12:48 +00:00
vdso/ia32: separate compat vdso helper
As helper unmaps 64-bit vDSO blob, it can call only raw syscalls. Also by that reason it's code should be not instrumented with GCOV/ASAN. Disable instrumentation by separating it into new object and filtering gcov/asan cflags. Fixes: #290 @avagin, it rarely reproduces, I failed to reproduce even once (with gcov, on the same env00 test, with the same linux-next) please, reopen #290 if you'll spot it afterward. Reported-by: Andrei Vagin <avagin@openvz.org> Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com> Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
This commit is contained in:
parent
164e048a8a
commit
f2504723c9
4 changed files with 81 additions and 65 deletions
|
|
@ -86,7 +86,9 @@ ifeq ($(VDSO),y)
|
|||
obj-y += pie-util-vdso.o
|
||||
obj-y += vdso.o
|
||||
obj-y += pie-util-vdso-elf32.o
|
||||
CFLAGS_pie-util-vdso-elf32.o += -DCONFIG_VDSO_32
|
||||
CFLAGS_pie-util-vdso-elf32.o += -DCONFIG_VDSO_32
|
||||
obj-$(CONFIG_COMPAT) += vdso-compat.o
|
||||
CFLAGS_REMOVE_vdso-compat.o += $(CFLAGS-ASAN) $(CFLAGS-GCOV)
|
||||
endif
|
||||
|
||||
PROTOBUF_GEN := scripts/protobuf-gen.sh
|
||||
|
|
|
|||
|
|
@ -18,6 +18,11 @@ extern int vdso_init(void);
|
|||
extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
|
||||
struct vm_area_list *vma_area_list);
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
void compat_vdso_helper(struct vdso_symtable *native, int pipe_fd,
|
||||
int err_fd, void *vdso_buf, size_t buf_size);
|
||||
#endif
|
||||
|
||||
#else /* CONFIG_VDSO */
|
||||
|
||||
#define vdso_init() (0)
|
||||
|
|
|
|||
71
criu/vdso-compat.c
Normal file
71
criu/vdso-compat.c
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#include <sys/syscall.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "parasite-syscall.h"
|
||||
#include "parasite.h"
|
||||
#include "vdso.h"
|
||||
|
||||
static void exit_on(int ret, int err_fd, char *reason)
|
||||
{
|
||||
if (ret) {
|
||||
syscall(__NR_write, err_fd, reason, strlen(reason));
|
||||
syscall(__NR_exit, ret);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Because of restrictions of ARCH_MAP_VDSO_* API, new vDSO blob
|
||||
* can be mapped only if there is no vDSO blob present for a process.
|
||||
* This is a helper process, it unmaps 64-bit vDSO and maps 32-bit vDSO.
|
||||
* Then it copies vDSO blob to shared with CRIU mapping.
|
||||
*
|
||||
* The purpose is to fill compat vdso's symtable (vdso_compat_rt).
|
||||
* It's an optimization to fill symtable only once at CRIU restore
|
||||
* for all restored tasks.
|
||||
*
|
||||
* @native - 64-bit vDSO blob (for easy unmap)
|
||||
* @pipe_fd - to get size of compat blob from /proc/.../maps
|
||||
* @err_fd - to print error messages
|
||||
* @vdso_buf, buf_size - shared with CRIU buffer
|
||||
*
|
||||
* WARN: This helper shouldn't call pr_err() or any syscall with
|
||||
* Glibc's wrapper function - it may very likely blow up.
|
||||
*/
|
||||
void compat_vdso_helper(struct vdso_symtable *native, int pipe_fd,
|
||||
int err_fd, void *vdso_buf, size_t buf_size)
|
||||
{
|
||||
size_t vma_size;
|
||||
void *vdso_addr;
|
||||
long vdso_size;
|
||||
long ret;
|
||||
|
||||
vma_size = native->vma_end - native->vma_start;
|
||||
ret = syscall(__NR_munmap, native->vma_start, vma_size);
|
||||
exit_on(ret, err_fd, "Error: Failed to unmap native vdso\n");
|
||||
|
||||
vma_size = native->vvar_end - native->vvar_start;
|
||||
ret = syscall(__NR_munmap, native->vvar_start, vma_size);
|
||||
exit_on(ret, err_fd, "Error: Failed to unmap native vvar\n");
|
||||
|
||||
ret = syscall(__NR_arch_prctl, ARCH_MAP_VDSO_32, native->vma_start);
|
||||
if (ret < 0)
|
||||
exit_on(ret, err_fd, "Error: ARCH_MAP_VDSO failed\n");
|
||||
|
||||
vdso_size = ret;
|
||||
if (vdso_size > buf_size)
|
||||
exit_on(-1, err_fd, "Error: Compatible vdso's size is bigger than reserved buf\n");
|
||||
|
||||
/* Stop so CRIU could parse smaps to find 32-bit vdso's size */
|
||||
ret = syscall(__NR_kill, syscall(__NR_getpid), SIGSTOP);
|
||||
exit_on(ret, err_fd, "Error: Can't stop myself with SIGSTOP (having a good time)\n");
|
||||
|
||||
ret = syscall(__NR_read, pipe_fd, &vdso_addr, sizeof(void *));
|
||||
if (ret != sizeof(void *))
|
||||
exit_on(-1, err_fd, "Error: Can't read size of mmaped vdso from pipe\n");
|
||||
|
||||
memcpy(vdso_buf, vdso_addr, vdso_size);
|
||||
|
||||
syscall(__NR_exit, 0);
|
||||
}
|
||||
66
criu/vdso.c
66
criu/vdso.c
|
|
@ -330,68 +330,6 @@ static int vdso_fill_self_symtable(struct vdso_symtable *s)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static void exit_on(int ret, int err_fd, char *reason)
|
||||
{
|
||||
if (ret) {
|
||||
syscall(__NR_write, err_fd, reason, strlen(reason));
|
||||
syscall(__NR_exit, ret);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Because of restrictions of ARCH_MAP_VDSO_* API, new vDSO blob
|
||||
* can be mapped only if there is no vDSO blob present for a process.
|
||||
* This is a helper process, it unmaps 64-bit vDSO and maps 32-bit vDSO.
|
||||
* Then it copies vDSO blob to shared with CRIU mapping.
|
||||
*
|
||||
* The purpose is to fill compat vdso's symtable (vdso_compat_rt).
|
||||
* It's an optimization to fill symtable only once at CRIU restore
|
||||
* for all restored tasks.
|
||||
*
|
||||
* @native - 64-bit vDSO blob (for easy unmap)
|
||||
* @pipe_fd - to get size of compat blob from /proc/.../maps
|
||||
* @err_fd - to print error messages
|
||||
* @vdso_buf, buf_size - shared with CRIU buffer
|
||||
*
|
||||
* WARN: This helper shouldn't call pr_err() or any syscall with
|
||||
* Glibc's wrapper function - it may very likely blow up.
|
||||
*/
|
||||
static void compat_vdso_helper(struct vdso_symtable *native, int pipe_fd,
|
||||
int err_fd, void *vdso_buf, size_t buf_size)
|
||||
{
|
||||
size_t vma_size;
|
||||
void *vdso_addr;
|
||||
long vdso_size;
|
||||
long ret;
|
||||
|
||||
vma_size = native->vma_end - native->vma_start;
|
||||
ret = syscall(__NR_munmap, native->vma_start, vma_size);
|
||||
exit_on(ret, err_fd, "Error: Failed to unmap native vdso\n");
|
||||
|
||||
vma_size = native->vvar_end - native->vvar_start;
|
||||
ret = syscall(__NR_munmap, native->vvar_start, vma_size);
|
||||
exit_on(ret, err_fd, "Error: Failed to unmap native vvar\n");
|
||||
|
||||
ret = syscall(__NR_arch_prctl, ARCH_MAP_VDSO_32, native->vma_start);
|
||||
if (ret < 0)
|
||||
exit_on(ret, err_fd, "Error: ARCH_MAP_VDSO failed\n");
|
||||
|
||||
vdso_size = ret;
|
||||
if (vdso_size > buf_size)
|
||||
exit_on(-1, err_fd, "Error: Compatible vdso's size is bigger than reserved buf\n");
|
||||
|
||||
/* Stop so CRIU could parse smaps to find 32-bit vdso's size */
|
||||
ret = syscall(__NR_kill, syscall(__NR_getpid), SIGSTOP);
|
||||
exit_on(ret, err_fd, "Error: Can't stop myself with SIGSTOP (having a good time)\n");
|
||||
|
||||
ret = syscall(__NR_read, pipe_fd, &vdso_addr, sizeof(void *));
|
||||
if (ret != sizeof(void *))
|
||||
exit_on(-1, err_fd, "Error: Can't read size of mmaped vdso from pipe\n");
|
||||
|
||||
memcpy(vdso_buf, vdso_addr, vdso_size);
|
||||
|
||||
syscall(__NR_exit, 0);
|
||||
}
|
||||
|
||||
static int vdso_mmap_compat(struct vdso_symtable *native,
|
||||
struct vdso_symtable *compat, void *vdso_buf, size_t buf_size)
|
||||
{
|
||||
|
|
@ -503,13 +441,13 @@ out_unmap:
|
|||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
#else /* CONFIG_COMPAT */
|
||||
static int vdso_fill_compat_symtable(struct vdso_symtable *native,
|
||||
struct vdso_symtable *compat)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_COMPAT */
|
||||
|
||||
int vdso_init(void)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue