[Makedumpfile PATCH 1/2] makedumpfile: add runtime kaslr offset if it exists
Xunlei Pang
xpang at redhat.com
Thu Apr 27 22:40:48 PDT 2017
On 04/27/2017 at 02:15 PM, Pratyush Anand wrote:
> If we have to erase a symbol from vmcore whose address is not present in
> vmcoreinfo, then we need to pass vmlinux as well to get the symbol
> address.
> When kaslr is enabled, virtual address of all the kernel symbols are
> randomized with an offset. vmlinux always has a static address, but all
> the arch specific calculation are based on run time kernel address. So
> we need to find a way to translate symbol address from vmlinux to kernel
> run time address.
>
> without this patch:
> # makedumpfile --split -d 5 -x vmlinux --config scrub.conf vmcore dumpfile_{1,2,3}
>
> readpage_kdump_compressed: pfn(f97ea) is excluded from vmcore.
> readmem: type_addr: 1, addr:f97eaff8, size:8
> vtop4_x86_64: Can't get pml4 (page_dir:f97eaff8).
> readmem: Can't convert a virtual address(ffffffff819f1284) to physical address.
> readmem: type_addr: 0, addr:ffffffff819f1284, size:390
> check_release: Can't get the address of system_utsname.
>
> After this patch check_release() is ok, and also we are able to erase
> symbol from vmcore.
>
> Signed-off-by: Pratyush Anand <panand at redhat.com>
> ---
> arch/x86_64.c | 23 +++++++++++++++++++++++
> erase_info.c | 1 +
> makedumpfile.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
> makedumpfile.h | 15 +++++++++++++++
> 4 files changed, 83 insertions(+)
>
> diff --git a/arch/x86_64.c b/arch/x86_64.c
> index e978a36f8878..ab5aae8f1b26 100644
> --- a/arch/x86_64.c
> +++ b/arch/x86_64.c
> @@ -33,6 +33,29 @@ get_xen_p2m_mfn(void)
> return NOT_FOUND_LONG_VALUE;
> }
>
> +unsigned long
> +get_kaslr_offset_x86_64(unsigned long vaddr)
> +{
> + unsigned long sym_vmcoreinfo, sym_vmlinux;
> +
> + if (!info->kaslr_offset) {
> + sym_vmlinux = get_symbol_addr("_stext");
> + if (sym_vmlinux == NOT_FOUND_SYMBOL)
> + return 0;
> + sym_vmcoreinfo = read_vmcoreinfo_symbol(STR_SYMBOL("_stext"));
> + info->kaslr_offset = sym_vmcoreinfo - sym_vmlinux;
> + }
> + if (vaddr >= __START_KERNEL_map &&
> + vaddr < __START_KERNEL_map + info->kaslr_offset)
> + return info->kaslr_offset;
> + else
> + /*
> + * TODO: we need to check if it is vmalloc/vmmemmap/module
> + * address, we will have different offset
> + */
> + return 0;
> +}
> +
> static int
> get_page_offset_x86_64(void)
> {
> diff --git a/erase_info.c b/erase_info.c
> index f2ba9149e93e..60abfa1a1adf 100644
> --- a/erase_info.c
> +++ b/erase_info.c
> @@ -1088,6 +1088,7 @@ resolve_config_entry(struct config_entry *ce, unsigned long long base_vaddr,
> ce->line, ce->name);
> return FALSE;
> }
> + ce->sym_addr += get_kaslr_offset(ce->sym_addr);
> ce->type_name = get_symbol_type_name(ce->name,
> DWARF_INFO_GET_SYMBOL_TYPE,
> &ce->size, &ce->type_flag);
> diff --git a/makedumpfile.c b/makedumpfile.c
> index 301772a8820c..7e78641917d7 100644
> --- a/makedumpfile.c
> +++ b/makedumpfile.c
> @@ -3782,6 +3782,46 @@ free_for_parallel()
> }
>
> int
> +find_kaslr_offsets()
> +{
> + off_t offset;
> + unsigned long size;
> + int ret = FALSE;
> +
> + get_vmcoreinfo(&offset, &size);
> +
> + if (!(info->name_vmcoreinfo = strdup(FILENAME_VMCOREINFO))) {
> + MSG("Can't duplicate strings(%s).\n", FILENAME_VMCOREINFO);
> + return FALSE;
> + }
> + if (!copy_vmcoreinfo(offset, size))
> + goto out;
> +
> + if (!open_vmcoreinfo("r"))
> + goto out;
> +
> + unlink(info->name_vmcoreinfo);
> +
> + /*
> + * This arch specific function should update info->kaslr_offset. If
> + * kaslr is not enabled then offset will be set to 0. arch specific
> + * function might need to read from vmcoreinfo, therefore we have
> + * called this function between open_vmcoreinfo() and
> + * close_vmcoreinfo()
> + */
> + get_kaslr_offset(SYMBOL(_stext));
Looks like acquiring "KERNELOFFSET" in read_vmcoreinfo() should be enough here.
We can get kaslr offset directly from the vmcoreinfo because the compressed dumpfile
contains vmcoreinfo as well in case of flag_refiltering, also x86_64 kernel has exported
"vmcoreinfo_append_str("KERNELOFFSET=%lx\n", kaslr_offset());"
Regards,
Xunlei
> +
> + close_vmcoreinfo();
> +
> + ret = TRUE;
> +out:
> + free(info->name_vmcoreinfo);
> + info->name_vmcoreinfo = NULL;
> +
> + return ret;
> +}
> +
> +int
> initial(void)
> {
> off_t offset;
> @@ -3833,6 +3873,9 @@ initial(void)
> set_dwarf_debuginfo("vmlinux", NULL,
> info->name_vmlinux, info->fd_vmlinux);
>
> + if (has_vmcoreinfo() && !find_kaslr_offsets())
> + return FALSE;
> +
> if (!get_symbol_info())
> return FALSE;
>
> @@ -11031,6 +11074,7 @@ main(int argc, char *argv[])
> info->fd_memory = -1;
> info->fd_dumpfile = -1;
> info->fd_bitmap = -1;
> + info->kaslr_offset = 0;
> initialize_tables();
>
> /*
> diff --git a/makedumpfile.h b/makedumpfile.h
> index e32e567018f6..0d358be8caac 100644
> --- a/makedumpfile.h
> +++ b/makedumpfile.h
> @@ -253,10 +253,14 @@ static inline int string_exists(char *s) { return (s ? TRUE : FALSE); }
> #define SYMBOL_INIT(symbol, str_symbol) \
> do { \
> SYMBOL(symbol) = get_symbol_addr(str_symbol); \
> + if (SYMBOL(symbol) != NOT_FOUND_SYMBOL) \
> + SYMBOL(symbol) += info->kaslr_offset; \
> } while (0)
> #define SYMBOL_INIT_NEXT(symbol, str_symbol) \
> do { \
> SYMBOL(symbol) = get_next_symbol_addr(str_symbol); \
> + if (SYMBOL(symbol) != NOT_FOUND_SYMBOL) \
> + SYMBOL(symbol) += info->kaslr_offset; \
> } while (0)
> #define WRITE_SYMBOL(str_symbol, symbol) \
> do { \
> @@ -838,6 +842,7 @@ int get_xen_info_arm64(void);
> #define get_phys_base() get_phys_base_arm64()
> #define get_machdep_info() get_machdep_info_arm64()
> #define get_versiondep_info() get_versiondep_info_arm64()
> +#define get_kaslr_offset(X) FALSE
> #define get_xen_basic_info_arch(X) get_xen_basic_info_arm64(X)
> #define get_xen_info_arch(X) get_xen_info_arm64(X)
> #define is_phys_addr(X) stub_true_ul(X)
> @@ -851,6 +856,7 @@ unsigned long long vaddr_to_paddr_arm(unsigned long vaddr);
> #define get_phys_base() get_phys_base_arm()
> #define get_machdep_info() get_machdep_info_arm()
> #define get_versiondep_info() stub_true()
> +#define get_kaslr_offset(X) FALSE
> #define vaddr_to_paddr(X) vaddr_to_paddr_arm(X)
> #define is_phys_addr(X) stub_true_ul(X)
> #endif /* arm */
> @@ -863,11 +869,13 @@ unsigned long long vaddr_to_paddr_x86(unsigned long vaddr);
> #define get_phys_base() stub_true()
> #define get_machdep_info() get_machdep_info_x86()
> #define get_versiondep_info() get_versiondep_info_x86()
> +#define get_kaslr_offset(X) FALSE
> #define vaddr_to_paddr(X) vaddr_to_paddr_x86(X)
> #define is_phys_addr(X) stub_true_ul(X)
> #endif /* x86 */
>
> #ifdef __x86_64__
> +unsigned long get_kaslr_offset_x86_64(unsigned long vaddr);
> int get_phys_base_x86_64(void);
> int get_machdep_info_x86_64(void);
> int get_versiondep_info_x86_64(void);
> @@ -876,6 +884,7 @@ unsigned long long vtop4_x86_64(unsigned long vaddr);
> #define get_phys_base() get_phys_base_x86_64()
> #define get_machdep_info() get_machdep_info_x86_64()
> #define get_versiondep_info() get_versiondep_info_x86_64()
> +#define get_kaslr_offset(X) get_kaslr_offset_x86_64(X)
> #define vaddr_to_paddr(X) vtop4_x86_64(X)
> #define is_phys_addr(X) stub_true_ul(X)
> #endif /* x86_64 */
> @@ -888,6 +897,7 @@ unsigned long long vaddr_to_paddr_ppc64(unsigned long vaddr);
> #define get_phys_base() stub_true()
> #define get_machdep_info() get_machdep_info_ppc64()
> #define get_versiondep_info() get_versiondep_info_ppc64()
> +#define get_kaslr_offset(X) FALSE
> #define vaddr_to_paddr(X) vaddr_to_paddr_ppc64(X)
> #define is_phys_addr(X) stub_true_ul(X)
> #endif /* powerpc64 */
> @@ -899,6 +909,7 @@ unsigned long long vaddr_to_paddr_ppc(unsigned long vaddr);
> #define get_phys_base() stub_true()
> #define get_machdep_info() get_machdep_info_ppc()
> #define get_versiondep_info() stub_true()
> +#define get_kaslr_offset(X) FALSE
> #define vaddr_to_paddr(X) vaddr_to_paddr_ppc(X)
> #define is_phys_addr(X) stub_true_ul(X)
> #endif /* powerpc32 */
> @@ -911,6 +922,7 @@ int is_iomem_phys_addr_s390x(unsigned long addr);
> #define get_phys_base() stub_true()
> #define get_machdep_info() get_machdep_info_s390x()
> #define get_versiondep_info() stub_true()
> +#define get_kaslr_offset(X) FALSE
> #define vaddr_to_paddr(X) vaddr_to_paddr_s390x(X)
> #define is_phys_addr(X) is_iomem_phys_addr_s390x(X)
> #endif /* s390x */
> @@ -923,6 +935,7 @@ unsigned long long vaddr_to_paddr_ia64(unsigned long vaddr);
> #define get_machdep_info() get_machdep_info_ia64()
> #define get_phys_base() get_phys_base_ia64()
> #define get_versiondep_info() stub_true()
> +#define get_kaslr_offset(X) FALSE
> #define vaddr_to_paddr(X) vaddr_to_paddr_ia64(X)
> #define VADDR_REGION(X) (((unsigned long)(X)) >> REGION_SHIFT)
> #define is_phys_addr(X) stub_true_ul(X)
> @@ -1152,6 +1165,7 @@ struct DumpInfo {
> int vmemmap_psize;
> int vmemmap_cnt;
> struct ppc64_vmemmap *vmemmap_list;
> + unsigned long kaslr_offset;
>
> /*
> * page table info for ppc64
> @@ -1803,6 +1817,7 @@ struct memory_range {
> struct memory_range crash_reserved_mem[CRASH_RESERVED_MEM_NR];
> int crash_reserved_mem_nr;
>
> +unsigned long read_vmcoreinfo_symbol(char *str_symbol);
> int readmem(int type_addr, unsigned long long addr, void *bufptr, size_t size);
> int get_str_osrelease_from_vmlinux(void);
> int read_vmcoreinfo_xen(void);
More information about the kexec
mailing list