Fix refiltering when kaslr enabled
Subsystems (2)
v2 cover Fix refiltering when kaslr enabled
Hi All,
We came across another failure in makedumpfile when kaslr is enabled. This failure occurs when we try re-filtering. We try to erase some symbol from a dumpfile which was copied/compressed from /proc/vmcore using makedumpfile.
We have very limited symbol information in vmcoreinfo. So symbols to be erased may not be available in vmcoreinfo and we look for it in vmlinux. However, symbol address from vmlinux is a static address which differs from run time address with KASLR_OFFSET. Therefore, reading any "virtual address of vmlinux" from vmcore is not possible.
These patches finds runtime KASLR offset and then calculates run time address of symbols read from vmlinux.
Since, I am not an expert of x86, and these patches touch x86 part of makedumpfile, therefore I have CCed x86 experts. Please, provide your review comment and let me know if you think there could have been a better way to resolve this issue.
thanks
~Pratyush
v1->v2:
- reading KERNELOFFSET from vmcoreinfo now instead of calculating it from _stext
Pratyush Anand (2):
makedumpfile: add runtime kaslr offset if it exists
x86_64: calculate page_offset in case of re-filtering
arch/x86_64.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- erase_info.c | 1 + makedumpfile.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ makedumpfile.h | 16 ++++++++++++++++ 4 files changed, 124 insertions(+), 2 deletions(-)
Signature · 7 lines
2.9.3 _______________________________________________ kexec mailing list [email protected] http://lists.infradead.org/mailman/listinfo/kexec
PATCH v2 1/2 makedumpfile: add runtime kaslr offset if it exists
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.
--- arch/x86_64.c | 36 ++++++++++++++++++++++++++++++++++++ erase_info.c | 1 + makedumpfile.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ makedumpfile.h | 16 ++++++++++++++++ 4 files changed, 104 insertions(+)
arch/x86_64.c +36 -0
@@ -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 = +strtol (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 ) {
erase_info.c +1 -0
@@ -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);
makedumpfile.c +51 -0
75 lines not on this page · raw message
makedumpfile.h +16 -0
@@ -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 );
Signature · 7 lines
2.9.3 _______________________________________________ kexec mailing list [email protected] http://lists.infradead.org/mailman/listinfo/kexec
PATCH v2 2/2 x86_64: calculate page_offset in case of re-filtering
In reply to Pratyush Anandwe do not call get_elf_info() in case of refiltering. Therefore, we will not have any pt_load in that case, and so we get:
get_page_offset_x86_64: Can't get any pt_load to calculate page offset.
However, we will have vmcoreinfo and vmlinux information in case of re-filtering. So, we are able to find kaslr offset and we can get page_offset_base address. Thus we can read the page offset as well. However, if kaslr is not enabled then use old method to find fixed page offset.
--- arch/x86_64.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)
arch/x86_64.c +20 -2
@@ -75,6 +75,7 @@ get_page_offset_x86_64(void)int i;unsigned long long phys_start;unsigned long long virt_start; +unsigned long page_offset_base;for (i =0 ;get_pt_load (i, &phys_start,NULL , &virt_start,NULL ); i++) { if (virt_start < __START_KERNEL_map
@@ -84,8 +85,25 @@ get_page_offset_x86_64(void) } } -ERRMSG ("Can't get any pt_load to calculate page offset.\n" ); -return FALSE; +if (!info->flag_refiltering) { +ERRMSG ("Can't get any pt_load to calculate page offset.\n" ); +return FALSE; + } +if (info->kaslr_offset) { + page_offset_base =get_symbol_addr ("page_offset_base" ); + page_offset_base += info->kaslr_offset; +if (!readmem (VADDR , page_offset_base, &info->page_offset, +sizeof (info->page_offset))) { +ERRMSG ("Can't read page_offset_base.\n" ); +return FALSE; + } + }else if (info->kernel_version <KERNEL_VERSION (2 ,6 ,27 )) { + info->page_offset = __PAGE_OFFSET_ORIG; + }else { + info->page_offset = __PAGE_OFFSET_2_6_27; + } + +return TRUE; }int
Signature · 7 lines
2.9.3 _______________________________________________ kexec mailing list [email protected] http://lists.infradead.org/mailman/listinfo/kexec