[Crash-utility] [PATCH 4/4] kaslr: fix failure of calculating kaslr_offset due to an sadump format restriction

HAGIO KAZUHITO(萩尾 一仁) k-hagio-ab at nec.com
Wed Jul 22 05:11:54 UTC 2020


> -----Original Message-----
> From: HATAYAMA Daisuke <d.hatayama at jp.fujitsu.com>
> 
> We faced recently a memory dump collected by sadump where unused part
> of register values are non-zero. For the crash dump, calculating
> kaslr_offset fails because it is based on the assumption that unused
> part of register values in the sadump format are always zero cleared.
> 
> The problem is that used and unused part of register values are
> rigorously indistinguishable in the sadump format. Although there is
> kernel data structure that represents a map between logical cpu
> numbers and lapic ids, they cannot be used in order to calculate
> kaslr_offset.
> 
> To fix this, we have no choice but use a trial-and-error approach: try
> to use each entry of register values in order until we find a good
> pair of cr3 and idtr by which we can refer to linux_banner symbol as
> expected.
> 
> This fix is for the sadump specific issue, so there is no functional
> change for the other crash dump formats.
> ---
>  kaslr_helper.c | 39 +++++++++++++++++++++++++++++++++++----
>  sadump.c       | 18 +++++++++++-------
>  2 files changed, 46 insertions(+), 11 deletions(-)
> 
> diff --git a/kaslr_helper.c b/kaslr_helper.c
> index acbb5c2..bb19e54 100644
> --- a/kaslr_helper.c
> +++ b/kaslr_helper.c
> @@ -406,6 +406,7 @@ calc_kaslr_offset(ulong *ko, ulong *pb)
>  	if (!machine_type("X86_64"))
>  		return FALSE;
> 
> +retry:
>  	if (SADUMP_DUMPFILE()) {
>  		if (!sadump_get_cr3_idtr(&cr3, &idtr))
>  			return FALSE;
> @@ -437,12 +438,20 @@ calc_kaslr_offset(ulong *ko, ulong *pb)
>  	machdep->machspec->pgdir_shift = PGDIR_SHIFT;
>  	machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD;
>  	if (!readmem(pgd, PHYSADDR, machdep->pgd, PAGESIZE(),
> -			"pgd", RETURN_ON_ERROR))
> -		goto quit;
> +			"pgd", RETURN_ON_ERROR)) {
> +		if (SADUMP_DUMPFILE())
> +			goto retry;
> +		else
> +			goto quit;
> +	}
> 
>  	/* Convert virtual address of IDT table to physical address */
> -	if (!kvtop(NULL, idtr, &idtr_paddr, verbose))
> -		goto quit;
> +	if (!kvtop(NULL, idtr, &idtr_paddr, verbose)) {
> +		if (SADUMP_DUMPFILE())
> +			goto retry;
> +		else
> +			goto quit;
> +	}
> 
>  	/* Now we can calculate kaslr_offset and phys_base */
>  	divide_error_vmcore = get_vec0_addr(idtr_paddr);
> @@ -450,6 +459,28 @@ calc_kaslr_offset(ulong *ko, ulong *pb)
>  	phys_base = idtr_paddr -
>  		(st->idt_table_vmlinux + kaslr_offset - __START_KERNEL_map);
> 
> +	if (SADUMP_DUMPFILE()) {
> +		char buf[sizeof("Linux version")];
> +		ulong linux_banner_paddr;
> +
> +		if (!kvtop(NULL,
> +			   st->linux_banner_vmlinux + kaslr_offset,
> +			   &linux_banner_paddr,
> +			   verbose))
> +			goto retry;
> +
> +		if (!readmem(linux_banner_paddr,
> +			     PHYSADDR,
> +			     buf,
> +			     sizeof(buf),
> +			     "linux_banner",
> +			     RETURN_ON_ERROR))
> +			goto retry;
> +
> +		if (!STRNEQ(buf, "Linux version"))
> +			goto retry;
> +	}
> +
>  	if (CRASHDEBUG(1)) {
>  		fprintf(fp, "calc_kaslr_offset: idtr=%lx\n", idtr);
>  		fprintf(fp, "calc_kaslr_offset: pgd=%lx\n", pgd);
> diff --git a/sadump.c b/sadump.c
> index 35f7cf0..85b4a09 100644
> --- a/sadump.c
> +++ b/sadump.c
> @@ -1666,21 +1666,24 @@ get_sadump_smram_cpu_state_any(struct sadump_smram_cpu_state *smram)
>  {
>          ulong offset;
>          struct sadump_header *sh = sd->dump_header;
> -        int apicid;
> +        static int apicid;
>          struct sadump_smram_cpu_state scs, zero;

$ make clean
$ make warn
...
cc -c -g -DX86_64 -DSNAPPY -DLZO -DGDB_7_6  sadump.c -Wall -O2 -Wstrict-prototypes -Wmissing-prototypes -fstack-protector -Wformat-security 
sadump.c: In function ‘get_sadump_smram_cpu_state_any’:
sadump.c:1670:44: warning: unused variable ‘zero’ [-Wunused-variable]
         struct sadump_smram_cpu_state scs, zero;
                                            ^

I can remove that zero when merging.

> 
> -        offset = sd->sub_hdr_offset + sizeof(uint32_t) +
> -                 sd->dump_header->nr_cpus * sizeof(struct sadump_apic_state);
> +        if (apicid >= sh->nr_cpus)
> +                 return FALSE;
> 
> -        memset(&zero, 0, sizeof(zero));
> +        offset = sd->sub_hdr_offset + sizeof(uint32_t) +
> +                 sd->dump_header->nr_cpus * sizeof(struct sadump_apic_state) +
> +                 apicid * sizeof(scs);
> 
> -        for (apicid = 0; apicid < sh->nr_cpus; ++apicid) {
> +        while (apicid < sh->nr_cpus) {
> +                apicid++;
>                  if (!read_device(&scs, sizeof(scs), &offset)) {
>                          error(INFO, "sadump: cannot read sub header "
>                                "cpu_state\n");
>                          return FALSE;
>                  }
> -                if (memcmp(&scs, &zero, sizeof(scs)) != 0) {
> +                if (scs.Cr3 && (scs.IdtUpper || scs.IdtLower)) {
>                          *smram = scs;
>                          return TRUE;
>                  }
> @@ -1695,7 +1698,8 @@ sadump_get_cr3_idtr(ulong *cr3, ulong *idtr)
>  	struct sadump_smram_cpu_state scs;
> 
>  	memset(&scs, 0, sizeof(scs));
> -	get_sadump_smram_cpu_state_any(&scs);
> +	if (!get_sadump_smram_cpu_state_any(&scs))
> +		return FALSE;
> 
>  	*cr3 = scs.Cr3;
>  	*idtr = ((uint64_t)scs.IdtUpper)<<32 | (uint64_t)scs.IdtLower;
> --
> 1.8.3.1





More information about the Crash-utility mailing list