Commit bcba8d97 authored by Dmitry Safonov's avatar Dmitry Safonov Committed by Andrei Vagin

vdso: Introduce type for checking vdso hint in maps file

Let's hide those kernel details in enum.
Further in this patches set I'll add kdat test for presence
of "[vdso]" hint after mremap(), so we will skip any checking
on kernels > v3.16 and do not init vdso_pfn also
(skipping parsing of self-pagemap).
Signed-off-by: 's avatarDmitry Safonov <dsafonov@virtuozzo.com>
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
parent 773fd404
......@@ -32,6 +32,42 @@ u64 vdso_pfn = VDSO_BAD_PFN;
struct vdso_maps vdso_maps = VDSO_MAPS_INIT;
struct vdso_maps vdso_maps_compat = VDSO_MAPS_INIT;
/*
* Starting with 3.16 the [vdso]/[vvar] marks are reported correctly
* even when they are remapped into a new place, but only since that
* particular version of the kernel!
* On previous kernels we need to check if vma is vdso by some means:
* - if pagemap is present, by pfn
* - by parsing ELF and filling vdso symtable otherwise
*/
enum vdso_check_t {
/* from slowest to fastest */
VDSO_CHECK_SYMS = 0,
VDSO_CHECK_PFN,
VDSO_NO_CHECK,
};
static enum vdso_check_t get_vdso_check_type(struct parasite_ctl *ctl)
{
/*
* ia32 C/R depends on mremap() for vdso patches (v4.8),
* so we can omit any check and be sure that "[vdso]"
* hint stays in /proc/../maps file and is correct.
*/
if (!compel_mode_native(ctl)) {
pr_info("Don't check vdso\n");
return VDSO_NO_CHECK;
}
if (kdat.pmap == PM_FULL) {
pr_info("Check vdso by pfn from pagemap\n");
return VDSO_CHECK_PFN;
}
pr_info("Pagemap is unavailable, check vdso by filling symtable\n");
return VDSO_CHECK_SYMS;
}
/*
* The VMAs list might have proxy vdso/vvar areas left
* from previous dump/restore cycle so we need to detect
......@@ -47,18 +83,19 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
struct vma_area *proxy_vvar_marked = NULL;
struct parasite_vdso_vma_entry *args;
int fd = -1, ret, exit_code = -1;
enum vdso_check_t vcheck;
u64 pfn = VDSO_BAD_PFN;
struct vma_area *vma;
off_t off;
vcheck = get_vdso_check_type(ctl);
args = compel_parasite_args(ctl, struct parasite_vdso_vma_entry);
if (kdat.pmap == PM_FULL) {
if (vcheck == VDSO_CHECK_PFN) {
BUG_ON(vdso_pfn == VDSO_BAD_PFN);
fd = open_proc(pid, "pagemap");
if (fd < 0)
return -1;
} else
pr_info("Pagemap is unavailable, trying a slow way\n");
}
list_for_each_entry(vma, &vma_area_list->h, list) {
if (!vma_area_is(vma, VMA_AREA_REGULAR))
......@@ -105,10 +142,7 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
*/
args->start = vma->e->start;
args->len = vma_area_len(vma);
if (!compel_mode_native(ctl))
args->try_fill_symtable = false;
else
args->try_fill_symtable = (fd < 0) ? true : false;
args->try_fill_symtable = (vcheck == VDSO_CHECK_SYMS);
args->is_vdso = false;
if (compel_rpc_call_sync(PARASITE_CMD_CHECK_VDSO_MARK, ctl)) {
......@@ -132,6 +166,9 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
continue;
}
if (vcheck == VDSO_NO_CHECK)
continue;
/*
* If we have an access to pagemap we can handle vDSO
* status early. Otherwise, in worst scenario, where
......@@ -140,7 +177,7 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
* detected via procfs status so we have to parse
* symbols in parasite code.
*/
if (fd >= 0) {
if (vcheck == VDSO_CHECK_PFN) {
off = (vma->e->start / PAGE_SIZE) * sizeof(u64);
ret = pread(fd, &pfn, sizeof(pfn), off);
if (ret < 0 || ret != sizeof(pfn)) {
......@@ -155,13 +192,6 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
}
}
/*
* Setup proper VMA status. Note starting with 3.16
* the [vdso]/[vvar] marks are reported correctly
* even when they are remapped into a new place,
* but only since that particular version of the
* kernel!
*/
if ((pfn == vdso_pfn && pfn != VDSO_BAD_PFN) || args->is_vdso) {
if (!vma_area_is(vma, VMA_AREA_VDSO)) {
pr_debug("Restore vDSO status by pfn/symtable at %lx\n",
......@@ -169,12 +199,7 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
vma->e->status |= VMA_AREA_VDSO;
}
} else {
/*
* Compat vDSO mremap support is only after v4.8,
* [vdso] vma name always stays after mremap.
*/
if (unlikely(vma_area_is(vma, VMA_AREA_VDSO)) &&
compel_mode_native(ctl)) {
if (unlikely(vma_area_is(vma, VMA_AREA_VDSO))) {
pr_debug("Drop mishinted vDSO status at %lx\n",
(long)vma->e->start);
vma->e->status &= ~VMA_AREA_VDSO;
......
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