diff --git a/40b93af74b51e6a322a9b70cabe7e0618973de22.patch b/40b93af74b51e6a322a9b70cabe7e0618973de22.patch new file mode 100644 index 0000000000000000000000000000000000000000..88d65f0a724f6404120c189567b35daab1a24b4b --- /dev/null +++ b/40b93af74b51e6a322a9b70cabe7e0618973de22.patch @@ -0,0 +1,171 @@ +diff --git a/defs.h b/defs.h +index d024756..9594950 100644 +--- a/defs.h ++++ b/defs.h +@@ -6626,7 +6626,7 @@ struct sadump_data; + struct sadump_data *get_sadump_data(void); + int sadump_calc_kaslr_offset(ulong *); + int sadump_get_nr_cpus(void); +-int sadump_get_cr3_idtr(int, ulong *, ulong *); ++int sadump_get_cr3_cr4_idtr(int, ulong *, ulong *, ulong *); + + /* + * qemu.c +@@ -6680,7 +6680,7 @@ int vmware_vmss_memory_dump(FILE *); + void dump_registers_for_vmss_dump(void); + int vmware_vmss_valid_regs(struct bt_info *); + int vmware_vmss_get_nr_cpus(void); +-int vmware_vmss_get_cr3_idtr(int, ulong *, ulong *); ++int vmware_vmss_get_cr3_cr4_idtr(int, ulong *, ulong *, ulong *); + int vmware_vmss_phys_base(ulong *phys_base); + int vmware_vmss_set_phys_base(ulong); + +diff --git a/kaslr_helper.c b/kaslr_helper.c +index 1a4c111..d92ea0f 100644 +--- a/kaslr_helper.c ++++ b/kaslr_helper.c +@@ -251,7 +251,7 @@ qemu_get_nr_cpus(void) + } + + static int +-qemu_get_cr3_idtr(int cpu, ulong *cr3, ulong *idtr) ++qemu_get_cr3_cr4_idtr(int cpu, ulong *cr3, ulong *cr4, ulong *idtr) + { + QEMUCPUState *cpustat; + +@@ -266,6 +266,7 @@ qemu_get_cr3_idtr(int cpu, ulong *cr3, ulong *idtr) + return FALSE; + + *cr3 = cpustat->cr[3]; ++ *cr4 = cpustat->cr[4]; + *idtr = cpustat->idt.base; + + return TRUE; +@@ -344,14 +345,14 @@ get_nr_cpus(void) + } + + static int +-get_cr3_idtr(int cpu, ulong *cr3, ulong *idtr) ++get_cr3_cr4_idtr(int cpu, ulong *cr3, ulong *cr4, ulong *idtr) + { + if (SADUMP_DUMPFILE()) +- return sadump_get_cr3_idtr(cpu, cr3, idtr); ++ return sadump_get_cr3_cr4_idtr(cpu, cr3, cr4, idtr); + else if (QEMU_MEM_DUMP_NO_VMCOREINFO()) +- return qemu_get_cr3_idtr(cpu, cr3, idtr); ++ return qemu_get_cr3_cr4_idtr(cpu, cr3, cr4, idtr); + else if (VMSS_DUMPFILE()) +- return vmware_vmss_get_cr3_idtr(cpu, cr3, idtr); ++ return vmware_vmss_get_cr3_cr4_idtr(cpu, cr3, cr4, idtr); + + return FALSE; + } +@@ -483,10 +484,11 @@ calc_kaslr_offset_from_idt(uint64_t idtr, uint64_t pgd, ulong *kaslr_offset, ulo + #define PTI_USER_PGTABLE_BIT PAGE_SHIFT + #define PTI_USER_PGTABLE_MASK (1 << PTI_USER_PGTABLE_BIT) + #define CR3_PCID_MASK 0xFFFull ++#define CR4_LA57 (1 << 12) + int + calc_kaslr_offset(ulong *ko, ulong *pb) + { +- uint64_t cr3 = 0, idtr = 0, pgd = 0; ++ uint64_t cr3 = 0, cr4 = 0, idtr = 0, pgd = 0; + ulong kaslr_offset, phys_base; + ulong kaslr_offset_kdump, phys_base_kdump; + int cpu, nr_cpus; +@@ -497,7 +499,7 @@ calc_kaslr_offset(ulong *ko, ulong *pb) + nr_cpus = get_nr_cpus(); + + for (cpu = 0; cpu < nr_cpus; cpu++) { +- if (!get_cr3_idtr(cpu, &cr3, &idtr)) ++ if (!get_cr3_cr4_idtr(cpu, &cr3, &cr4, &idtr)) + continue; + + if (!cr3) +@@ -514,13 +516,23 @@ calc_kaslr_offset(ulong *ko, ulong *pb) + * calc_kaslr_offset() is called before machdep_init(PRE_GDB), so some + * variables are not initialized yet. Set up them here to call kvtop(). + * +- * TODO: XEN and 5-level is not supported ++ * TODO: XEN is not supported + */ + vt->kernel_pgd[0] = pgd; + machdep->last_pgd_read = vt->kernel_pgd[0]; +- machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_2_6; +- machdep->machspec->pgdir_shift = PGDIR_SHIFT; +- machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD; ++ if (cr4 & CR4_LA57) { ++ machdep->flags |= VM_5LEVEL; ++ machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_5LEVEL; ++ machdep->machspec->pgdir_shift = PGDIR_SHIFT_5LEVEL; ++ machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD_5LEVEL; ++ if ((machdep->machspec->p4d = (char *)malloc(PAGESIZE())) == NULL) ++ error(FATAL, "cannot malloc p4d space."); ++ machdep->machspec->last_p4d_read = 0; ++ } else { ++ machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_2_6; ++ 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)) + continue; +diff --git a/sadump.c b/sadump.c +index 08893c4..d75c66b 100644 +--- a/sadump.c ++++ b/sadump.c +@@ -1679,7 +1679,7 @@ sadump_get_nr_cpus(void) + } + + int +-sadump_get_cr3_idtr(int cpu, ulong *cr3, ulong *idtr) ++sadump_get_cr3_cr4_idtr(int cpu, ulong *cr3, ulong *cr4, ulong *idtr) + { + struct sadump_smram_cpu_state scs; + +@@ -1688,6 +1688,7 @@ sadump_get_cr3_idtr(int cpu, ulong *cr3, ulong *idtr) + return FALSE; + + *cr3 = scs.Cr3; ++ *cr4 = scs.Cr4; + *idtr = ((uint64_t)scs.IdtUpper)<<32 | (uint64_t)scs.IdtLower; + + return TRUE; +diff --git a/vmware_vmss.c b/vmware_vmss.c +index 952ac48..52d58e8 100644 +--- a/vmware_vmss.c ++++ b/vmware_vmss.c +@@ -879,12 +879,13 @@ vmware_vmss_get_nr_cpus(void) + } + + int +-vmware_vmss_get_cr3_idtr(int cpu, ulong *cr3, ulong *idtr) ++vmware_vmss_get_cr3_cr4_idtr(int cpu, ulong *cr3, ulong *cr4, ulong *idtr) + { + if (cpu >= vmss.num_vcpus || vmss.vcpu_regs[cpu] != REGS_PRESENT_ALL) + return FALSE; + + *cr3 = vmss.regs64[cpu]->cr[3]; ++ *cr4 = vmss.regs64[cpu]->cr[4]; + *idtr = vmss.regs64[cpu]->idtr; + + return TRUE; +diff --git a/x86_64.c b/x86_64.c +index 0acef2b..939c8a9 100644 +--- a/x86_64.c ++++ b/x86_64.c +@@ -356,9 +356,11 @@ x86_64_init(int when) + machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_5LEVEL; + machdep->machspec->pgdir_shift = PGDIR_SHIFT_5LEVEL; + machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD_5LEVEL; +- if ((machdep->machspec->p4d = (char *)malloc(PAGESIZE())) == NULL) +- error(FATAL, "cannot malloc p4d space."); +- machdep->machspec->last_p4d_read = 0; ++ if (!machdep->machspec->p4d) { ++ if ((machdep->machspec->p4d = (char *)malloc(PAGESIZE())) == NULL) ++ error(FATAL, "cannot malloc p4d space."); ++ machdep->machspec->last_p4d_read = 0; ++ } + machdep->uvtop = x86_64_uvtop_level4; /* 5-level is optional per-task */ + machdep->kvbase = (ulong)PAGE_OFFSET; + machdep->identity_map_base = (ulong)PAGE_OFFSET; diff --git a/7ccdda4ab2384f7e0251308e7b8d090e1e8a091b.patch b/7ccdda4ab2384f7e0251308e7b8d090e1e8a091b.patch new file mode 100644 index 0000000000000000000000000000000000000000..c7461dfc5615f04719aef409d7afd14659e4af5b --- /dev/null +++ b/7ccdda4ab2384f7e0251308e7b8d090e1e8a091b.patch @@ -0,0 +1,504 @@ +diff --git a/defs.h b/defs.h +index 00786c2..d024756 100644 +--- a/defs.h ++++ b/defs.h +@@ -6457,6 +6457,7 @@ void display_ELF_note(int, int, void *, FILE *); + void *netdump_get_prstatus_percpu(int); + int kdump_kaslr_check(void); + void display_vmcoredd_note(void *ptr, FILE *ofp); ++int kdump_get_nr_cpus(void); + QEMUCPUState *kdump_get_qemucpustate(int); + void kdump_device_dump_info(FILE *); + void kdump_device_dump_extract(int, char *, FILE *); +@@ -6505,6 +6506,7 @@ void process_elf32_notes(void *, ulong); + void process_elf64_notes(void *, ulong); + void dump_registers_for_compressed_kdump(void); + int diskdump_kaslr_check(void); ++int diskdump_get_nr_cpus(void); + QEMUCPUState *diskdump_get_qemucpustate(int); + void diskdump_device_dump_info(FILE *); + void diskdump_device_dump_extract(int, char *, FILE *); +@@ -6623,7 +6625,8 @@ void sadump_unset_zero_excluded(void); + struct sadump_data; + struct sadump_data *get_sadump_data(void); + int sadump_calc_kaslr_offset(ulong *); +-int sadump_get_cr3_idtr(ulong *, ulong *); ++int sadump_get_nr_cpus(void); ++int sadump_get_cr3_idtr(int, ulong *, ulong *); + + /* + * qemu.c +@@ -6676,7 +6679,8 @@ void get_vmware_vmss_regs(struct bt_info *, ulong *, ulong *); + int vmware_vmss_memory_dump(FILE *); + void dump_registers_for_vmss_dump(void); + int vmware_vmss_valid_regs(struct bt_info *); +-int vmware_vmss_get_cr3_idtr(ulong *, ulong *); ++int vmware_vmss_get_nr_cpus(void); ++int vmware_vmss_get_cr3_idtr(int, ulong *, ulong *); + int vmware_vmss_phys_base(ulong *phys_base); + int vmware_vmss_set_phys_base(ulong); + +diff --git a/diskdump.c b/diskdump.c +index 63a08a1..4f14596 100644 +--- a/diskdump.c ++++ b/diskdump.c +@@ -2517,6 +2517,12 @@ diskdump_kaslr_check() + } + + #ifdef X86_64 ++int ++diskdump_get_nr_cpus(void) ++{ ++ return dd->num_qemu_notes; ++} ++ + QEMUCPUState * + diskdump_get_qemucpustate(int cpu) + { +diff --git a/kaslr_helper.c b/kaslr_helper.c +index bb19e54..1a4c111 100644 +--- a/kaslr_helper.c ++++ b/kaslr_helper.c +@@ -240,21 +240,30 @@ get_vmcoreinfo(ulong elfcorehdr, ulong *addr, int *len) + } + + static int +-qemu_get_cr3_idtr(ulong *cr3, ulong *idtr) ++qemu_get_nr_cpus(void) ++{ ++ if (DISKDUMP_DUMPFILE()) ++ return diskdump_get_nr_cpus(); ++ else if (KDUMP_DUMPFILE()) ++ return kdump_get_nr_cpus(); ++ ++ return 0; ++} ++ ++static int ++qemu_get_cr3_idtr(int cpu, ulong *cr3, ulong *idtr) + { + QEMUCPUState *cpustat; + +- if (DISKDUMP_DUMPFILE()) { +- cpustat = diskdump_get_qemucpustate(0); +- } else if (KDUMP_DUMPFILE()) { +- cpustat = kdump_get_qemucpustate(0); +- } else { ++ if (DISKDUMP_DUMPFILE()) ++ cpustat = diskdump_get_qemucpustate(cpu); ++ else if (KDUMP_DUMPFILE()) ++ cpustat = kdump_get_qemucpustate(cpu); ++ else + return FALSE; +- } + +- if (!cpustat) { ++ if (!cpustat) + return FALSE; +- } + + *cr3 = cpustat->cr[3]; + *idtr = cpustat->idt.base; +@@ -321,18 +330,55 @@ get_kaslr_offset_from_vmcoreinfo(ulong orig_kaslr_offset, + return ret; + } + ++static int ++get_nr_cpus(void) ++{ ++ if (SADUMP_DUMPFILE()) ++ return sadump_get_nr_cpus(); ++ else if (QEMU_MEM_DUMP_NO_VMCOREINFO()) ++ return qemu_get_nr_cpus(); ++ else if (VMSS_DUMPFILE()) ++ return vmware_vmss_get_nr_cpus(); ++ ++ return 0; ++} ++ ++static int ++get_cr3_idtr(int cpu, ulong *cr3, ulong *idtr) ++{ ++ if (SADUMP_DUMPFILE()) ++ return sadump_get_cr3_idtr(cpu, cr3, idtr); ++ else if (QEMU_MEM_DUMP_NO_VMCOREINFO()) ++ return qemu_get_cr3_idtr(cpu, cr3, idtr); ++ else if (VMSS_DUMPFILE()) ++ return vmware_vmss_get_cr3_idtr(cpu, cr3, idtr); ++ ++ return FALSE; ++} ++ ++#define BANNER "Linux version" ++static int ++verify_kaslr_offset(ulong kaslr_offset) ++{ ++ char buf[sizeof(BANNER)]; ++ ulong linux_banner_paddr; ++ ++ if (!kvtop(NULL, st->linux_banner_vmlinux + kaslr_offset, ++ &linux_banner_paddr, CRASHDEBUG(1))) ++ return FALSE; ++ ++ if (!readmem(linux_banner_paddr, PHYSADDR, buf, sizeof(buf), ++ "linux_banner", RETURN_ON_ERROR)) ++ return FALSE; ++ ++ if (!STRNEQ(buf, BANNER)) ++ return FALSE; ++ ++ return TRUE; ++} ++ + /* +- * Calculate kaslr_offset and phys_base +- * +- * kaslr_offset: +- * The difference between original address in System.map or vmlinux and +- * actual address placed randomly by kaslr feature. To be more accurate, +- * kaslr_offset = actual address - original address +- * +- * phys_base: +- * Physical address where the kerenel is placed. In other words, it's a +- * physical address of __START_KERNEL_map. This is also decided randomly by +- * kaslr. ++ * IDT based method to calculate kaslr_offset and phys_base + * + * kaslr offset and phys_base are calculated as follows: + * +@@ -370,17 +416,61 @@ get_kaslr_offset_from_vmcoreinfo(ulong orig_kaslr_offset, + * Note that the address (A) cannot be used instead of (E) because (A) is + * not direct map address, it's a fixed map address. + * +- * This solution works in most every case, but does not work in the +- * following case. ++ * NOTE: This solution works in most every case, but does not work in the ++ * following case. If the dump is captured on early stage of kernel boot, ++ * IDTR points to the early IDT table(early_idts) instead of normal ++ * IDT(idt_table). Need enhancement. ++ */ ++static int ++calc_kaslr_offset_from_idt(uint64_t idtr, uint64_t pgd, ulong *kaslr_offset, ulong *phys_base) ++{ ++ uint64_t idtr_paddr; ++ ulong divide_error_vmcore; ++ int verbose = CRASHDEBUG(1)? 1: 0; ++ ++ if (!idtr) ++ return FALSE; ++ ++ /* Convert virtual address of IDT table to physical address */ ++ if (!kvtop(NULL, idtr, &idtr_paddr, verbose)) ++ return FALSE; ++ ++ /* 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); ++ ++ if (verbose) { ++ fprintf(fp, "calc_kaslr_offset: idtr=%lx\n", idtr); ++ fprintf(fp, "calc_kaslr_offset: pgd=%lx\n", pgd); ++ fprintf(fp, "calc_kaslr_offset: idtr(phys)=%lx\n", idtr_paddr); ++ fprintf(fp, "calc_kaslr_offset: divide_error(vmlinux): %lx\n", ++ st->divide_error_vmlinux); ++ fprintf(fp, "calc_kaslr_offset: divide_error(vmcore): %lx\n", ++ divide_error_vmcore); ++ } ++ return TRUE; ++} ++ ++/* ++ * Calculate kaslr_offset and phys_base + * +- * 1) If the dump is captured on early stage of kernel boot, IDTR points +- * early IDT table(early_idts) instead of normal IDT(idt_table). +- * 2) If the dump is captured whle kdump is working, IDTR points +- * IDT table of 2nd kernel, not 1st kernel. ++ * kaslr_offset: ++ * The difference between original address in System.map or vmlinux and ++ * actual address placed randomly by kaslr feature. To be more accurate, ++ * kaslr_offset = actual address - original address + * +- * Current implementation does not support the case 1), need +- * enhancement in the future. For the case 2), get kaslr_offset and +- * phys_base as follows. ++ * phys_base: ++ * Physical address where the kerenel is placed. In other words, it's a ++ * physical address of __START_KERNEL_map. This is also decided randomly by ++ * kaslr. ++ * ++ * It walks through all available CPUs registers to calculate the offset/base. ++ * ++ * Also, it considers the case where dump is captured whle kdump is working, ++ * IDTR points to the IDT table of 2nd kernel, not 1st kernel. ++ * In that case, get kaslr_offset and phys_base as follows. + * + * 1) Get kaslr_offset and phys_base using the above solution. + * 2) Get kernel boot parameter from "saved_command_line" +@@ -396,110 +486,66 @@ get_kaslr_offset_from_vmcoreinfo(ulong orig_kaslr_offset, + int + calc_kaslr_offset(ulong *ko, ulong *pb) + { +- uint64_t cr3 = 0, idtr = 0, pgd = 0, idtr_paddr; +- ulong divide_error_vmcore; ++ uint64_t cr3 = 0, idtr = 0, pgd = 0; + ulong kaslr_offset, phys_base; + ulong kaslr_offset_kdump, phys_base_kdump; +- int ret = FALSE; +- int verbose = CRASHDEBUG(1)? 1: 0; ++ int cpu, nr_cpus; + + if (!machine_type("X86_64")) + return FALSE; + +-retry: +- if (SADUMP_DUMPFILE()) { +- if (!sadump_get_cr3_idtr(&cr3, &idtr)) +- return FALSE; +- } else if (QEMU_MEM_DUMP_NO_VMCOREINFO()) { +- if (!qemu_get_cr3_idtr(&cr3, &idtr)) +- return FALSE; +- } else if (VMSS_DUMPFILE()) { +- if (!vmware_vmss_get_cr3_idtr(&cr3, &idtr)) +- return FALSE; +- } else +- return FALSE; ++ nr_cpus = get_nr_cpus(); + +- if (st->pti_init_vmlinux || st->kaiser_init_vmlinux) +- pgd = cr3 & ~(CR3_PCID_MASK|PTI_USER_PGTABLE_MASK); +- else +- pgd = cr3 & ~CR3_PCID_MASK; ++ for (cpu = 0; cpu < nr_cpus; cpu++) { ++ if (!get_cr3_idtr(cpu, &cr3, &idtr)) ++ continue; + +- /* +- * Set up for kvtop. +- * +- * calc_kaslr_offset() is called before machdep_init(PRE_GDB), so some +- * variables are not initialized yet. Set up them here to call kvtop(). +- * +- * TODO: XEN and 5-level is not supported +- */ +- vt->kernel_pgd[0] = pgd; +- machdep->last_pgd_read = vt->kernel_pgd[0]; +- machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_2_6; +- 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)) { +- if (SADUMP_DUMPFILE()) +- goto retry; +- else +- goto quit; +- } ++ if (!cr3) ++ continue; + +- /* Convert virtual address of IDT table to physical address */ +- if (!kvtop(NULL, idtr, &idtr_paddr, verbose)) { +- if (SADUMP_DUMPFILE()) +- goto retry; ++ if (st->pti_init_vmlinux || st->kaiser_init_vmlinux) ++ pgd = cr3 & ~(CR3_PCID_MASK|PTI_USER_PGTABLE_MASK); + else +- goto quit; +- } ++ pgd = cr3 & ~CR3_PCID_MASK; ++ ++ /* ++ * Set up for kvtop. ++ * ++ * calc_kaslr_offset() is called before machdep_init(PRE_GDB), so some ++ * variables are not initialized yet. Set up them here to call kvtop(). ++ * ++ * TODO: XEN and 5-level is not supported ++ */ ++ vt->kernel_pgd[0] = pgd; ++ machdep->last_pgd_read = vt->kernel_pgd[0]; ++ machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_2_6; ++ 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)) ++ continue; + +- /* 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); +- +- 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 (!calc_kaslr_offset_from_idt(idtr, pgd, &kaslr_offset, &phys_base)) ++ continue; + +- if (CRASHDEBUG(1)) { +- fprintf(fp, "calc_kaslr_offset: idtr=%lx\n", idtr); +- fprintf(fp, "calc_kaslr_offset: pgd=%lx\n", pgd); +- fprintf(fp, "calc_kaslr_offset: idtr(phys)=%lx\n", idtr_paddr); +- fprintf(fp, "calc_kaslr_offset: divide_error(vmlinux): %lx\n", +- st->divide_error_vmlinux); +- fprintf(fp, "calc_kaslr_offset: divide_error(vmcore): %lx\n", +- divide_error_vmcore); ++ if (verify_kaslr_offset(kaslr_offset)) ++ goto found; + } + ++ vt->kernel_pgd[0] = 0; ++ machdep->last_pgd_read = 0; ++ return FALSE; ++ ++found: + /* + * Check if current kaslr_offset/phys_base is for 1st kernel or 2nd + * kernel. If we are in 2nd kernel, get kaslr_offset/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; ++ if (get_kaslr_offset_from_vmcoreinfo(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"); +@@ -514,11 +560,9 @@ calc_kaslr_offset(ulong *ko, ulong *pb) + *ko = kaslr_offset; + *pb = phys_base; + +- ret = TRUE; +-quit: + vt->kernel_pgd[0] = 0; + machdep->last_pgd_read = 0; +- return ret; ++ return TRUE; + } + #else + int +diff --git a/netdump.c b/netdump.c +index 2ca39e2..c76d9dd 100644 +--- a/netdump.c ++++ b/netdump.c +@@ -5197,6 +5197,12 @@ kdump_kaslr_check(void) + } + + #ifdef X86_64 ++int ++kdump_get_nr_cpus(void) ++{ ++ return nd->num_qemu_notes; ++} ++ + QEMUCPUState * + kdump_get_qemucpustate(int cpu) + { +diff --git a/sadump.c b/sadump.c +index f313528..08893c4 100644 +--- a/sadump.c ++++ b/sadump.c +@@ -1671,44 +1671,20 @@ get_sadump_data(void) + } + + #ifdef X86_64 +-static int +-get_sadump_smram_cpu_state_any(struct sadump_smram_cpu_state *smram) ++int ++sadump_get_nr_cpus(void) + { +- 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; ++ /* apicids */ ++ return sd->dump_header->nr_cpus; + } + + int +-sadump_get_cr3_idtr(ulong *cr3, ulong *idtr) ++sadump_get_cr3_idtr(int cpu, ulong *cr3, ulong *idtr) + { + struct sadump_smram_cpu_state scs; + + memset(&scs, 0, sizeof(scs)); +- if (!get_sadump_smram_cpu_state_any(&scs)) ++ if (!sadump_get_smram_cpu_state(cpu, &scs)) + return FALSE; + + *cr3 = scs.Cr3; +diff --git a/vmware_vmss.c b/vmware_vmss.c +index b168f29..952ac48 100644 +--- a/vmware_vmss.c ++++ b/vmware_vmss.c +@@ -873,13 +873,19 @@ vmware_vmss_valid_regs(struct bt_info *bt) + } + + int +-vmware_vmss_get_cr3_idtr(ulong *cr3, ulong *idtr) ++vmware_vmss_get_nr_cpus(void) + { +- if (vmss.num_vcpus == 0 || vmss.vcpu_regs[0] != REGS_PRESENT_ALL) ++ return vmss.num_vcpus; ++} ++ ++int ++vmware_vmss_get_cr3_idtr(int cpu, ulong *cr3, ulong *idtr) ++{ ++ if (cpu >= vmss.num_vcpus || vmss.vcpu_regs[cpu] != REGS_PRESENT_ALL) + return FALSE; + +- *cr3 = vmss.regs64[0]->cr[3]; +- *idtr = vmss.regs64[0]->idtr; ++ *cr3 = vmss.regs64[cpu]->cr[3]; ++ *idtr = vmss.regs64[cpu]->idtr; + + return TRUE; + } diff --git a/crash.spec b/crash.spec index 56316c6dece61d96031646f64f15d49dbe86fa60..25692521f99d87ca903d442d9f7a425c35034ac4 100644 --- a/crash.spec +++ b/crash.spec @@ -1,6 +1,6 @@ Name: crash Version: 7.2.8 -Release: 3 +Release: 4 Summary: Linux kernel crash utility. License: GPLv3 URL: http://people.redhat.com/anderson @@ -11,6 +11,9 @@ Patch1: use_system_readline_v3.patch Patch9000: add-SDEI-stack-resolution.patch Patch9001: fix-bitmap_len-calculation-overflow-problem-in-large.patch +Patch9002: 7ccdda4ab2384f7e0251308e7b8d090e1e8a091b.patch +Patch9003: 40b93af74b51e6a322a9b70cabe7e0618973de22.patch +Patch9004: f82c150a8422f4b5506ac52d1dc62fa31a86e37f.patch BuildRequires: ncurses-devel zlib-devel lzo-devel snappy-devel BuildRequires: gcc gcc-c++ bison readline-devel @@ -75,6 +78,9 @@ install -D -m 0644 defs.h %{buildroot}%{_includedir}/%{name}/defs.h %{_mandir}/man8/crash.8* %changelog +* 20201112103007620873 patch-tracking 7.2.8-4 +- append patch file of upstream repository from <7ccdda4ab2384f7e0251308e7b8d090e1e8a091b> to + * Tue Sep 8 2020 shixuantong - 7.2.8-3 - Restore Source0 and URL @@ -91,4 +97,4 @@ install -D -m 0644 defs.h %{buildroot}%{_includedir}/%{name}/defs.h - Package rebuild. * Fri Aug 30 2019 openEuler Buildteam - 7.2.6-1 -- Package init. +- Package init. \ No newline at end of file diff --git a/f82c150a8422f4b5506ac52d1dc62fa31a86e37f.patch b/f82c150a8422f4b5506ac52d1dc62fa31a86e37f.patch new file mode 100644 index 0000000000000000000000000000000000000000..45addae98d92755edbcddfa9869443a6ef0d4b2b --- /dev/null +++ b/f82c150a8422f4b5506ac52d1dc62fa31a86e37f.patch @@ -0,0 +1,190 @@ +diff --git a/kaslr_helper.c b/kaslr_helper.c +index d92ea0f..b0483ab 100644 +--- a/kaslr_helper.c ++++ b/kaslr_helper.c +@@ -378,6 +378,152 @@ verify_kaslr_offset(ulong kaslr_offset) + return TRUE; + } + ++/* ++ * Find virtual (VA) and physical (PA) addresses of kernel start ++ * ++ * va: ++ * Actual address of the kernel start (_stext) placed ++ * randomly by kaslr feature. To be more accurate, ++ * VA = _stext(from vmlinux) + kaslr_offset ++ * ++ * pa: ++ * Physical address where the kerenel is placed. ++ * ++ * In nokaslr case, VA = _stext (from vmlinux) ++ * In kaslr case, virtual address of the kernel placement goes ++ * in this range: ffffffff80000000..ffffffff9fffffff, or ++ * __START_KERNEL_map..+512MB ++ * ++ * https://www.kernel.org/doc/Documentation/x86/x86_64/mm.txt ++ * ++ * Randomized VA will be the first valid page starting from ++ * ffffffff80000000 (__START_KERNEL_map). Page tree entry of ++ * this page will contain the PA of the kernel start. ++ */ ++static int ++find_kernel_start(uint64_t pgd, ulong *va, ulong *pa) ++{ ++ int pgd_idx, p4d_idx, pud_idx, pmd_idx, pte_idx; ++ uint64_t pgd_pte = 0, pud_pte, pmd_pte, pte; ++ ++ pgd_idx = pgd_index(__START_KERNEL_map); ++ if (machdep->flags & VM_5LEVEL) ++ p4d_idx = p4d_index(__START_KERNEL_map); ++ pud_idx = pud_index(__START_KERNEL_map); ++ pmd_idx = pmd_index(__START_KERNEL_map); ++ pte_idx = pte_index(__START_KERNEL_map); ++ ++ /* If the VM is in 5-level page table */ ++ if (machdep->flags & VM_5LEVEL) ++ *va = ~((1UL << 57) - 1); ++ else ++ *va = ~__VIRTUAL_MASK; ++ ++ FILL_PGD(pgd & PHYSICAL_PAGE_MASK, PHYSADDR, PAGESIZE()); ++ for (; pgd_idx < PTRS_PER_PGD; pgd_idx++) { ++ pgd_pte = ULONG(machdep->pgd + pgd_idx * sizeof(uint64_t)); ++ if (pgd_pte & _PAGE_PRESENT) ++ break; ++ p4d_idx = pud_idx = pmd_idx = pte_idx = 0; ++ } ++ if (pgd_idx == PTRS_PER_PGD) ++ return FALSE; ++ *va |= (ulong)pgd_idx << __PGDIR_SHIFT; ++ ++ if (machdep->flags & VM_5LEVEL) { ++ FILL_P4D(pgd_pte & PHYSICAL_PAGE_MASK, PHYSADDR, PAGESIZE()); ++ for (; p4d_idx < PTRS_PER_P4D; p4d_idx++) { ++ /* reuse pgd_pte */ ++ pgd_pte = ULONG(machdep->machspec->p4d + p4d_idx * sizeof(uint64_t)); ++ if (pgd_pte & _PAGE_PRESENT) ++ break; ++ pud_idx = pmd_idx = pte_idx = 0; ++ } ++ if (p4d_idx == PTRS_PER_P4D) ++ return FALSE; ++ *va |= (ulong)p4d_idx << P4D_SHIFT; ++ } ++ ++ FILL_PUD(pgd_pte & PHYSICAL_PAGE_MASK, PHYSADDR, PAGESIZE()); ++ for (; pud_idx < PTRS_PER_PUD; pud_idx++) { ++ pud_pte = ULONG(machdep->pud + pud_idx * sizeof(uint64_t)); ++ if (pud_pte & _PAGE_PRESENT) ++ break; ++ pmd_idx = pte_idx = 0; ++ } ++ if (pud_idx == PTRS_PER_PUD) ++ return FALSE; ++ *va |= (ulong)pud_idx << PUD_SHIFT; ++ if (pud_pte & _PAGE_PSE) { ++ /* 1GB page */ ++ *pa = pud_pte & PHYSICAL_PAGE_MASK; ++ return TRUE; ++ } ++ ++ FILL_PMD(pud_pte & PHYSICAL_PAGE_MASK, PHYSADDR, PAGESIZE()); ++ for (; pmd_idx < PTRS_PER_PMD; pmd_idx++) { ++ pmd_pte = ULONG(machdep->pmd + pmd_idx * sizeof(uint64_t)); ++ if (pmd_pte & _PAGE_PRESENT) ++ break; ++ pte_idx = 0; ++ } ++ if (pmd_idx == PTRS_PER_PMD) ++ return FALSE; ++ *va |= pmd_idx << PMD_SHIFT; ++ if (pmd_pte & _PAGE_PSE) { ++ /* 2MB page */ ++ *pa = pmd_pte & PHYSICAL_PAGE_MASK; ++ return TRUE; ++ } ++ ++ FILL_PTBL(pmd_pte & PHYSICAL_PAGE_MASK, PHYSADDR, PAGESIZE()); ++ for (; pte_idx < PTRS_PER_PTE; pte_idx++) { ++ pte = ULONG(machdep->ptbl + pte_idx * sizeof(uint64_t)); ++ if (pte & _PAGE_PRESENT) ++ break; ++ } ++ if (pte_idx == PTRS_PER_PTE) ++ return FALSE; ++ ++ *va |= pte_idx << PAGE_SHIFT; ++ *pa = pmd_pte & PHYSICAL_PAGE_MASK; ++ return TRUE; ++} ++ ++/* ++ * Page Tables based method to calculate kaslr_offset and phys_base. ++ * It uses VA and PA of kernel start. ++ * ++ * kaslr offset and phys_base are calculated as follows: ++ * ++ * kaslr_offset = VA - st->_stext_vmlinux ++ * phys_base = PA - (VA - __START_KERNEL_map) ++ */ ++static int ++calc_kaslr_offset_from_page_tables(uint64_t pgd, ulong *kaslr_offset, ++ ulong *phys_base) ++{ ++ ulong va, pa; ++ ++ if (!st->_stext_vmlinux || st->_stext_vmlinux == UNINITIALIZED) { ++ fprintf(fp, "%s: st->_stext_vmlinux must be initialized\n", ++ __FUNCTION__); ++ return FALSE; ++ } ++ if (!find_kernel_start(pgd, &va, &pa)) ++ return FALSE; ++ ++ if (CRASHDEBUG(1)) { ++ fprintf(fp, "calc_kaslr_offset: _stext(vmlinux): %lx\n", st->_stext_vmlinux); ++ fprintf(fp, "calc_kaslr_offset: kernel start VA: %lx\n", va); ++ fprintf(fp, "calc_kaslr_offset: kernel start PA: %lx\n", pa); ++ } ++ ++ *kaslr_offset = va - st->_stext_vmlinux; ++ *phys_base = pa - (va - __START_KERNEL_map); ++ return TRUE; ++} ++ + /* + * IDT based method to calculate kaslr_offset and phys_base + * +@@ -537,8 +683,13 @@ calc_kaslr_offset(ulong *ko, ulong *pb) + "pgd", RETURN_ON_ERROR)) + continue; + +- if (!calc_kaslr_offset_from_idt(idtr, pgd, &kaslr_offset, &phys_base)) +- continue; ++ if (!calc_kaslr_offset_from_page_tables(pgd, &kaslr_offset, ++ &phys_base)) { ++ if (!calc_kaslr_offset_from_idt(idtr, pgd, ++ &kaslr_offset, ++ &phys_base)) ++ continue; ++ } + + if (verify_kaslr_offset(kaslr_offset)) + goto found; +diff --git a/symbols.c b/symbols.c +index 70b1455..08e9995 100644 +--- a/symbols.c ++++ b/symbols.c +@@ -634,8 +634,11 @@ kaslr_init(void) + } + } + +- if (SADUMP_DUMPFILE() || VMSS_DUMPFILE()) ++ if (SADUMP_DUMPFILE() || QEMU_MEM_DUMP_NO_VMCOREINFO() || VMSS_DUMPFILE()) { ++ /* Need for kaslr_offset and phys_base */ + kt->flags2 |= KASLR_CHECK; ++ st->_stext_vmlinux = UNINITIALIZED; ++ } + } + + /*