[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