diff --git a/defs.h b/defs.h index d0b021f..00971ba 100644 --- a/defs.h +++ b/defs.h @@ -2697,6 +2697,7 @@ struct symbol_table_data { ulong pti_init_vmlinux; ulong kaiser_init_vmlinux; int kernel_symbol_type; + ulong linux_banner_vmlinux; }; /* flags for st */ diff --git a/kaslr_helper.c b/kaslr_helper.c index fe5909c..bb19e54 100644 --- a/kaslr_helper.c +++ b/kaslr_helper.c @@ -394,10 +394,11 @@ quit: #define PTI_USER_PGTABLE_MASK (1 << PTI_USER_PGTABLE_BIT) #define CR3_PCID_MASK 0xFFFull int -calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_base) +calc_kaslr_offset(ulong *ko, ulong *pb) { uint64_t cr3 = 0, idtr = 0, pgd = 0, idtr_paddr; ulong divide_error_vmcore; + ulong kaslr_offset, phys_base; ulong kaslr_offset_kdump, phys_base_kdump; int ret = FALSE; int verbose = CRASHDEBUG(1)? 1: 0; @@ -405,6 +406,7 @@ calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_base) if (!machine_type("X86_64")) return FALSE; +retry: if (SADUMP_DUMPFILE()) { if (!sadump_get_cr3_idtr(&cr3, &idtr)) return FALSE; @@ -436,18 +438,48 @@ calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_base) 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); - *kaslr_offset = divide_error_vmcore - st->divide_error_vmlinux; - *phys_base = idtr_paddr - - (st->idt_table_vmlinux + *kaslr_offset - __START_KERNEL_map); + kaslr_offset = divide_error_vmcore - st->divide_error_vmlinux; + 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); @@ -465,9 +497,9 @@ calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_base) * from vmcoreinfo */ if (get_kaslr_offset_from_vmcoreinfo( - *kaslr_offset, &kaslr_offset_kdump, &phys_base_kdump)) { - *kaslr_offset = kaslr_offset_kdump; - *phys_base = phys_base_kdump; + kaslr_offset, &kaslr_offset_kdump, &phys_base_kdump)) { + kaslr_offset = kaslr_offset_kdump; + phys_base = phys_base_kdump; } else if (CRASHDEBUG(1)) { fprintf(fp, "kaslr_helper: failed to determine which kernel was running at crash,\n"); fprintf(fp, "kaslr_helper: asssuming the kdump 1st kernel.\n"); @@ -475,10 +507,13 @@ calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_base) if (CRASHDEBUG(1)) { fprintf(fp, "calc_kaslr_offset: kaslr_offset=%lx\n", - *kaslr_offset); - fprintf(fp, "calc_kaslr_offset: phys_base=%lx\n", *phys_base); + kaslr_offset); + fprintf(fp, "calc_kaslr_offset: phys_base=%lx\n", phys_base); } + *ko = kaslr_offset; + *pb = phys_base; + ret = TRUE; quit: vt->kernel_pgd[0] = 0; diff --git a/sadump.c b/sadump.c index 35f7cf0..009e17a 100644 --- a/sadump.c +++ b/sadump.c @@ -1664,29 +1664,32 @@ get_sadump_data(void) static int get_sadump_smram_cpu_state_any(struct sadump_smram_cpu_state *smram) { - ulong offset; - struct sadump_header *sh = sd->dump_header; - int apicid; - struct sadump_smram_cpu_state scs, zero; - - offset = sd->sub_hdr_offset + sizeof(uint32_t) + - sd->dump_header->nr_cpus * sizeof(struct sadump_apic_state); - - memset(&zero, 0, sizeof(zero)); - - for (apicid = 0; 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) { - *smram = scs; - return TRUE; - } - } - - return FALSE; + ulong offset; + struct sadump_header *sh = sd->dump_header; + static int apicid; + struct sadump_smram_cpu_state scs; + + if (apicid >= sh->nr_cpus) + return FALSE; + + offset = sd->sub_hdr_offset + sizeof(uint32_t) + + sd->dump_header->nr_cpus * sizeof(struct sadump_apic_state) + + apicid * sizeof(scs); + + 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 (scs.Cr3 && (scs.IdtUpper || scs.IdtLower)) { + *smram = scs; + return TRUE; + } + } + + return FALSE; } int @@ -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; diff --git a/symbols.c b/symbols.c index f04e8b5..717a56b 100644 --- a/symbols.c +++ b/symbols.c @@ -3227,6 +3227,11 @@ dump_symbol_table(void) fprintf(fp, " kaiser_init_vmlinux: (unused)\n"); } + if (SADUMP_DUMPFILE()) + fprintf(fp, "linux_banner_vmlinux: %lx\n", st->linux_banner_vmlinux); + else + fprintf(fp, "linux_banner_vmlinux: (unused)\n"); + fprintf(fp, " symval_hash[%d]: %lx\n", SYMVAL_HASH, (ulong)&st->symval_hash[0]); @@ -12629,15 +12634,25 @@ numeric_forward(const void *P_x, const void *P_y) else if (STREQ(y->name, "idt_table")) st->idt_table_vmlinux = valueof(y); + if (STREQ(x->name, "kaiser_init")) + st->kaiser_init_vmlinux = valueof(x); + else if (STREQ(y->name, "kaiser_init")) + st->kaiser_init_vmlinux = valueof(y); + + if (STREQ(x->name, "linux_banner")) + st->linux_banner_vmlinux = valueof(x); + else if (STREQ(y->name, "linux_banner")) + st->linux_banner_vmlinux = valueof(y); + + if (STREQ(x->name, "pti_init")) + st->pti_init_vmlinux = valueof(x); + else if (STREQ(y->name, "pti_init")) + st->pti_init_vmlinux = valueof(y); + if (STREQ(x->name, "saved_command_line")) st->saved_command_line_vmlinux = valueof(x); else if (STREQ(y->name, "saved_command_line")) st->saved_command_line_vmlinux = valueof(y); - - if (STREQ(x->name, "pti_init")) - st->pti_init_vmlinux = valueof(x); - else if (STREQ(y->name, "kaiser_init")) - st->kaiser_init_vmlinux = valueof(y); } xs = bfd_get_section(x);