diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 946e81a9a..014cf87af 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -5,6 +5,9 @@ #include "int.h" #include "config.h" +#ifdef CONFIG_VDSO +#include "util-vdso.h" +#endif struct stat; @@ -52,6 +55,12 @@ struct kerndat_s { bool has_uffd; unsigned long uffd_features; bool has_thp_disable; +#ifdef CONFIG_VDSO + struct vdso_symtable vdso_sym; +#ifdef CONFIG_COMPAT + struct vdso_symtable vdso_sym_compat; +#endif +#endif }; extern struct kerndat_s kdat; diff --git a/criu/include/vdso.h b/criu/include/vdso.h index 6a9752bd1..b6110e442 100644 --- a/criu/include/vdso.h +++ b/criu/include/vdso.h @@ -15,6 +15,7 @@ extern struct vdso_maps vdso_maps_compat; extern int vdso_init_dump(void); extern int vdso_init_restore(void); +extern int kerndat_vdso_fill_symtable(void); extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid, struct vm_area_list *vma_area_list); @@ -28,6 +29,7 @@ extern void compat_vdso_helper(struct vdso_maps *native, int pipe_fd, #define vdso_init_dump() (0) #define vdso_init_restore() (0) +#define kerndat_vdso_fill_symtable() (0) #define parasite_fixup_vdso(ctl, pid, vma_area_list) (0) #endif /* CONFIG_VDSO */ diff --git a/criu/kerndat.c b/criu/kerndat.c index 32893ef2c..055cc4e67 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -34,6 +34,7 @@ #include "linux/userfaultfd.h" #include "prctl.h" #include "uffd.h" +#include "vdso.h" struct kerndat_s kdat = { }; @@ -861,6 +862,9 @@ int kerndat_init(void) ret = kerndat_uffd(); if (!ret) ret = kerndat_has_thp_disable(); + /* Needs kdat.compat_cr filled before */ + if (!ret) + ret = kerndat_vdso_fill_symtable(); kerndat_lsm(); kerndat_mmap_min_addr(); diff --git a/criu/vdso.c b/criu/vdso.c index da3da69f4..83f30807e 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -457,13 +457,6 @@ out_unmap: pr_perror("Failed to unmap buf for compat vdso"); return ret; } - -#else /* CONFIG_COMPAT */ -static int vdso_fill_compat_symtable(struct vdso_maps *native, - struct vdso_maps *compat) -{ - return 0; -} #endif /* CONFIG_COMPAT */ int vdso_init_dump(void) @@ -481,7 +474,53 @@ int vdso_init_dump(void) 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 + * not parked as run-time vdso in restorer, but mapped with + * arch_prlctl(MAP_VDSO_32) API. + * By that reason we verify only native sizes. + */ +static int is_kdat_vdso_sym_valid(void) +{ + if (vdso_maps.sym.vdso_size != kdat.vdso_sym.vdso_size) + return false; + if (vdso_maps.sym.vvar_size != kdat.vdso_sym.vvar_size) + return false; + + return true; +} + int vdso_init_restore(void) +{ + if (kdat.vdso_sym.vdso_size == VDSO_BAD_SIZE) { + pr_err("Kdat has empty vdso symtable\n"); + return -1; + } + + /* Already filled vdso_maps during kdat test */ + if (vdso_maps.vdso_start != VDSO_BAD_ADDR) + return 0; + + 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; + } + + vdso_maps.sym = kdat.vdso_sym; +#ifdef CONFIG_COMPAT + vdso_maps_compat.sym = kdat.vdso_sym_compat; +#endif + + return 0; +} + +int kerndat_vdso_fill_symtable(void) { if (vdso_parse_maps(PROC_SELF, &vdso_maps)) { pr_err("Failed reading self/maps for filling vdso/vvar bounds\n"); @@ -492,11 +531,15 @@ int vdso_init_restore(void) pr_err("Failed to fill self vdso symtable\n"); return -1; } + kdat.vdso_sym = vdso_maps.sym; +#ifdef CONFIG_COMPAT if (vdso_fill_compat_symtable(&vdso_maps, &vdso_maps_compat)) { pr_err("Failed to fill compat vdso symtable\n"); return -1; } + kdat.vdso_sym_compat = vdso_maps_compat.sym; +#endif return 0; }