vdso: Repair !CONFIG_VDSO

Apparently, C/R is broken when CONFIG_VDSO is not set.
Probably, I've broken it while adding arm vdso support.
Or maybe some commits after.

Repair it by adding checks into vdso_init_dump(), vdso_init_restore().
Also, don't try handling vDSO in restorer if it wasn't present in
parent. And prevent summing VDSO_BAD_SIZE to {vdso,vvar}_rt_size.

Reported-by: Adrian Reber <areber@redhat.com>
Signed-off-by: Dmitry Safonov <dima@arista.com>
This commit is contained in:
Dmitry Safonov 2020-01-22 14:00:27 +00:00 committed by Andrei Vagin
parent 0022c28468
commit a96a7ed87f
4 changed files with 50 additions and 21 deletions

View file

@ -3373,10 +3373,13 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns
vdso_maps_rt = vdso_maps;
/*
* Figure out how much memory runtime vdso and vvar will need.
* Check if vDSO or VVAR is not provided by kernel.
*/
vdso_rt_size = vdso_maps_rt.sym.vdso_size;
if (vdso_rt_size && vdso_maps_rt.sym.vvar_size)
vdso_rt_size += ALIGN(vdso_maps_rt.sym.vvar_size, PAGE_SIZE);
if (vdso_maps_rt.sym.vdso_size != VDSO_BAD_SIZE) {
vdso_rt_size = vdso_maps_rt.sym.vdso_size;
if (vdso_maps_rt.sym.vvar_size != VVAR_BAD_SIZE)
vdso_rt_size += ALIGN(vdso_maps_rt.sym.vvar_size, PAGE_SIZE);
}
task_args->bootstrap_len += vdso_rt_size;
/*

View file

@ -292,6 +292,18 @@ int vdso_proxify(struct vdso_maps *rt, bool *added_proxy,
return -1;
}
/*
* We could still do something about it here..
* 1. Hope that vDSO from images still works (might not be the case).
* 2. Try to map vDSO.
* But, hopefully no one intends to migrate application that uses
* vDSO to a dut where kernel doesn't provide it.
*/
if (!vdso_is_present(rt)) {
pr_err("vDSO isn't provided by kernel, but exists in images\n");
return -1;
}
/*
* vDSO mark overwrites Elf program header of proxy vDSO thus
* it must never ever be greater in size.

View file

@ -1454,7 +1454,7 @@ long __export_restore_task(struct task_restore_args *args)
* it's presence in original task: vdso will be used for fast
* getttimeofday() in restorer's log timings.
*/
if (!args->can_map_vdso) {
if (!args->can_map_vdso && vdso_is_present(&args->vdso_maps_rt)) {
/* It's already checked in kdat, but let's check again */
if (args->compatible_mode) {
pr_err("Compatible mode without vdso map support\n");

View file

@ -275,6 +275,10 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
struct vma_area *vma;
int fd = -1;
/* vDSO is not provided by kernel */
if (kdat.vdso_sym.vdso_size == VDSO_BAD_SIZE)
return 0;
vcheck = get_vdso_check_type(ctl);
if (vcheck == VDSO_CHECK_PFN) {
BUG_ON(vdso_pfn == VDSO_BAD_PFN);
@ -534,21 +538,6 @@ out_unmap:
}
#endif /* CONFIG_COMPAT */
int vdso_init_dump(void)
{
if (vdso_parse_maps(PROC_SELF, &vdso_maps)) {
pr_err("Failed reading self/maps for filling vdso/vvar bounds\n");
return -1;
}
if (kdat.pmap != PM_FULL)
pr_info("VDSO detection turned off\n");
else if (vaddr_to_pfn(-1, vdso_maps.vdso_start, &vdso_pfn))
return -1;
return 0;
}
/*
* Check vdso/vvar sized read from maps to kdat values.
* We do not read /proc/self/maps for compatible vdso as it's
@ -566,11 +555,36 @@ static int is_kdat_vdso_sym_valid(void)
return true;
}
int vdso_init_dump(void)
{
if (vdso_parse_maps(PROC_SELF, &vdso_maps)) {
pr_err("Failed reading self/maps for filling vdso/vvar bounds\n");
return -1;
}
if (!is_kdat_vdso_sym_valid()) {
pr_err("Kdat sizes of vdso/vvar differ to maps file \n");
return -1;
}
if (kdat.vdso_sym.vdso_size == VDSO_BAD_SIZE) {
pr_debug("Kdat has empty vdso symtable - probably CONFIG_VDSO is not set\n");
return 0;
}
if (kdat.pmap != PM_FULL)
pr_info("VDSO detection turned off\n");
else if (vaddr_to_pfn(-1, vdso_maps.vdso_start, &vdso_pfn))
return -1;
return 0;
}
int vdso_init_restore(void)
{
if (kdat.vdso_sym.vdso_size == VDSO_BAD_SIZE) {
pr_err("Kdat has empty vdso symtable\n");
return -1;
pr_debug("Kdat has empty vdso symtable - probably CONFIG_VDSO is not set\n");
return 0;
}
/* Already filled vdso_maps during kdat test */