[Makedumpfile PATCH v3 1/2] makedumpfile: add runtime kaslr offset if it exists
Atsushi Kumagai
ats-kumagai at wm.jp.nec.com
Wed May 24 20:03:40 PDT 2017
Hello Pratyush,
>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:
> # cat > scrub.conf << EOF
> [vmlinux]
> erase jiffies
> erase init_task.utime
> for tsk in init_task.tasks.next within task_struct:tasks
> erase tsk.utime
> endfor
> EOF
>
> # 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 | 36 ++++++++++++++++++++++++++++++++++++
> erase_info.c | 1 +
> makedumpfile.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> makedumpfile.h | 16 ++++++++++++++++
> 4 files changed, 106 insertions(+)
>
>diff --git a/arch/x86_64.c b/arch/x86_64.c
>index e978a36f8878..fd2e8ac154d6 100644
>--- a/arch/x86_64.c
>+++ b/arch/x86_64.c
>@@ -33,6 +33,42 @@ get_xen_p2m_mfn(void)
> return NOT_FOUND_LONG_VALUE;
> }
>
>+unsigned long
>+get_kaslr_offset_x86_64(unsigned long vaddr)
>+{
>+ unsigned int i;
>+ char buf[BUFSIZE_FGETS], *endp;
>+
>+ if (!info->kaslr_offset && info->file_vmcoreinfo) {
>+ if (fseek(info->file_vmcoreinfo, 0, SEEK_SET) < 0) {
>+ ERRMSG("Can't seek the vmcoreinfo file(%s). %s\n",
>+ info->name_vmcoreinfo, strerror(errno));
>+ return FALSE;
>+ }
>+
>+ while (fgets(buf, BUFSIZE_FGETS, info->file_vmcoreinfo)) {
>+ i = strlen(buf);
>+ if (!i)
>+ break;
>+ if (buf[i - 1] == '\n')
>+ buf[i - 1] = '\0';
>+ if (strncmp(buf, STR_KERNELOFFSET,
>+ strlen(STR_KERNELOFFSET)) == 0)
>+ info->kaslr_offset =
>+ strtoul(buf+strlen(STR_KERNELOFFSET),&endp,16);
>+ }
>+ }
>+ 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..4986d098d69a 100644
>--- a/makedumpfile.c
>+++ b/makedumpfile.c
>@@ -2099,6 +2099,13 @@ void
> write_vmcoreinfo_data(void)
> {
> /*
>+ * write 1st kernel's KERNELOFFSET
>+ */
>+ if (info->kaslr_offset)
>+ fprintf(info->file_vmcoreinfo, "%s%lx\n", STR_KERNELOFFSET,
>+ info->kaslr_offset);
When will this data written to VMCOREINFO file be used ?
info->kaslr_offset is necessary for vmlinux but -x and -i are exclusive.
Thanks,
Atsushi Kumagai
>+ /*
> * write 1st kernel's OSRELEASE
> */
> fprintf(info->file_vmcoreinfo, "%s%s\n", STR_OSRELEASE,
>@@ -3782,6 +3789,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));
>+
>+ close_vmcoreinfo();
>+
>+ ret = TRUE;
>+out:
>+ free(info->name_vmcoreinfo);
>+ info->name_vmcoreinfo = NULL;
>+
>+ return ret;
>+}
>+
>+int
> initial(void)
> {
> off_t offset;
>@@ -3833,6 +3880,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;
>
>@@ -8635,6 +8685,7 @@ close_vmcoreinfo(void)
> if(fclose(info->file_vmcoreinfo) < 0)
> ERRMSG("Can't close the vmcoreinfo file(%s). %s\n",
> info->name_vmcoreinfo, strerror(errno));
>+ info->file_vmcoreinfo = NULL;
> }
>
> void
>@@ -11026,11 +11077,13 @@ main(int argc, char *argv[])
> strerror(errno));
> goto out;
> }
>+ info->file_vmcoreinfo = NULL;
> info->fd_vmlinux = -1;
> info->fd_xen_syms = -1;
> 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..9f16becadd55 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 { \
>@@ -495,6 +499,7 @@ do { \
> #define STR_CONFIG_X86_PAE "CONFIG_X86_PAE=y"
> #define STR_CONFIG_PGTABLE_4 "CONFIG_PGTABLE_4=y"
> #define STR_CONFIG_PGTABLE_3 "CONFIG_PGTABLE_3=y"
>+#define STR_KERNELOFFSET "KERNELOFFSET="
>
> /*
> * common value
>@@ -838,6 +843,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 +857,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 +870,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 +885,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 +898,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 +910,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 +923,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 +936,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 +1166,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 +1818,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);
>--
>2.9.3
>
More information about the kexec
mailing list