Re: [ARM64][patch v3] Auto calculate kimage_voffset by kaslr offset

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 2017/3/17 4:57, Dave Anderson wrote:
>
> Yueyi Li,
>
> The live system case addition to your patch is interesting, and is the only thing
> I can really test.
>
> I tried your patch on 2 live systems which are KASLR-capable, but where
> CONFIG_RANDOMIZE_BASE is not configured.   One of them is 4.8-based, and
> the other is 4.10-based.  I commented out the ioctl() call to the /dev/crash
> driver that returns the value of kimage_voffset, and invoked the session
> as "crash --kaslr=0".  Doing it that way forces your arm64_calc_kimage_voffset()
> function to run its ACTIVE() section.
>
> However, it only works on one of the 4.10-based systems.
>
> The problem is related to the value of the kernel's actual PHYS_BASE value that
> is stored in the "memstart_addr" symbol, vs. what is seen in the /proc/iomem output.
>
> On the Linux 4.10-based system where your patch works OK, these are the values:
>
>    # cat /proc/iomem
>    ...
>    4000000000-40001fffff : reserved
>    4000200000-4001ffffff : System RAM
>      4000280000-4000ccffff : Kernel code
>      4000e00000-40016effff : Kernel data
>    40023b0000-4ff733ffff : System RAM
>    4ff7340000-4ff77cffff : reserved
>    4ff77d0000-4ff792ffff : System RAM
>    4ff7930000-4ff7e7ffff : reserved
>    4ff7e80000-4ff7e8ffff : System RAM
>    4ff7e90000-4ff7efffff : reserved
>    4ff7f10000-4ff800ffff : reserved
>    4ff8010000-4fffffffff : System RAM
>    ...
>
>    crash> px memstart_addr
>    memstart_addr = $1 = 0x4000000000
>    crash> help -m | grep phys_offset
>               phys_offset: 4000000000
>    crash>
>
> Note that /proc/iomem shows the lowest "RAM" secttion at 4000200000,
> whereas the real PHYS_OFFSET is 4000000000.  So your arm64_calc_kimage_voffset()
> function calculates its local phys_offset value as 4000200000 from the output of
> /proc/iomem, and uses it to calculate the *correct* value of kimage_voffset.
> But that's seems strange to me, given that 4000200000 is not the actual PHYS_OFFSET
> value that is stored in memstart_addr, and which is used by the crash utility for
> address translation?
PHYS_OFFSET should be the offset  between VA_START physical address and 
ZERO address. For most arm64 system, VA_START is start address of 
physical memory, but there is a 2M reserved memory region on your 
4.10-base system, so that PHYS_OFFSET is 0x400200000.
>
> However, on the Linux 4.8-based system where it fails, these are the values,
> where you'll note that there are no "reserved" sections shown:
>    
>    # cat /proc/iomem
>    ...
>    4000000000-40001fffff : System RAM
>    4000200000-43fa59ffff : System RAM
>      4000280000-4000c7ffff : Kernel code
>      4000d90000-400166ffff : Kernel data
>    43fa5a0000-43fa9dffff : System RAM
>    43fa9e0000-43ff99ffff : System RAM
>    43ff9a0000-43ff9affff : System RAM
>    43ff9b0000-43ff9bffff : System RAM
>    43ff9c0000-43ff9effff : System RAM
>    43ff9f0000-43ffffffff : System RAM
>    ...
>
>    crash> px memstart_addr
>    memstart_addr = $1 = 0x4000000000
>    crash> help -m | grep phys_offset
>               phys_offset: 4000000000
>    crash>
>
> Also note that the /proc/iomem base RAM and memstart_addr values are the
> same 4000000000.  So in this case, your arm64_calc_kimage_voffset() function
> calculates the temporary phys_base as 4000000000 from /proc/iomem, and uses it
> to calculate an *incorrect* value of kimage_voffset, and the crash session
> fails.  (Interestingly enough, if I hard-code the temporary value to be
> 4000200000, it works OK!)
>
> So that make me wonder how this makes sense when arm64_calc_kimage_voffset()
> uses your ELF dumpfile as the source of phys_base?  Do you have the
> capability of looking at /proc/iomem on the system that was the source
> of your dumpfile?  Do your /proc/iomem values reflect what's in the
> dumpfile's lowest PT_LOAD segment?
On your 4.8-based system,  also have 2M reserved memory region, but it 
be claimed  'System RAM'.  On kernel booting, it will request first big 
enough 'System RAM' memory region to load kernel code, the first region 
of 4.8-base system is too small to load kernel code.

So, it means there is a BUG in crash utility phys_offset calculate on 
live system, seems the committer had realized it.
in arm64_calc_phys_offset():

         /*
          * Memory regions are sorted in ascending order. We take the
          * first region which should be correct for most uses.
          */
         errflag = 1;
         while (fgets(buf, BUFSIZE, iomem)) {
             if (strstr(buf, ": System RAM")) {
                 clean_line(buf);
                 errflag = 0;
                 break;
             }
         }
         fclose(iomem);

>
> Dave
>
> --
> Crash-utility mailing list
> Crash-utility@xxxxxxxxxx
> https://www.redhat.com/mailman/listinfo/crash-utility
I made fix in patch v4, please check.

Thanks,
Yueyi Li
From 78053fb3dded3601928a222b8118d3ef213d9d3f Mon Sep 17 00:00:00 2001
From: Yueyi Li <liyueyi@xxxxxxxx>
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=<offset>'
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=<addr>\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

--
Crash-utility mailing list
Crash-utility@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/crash-utility

[Index of Archives]     [Fedora Development]     [Fedora Desktop]     [Fedora SELinux]     [Yosemite News]     [KDE Users]     [Fedora Tools]

 

Powered by Linux