From 78053fb3dded3601928a222b8118d3ef213d9d3f Mon Sep 17 00:00:00 2001 From: Yueyi Li Date: Tue, 14 Mar 2017 21:25:21 +0800 Subject: [PATCH] [ARM64][patch] Auto calculate kimage_voffset by kaslr offset ARM64 kimage_voffset can be calculated if kernel ASLR offset is known. Add a function to auto calculate kimage_voffset when '--kaslr=' was set. --- arm64.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 108 insertions(+), 14 deletions(-) diff --git a/arm64.c b/arm64.c index 6eaf96d..c857b5c 100644 --- a/arm64.c +++ b/arm64.c @@ -27,6 +27,7 @@ static struct machine_specific arm64_machine_specific = { 0 }; static int arm64_verify_symbol(const char *, ulong, char); static void arm64_parse_cmdline_args(void); +static void arm64_calc_kimage_voffset(void); static void arm64_calc_phys_offset(void); static void arm64_calc_virtual_memory_ranges(void); static int arm64_kdump_phys_base(ulong *); @@ -324,6 +325,9 @@ arm64_init(int when) machdep->init_kernel_pgd = arm64_init_kernel_pgd; /* use machdep parameters */ + arm64_calc_kimage_voffset(); + + /* use machdep parameters */ arm64_calc_phys_offset(); if (CRASHDEBUG(1)) { @@ -735,6 +739,83 @@ arm64_parse_cmdline_args(void) } } +static void +arm64_calc_kimage_voffset(void) +{ + struct machine_specific *ms = machdep->machspec; + ulong phys_offset; + + if (ms->kimage_voffset) /* vmcoreinfo or --machdep override */ + return; + + if (!(kt->flags2 & KASLR) || !(kt->flags & RELOC_SET)) /*Calculate kiamge_voffset when KASLR enabled.*/ + return; + + if(ACTIVE()){ + char buf[BUFSIZE]; + char *p1; + int errflag; + FILE *iomem; + ulong kernel_code_range; + ulong memory_end; + ulong memory_start; + + if ((iomem = fopen("/proc/iomem", "r")) == NULL) + return; + + kernel_code_range = symbol_value("__init_begin") - symbol_value("_text"); + + errflag = 1; + while (fgets(buf, BUFSIZE, iomem)) { + if (strstr(buf, ": System RAM")) { + clean_line(buf); + + /*get end address of system ram region*/ + if (!(p1 = strstr(buf, ":"))) + continue; + *(p1-1) = NULLCHAR; + if (!(p1 = strstr(buf, "-"))) + continue; + memory_end = htol(p1+1, RETURN_ON_ERROR | QUIET, NULL); + if (BADADDR == memory_end) + continue; + + /*get start address of system ram region*/ + *p1 = NULLCHAR; + memory_start = htol(buf, RETURN_ON_ERROR | QUIET, NULL); + if (BADADDR == memory_start) + continue; + + /* system ram region is to small to load kernel code, find next region*/ + if((memory_end - memory_start) < kernel_code_range) + continue; + + errflag = 0; + break; + } + } + fclose(iomem); + + if (errflag) + return; + + phys_offset = memory_start; + }else if (DISKDUMP_DUMPFILE()) + return; + else if (KDUMP_DUMPFILE()) + arm_kdump_phys_base(&phys_offset); /*Get start address of first memory block*/ + else{ + error(WARNING, + "kimage_voffset cannot be determined from the dumpfile.\n"); + error(CONT, + "Using default value of 0. If this is not correct, then try\n"); + error(CONT, + "using the command line option: --machdep kimage_voffset=\n"); + return; + } + + ms->kimage_voffset = ms->vmalloc_start_addr + (kt->relocate * -1) - phys_offset; +} static void arm64_calc_phys_offset(void) @@ -758,6 +839,9 @@ arm64_calc_phys_offset(void) FILE *iomem; physaddr_t paddr; struct syment *sp; + ulong kernel_code_range; + ulong memory_end; + ulong memory_start; if ((machdep->flags & NEW_VMEMMAP) && ms->kimage_voffset && (sp = kernel_symbol_search("memstart_addr"))) { @@ -772,14 +856,33 @@ arm64_calc_phys_offset(void) if ((iomem = fopen("/proc/iomem", "r")) == NULL) return; - /* - * Memory regions are sorted in ascending order. We take the - * first region which should be correct for most uses. - */ + kernel_code_range = symbol_value("__init_begin") - symbol_value("_text"); + errflag = 1; while (fgets(buf, BUFSIZE, iomem)) { if (strstr(buf, ": System RAM")) { clean_line(buf); + + /*get end address of system ram region*/ + if (!(p1 = strstr(buf, ":"))) + continue; + *(p1-1) = NULLCHAR; + if (!(p1 = strstr(buf, "-"))) + continue; + memory_end = htol(p1+1, RETURN_ON_ERROR | QUIET, NULL); + if (BADADDR == memory_end) + continue; + + /*get start address of system ram region*/ + *p1 = NULLCHAR; + memory_start = htol(buf, RETURN_ON_ERROR | QUIET, NULL); + if (BADADDR == memory_start) + continue; + + /* system ram region is to small to load kernel code, find next region*/ + if((memory_end - memory_start) < kernel_code_range) + continue; + errflag = 0; break; } @@ -789,16 +892,7 @@ arm64_calc_phys_offset(void) if (errflag) return; - if (!(p1 = strstr(buf, "-"))) - return; - - *p1 = NULLCHAR; - - phys_offset = htol(buf, RETURN_ON_ERROR | QUIET, &errflag); - if (errflag) - return; - - ms->phys_offset = phys_offset; + phys_offset = memory_start; } else if (DISKDUMP_DUMPFILE() && diskdump_phys_base(&phys_offset)) { ms->phys_offset = phys_offset; } else if (KDUMP_DUMPFILE() && arm64_kdump_phys_base(&phys_offset)) { -- 1.9.1