commit 1e488cfefa1d9ca4ca626bc2a308b39f7404f5db Author: Dave Anderson Date: Tue Jan 23 16:35:41 2018 -0500 Fix for the "bt" command and the "ps -s" option for zombie tasks whose kernel stacks have been freed/detached. Without the patch, the "bt" command indicates "bt: invalid kernel virtual address: 0 type: stack contents" and "bt: read of stack at 0 failed"; it will be changed to display "(no stack)". The "ps -s" option would fail prematurely upon reaching such a task, indicating "ps: invalid kernel virtual address: 0 type: stack contents" and "ps: read of stack at 0 failed". (anderson@redhat.com) diff --git a/kernel.c b/kernel.c index 4638495..1bf6251 100644 --- a/kernel.c +++ b/kernel.c @@ -1,8 +1,8 @@ /* kernel.c - core analysis suite * * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. - * Copyright (C) 2002-2017 David Anderson - * Copyright (C) 2002-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2002-2018 David Anderson + * Copyright (C) 2002-2018 Red Hat, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -2890,6 +2890,11 @@ back_trace(struct bt_info *bt) return; } + if (bt->stackbase == 0) { + fprintf(fp, "(no stack)\n"); + return; + } + fill_stackbuf(bt); if (CRASHDEBUG(4)) { diff --git a/task.c b/task.c index b303ef7..db05ab4 100644 --- a/task.c +++ b/task.c @@ -1,8 +1,8 @@ /* task.c - core analysis suite * * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. - * Copyright (C) 2002-2017 David Anderson - * Copyright (C) 2002-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2002-2018 David Anderson + * Copyright (C) 2002-2018 Red Hat, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -4182,12 +4182,14 @@ task_pointer_string(struct task_context *tc, ulong do_kstackp, char *buf) KVADDR, &bt->stkptr, sizeof(void *), "thread_struct ksp", FAULT_ON_ERROR); } else { - bt->task = tc->task; - bt->tc = tc; - bt->stackbase = GET_STACKBASE(tc->task); - bt->stacktop = GET_STACKTOP(tc->task); - bt->flags |= BT_KSTACKP; - back_trace(bt); + if ((bt->stackbase = GET_STACKBASE(tc->task))) { + bt->stacktop = GET_STACKTOP(tc->task); + bt->task = tc->task; + bt->tc = tc; + bt->flags |= BT_KSTACKP; + back_trace(bt); + } else + bt->stkptr = 0; } if (bt->stkptr) commit 693e0fa8ea8b2791329a4197fafd8700afa14c3b Author: Dave Anderson Date: Thu Jan 25 14:52:54 2018 -0500 Fix for running on live systems on 4.15-rc2 and later kernels that are configured with CONFIG_RANDOMIZE_BASE and contain kernel commit 668533dc0764b30c9dd2baf3ca800156f688326b, titled "kallsyms: take advantage of the new '%px' format". Without the patch, a live crash session does not show the "WARNING: kernel relocated ..." message expected with KASLR, and then displays the message "crash: cannot set context for pid: " prior to generating a SIGSEGV. (anderson@redhat.com) diff --git a/symbols.c b/symbols.c index 2372887..9a3763c 100644 --- a/symbols.c +++ b/symbols.c @@ -1,8 +1,8 @@ /* symbols.c - core analysis suite * * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. - * Copyright (C) 2002-2017 David Anderson - * Copyright (C) 2002-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2002-2018 David Anderson + * Copyright (C) 2002-2018 Red Hat, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1004,10 +1004,9 @@ symbol_value_from_proc_kallsyms(char *symname) found = FALSE; while (!found && fgets(buf, BUFSIZE, kp) && - (parse_line(buf, kallsyms) == 3) && - hexadecimal(kallsyms[0], 0)) { - - if (STREQ(kallsyms[2], symname)) { + (parse_line(buf, kallsyms) == 3)) { + if (hexadecimal(kallsyms[0], 0) && + STREQ(kallsyms[2], symname)) { kallsym = htol(kallsyms[0], RETURN_ON_ERROR, NULL); found = TRUE; break; commit 1af7813e0552ac93b39a44abffffc04600d3ed4c Author: Dave Anderson Date: Thu Jan 25 15:17:26 2018 -0500 Fix for 4.15-rc5 and later x86_64 kernels that contain kernel commit c482feefe1aeb150156248ba0fd3e029bc886605, titled "x86/entry/64: Make cpu_entry_area.tss read-only". Without the patch, the addresses and sizes of the x86_64 exception stacks cannot be determined; therefore if a backtrace starts on one of the exception stacks, then the "bt" command will fail. (anderson@redhat.com) diff --git a/x86_64.c b/x86_64.c index e924ca9..467b5d7 100644 --- a/x86_64.c +++ b/x86_64.c @@ -1245,8 +1245,10 @@ x86_64_ist_init(void) struct syment *boot_sp, *tss_sp, *ist_sp; ms = machdep->machspec; - if (!(tss_sp = per_cpu_symbol_search("per_cpu__init_tss"))) - tss_sp = per_cpu_symbol_search("per_cpu__cpu_tss"); + if (!(tss_sp = per_cpu_symbol_search("per_cpu__init_tss"))) { + if (!(tss_sp = per_cpu_symbol_search("per_cpu__cpu_tss"))) + tss_sp = per_cpu_symbol_search("per_cpu__cpu_tss_rw"); + } ist_sp = per_cpu_symbol_search("per_cpu__orig_ist"); x86_64_exception_stacks_init(); commit 1160ba19884fed4420c334394cde7a40b113e09c Author: Dave Anderson Date: Fri Jan 26 11:06:48 2018 -0500 Additional fix for support of KASLR enabled kernels captured by the SADUMP dumpfile facility, where this patch fixes a problem when Page Table Isolation(PTI) is enabled. When PTI is enabled, bit 12 of CR3 register is used to split user space and kernel space. Also bit 11:0 is used for Process Context IDentifiers(PCID). To open an SADUMP dumpfile, the value of CR3 is used to calculate KASLR offset and phys_base; this patch masks the CR3 register value correctly for a PTI enabled kernel. (indou.takao@jp.fujitsu.com) diff --git a/defs.h b/defs.h index 4d2fb2f..92341d2 100644 --- a/defs.h +++ b/defs.h @@ -2605,6 +2605,8 @@ struct symbol_table_data { ulong divide_error_vmlinux; ulong idt_table_vmlinux; ulong saved_command_line_vmlinux; + ulong pti_init_vmlinux; + ulong kaiser_init_vmlinux; }; /* flags for st */ diff --git a/sadump.c b/sadump.c index 6b912d4..25cefe9 100644 --- a/sadump.c +++ b/sadump.c @@ -1749,7 +1749,7 @@ static ulong memparse(char *ptr, char **retptr) * of elfcorehdr. */ static ulong -get_elfcorehdr(ulong cr3, ulong kaslr_offset) +get_elfcorehdr(ulong kaslr_offset) { char cmdline[BUFSIZE], *ptr; ulong cmdline_vaddr; @@ -1906,7 +1906,7 @@ get_vmcoreinfo(ulong elfcorehdr, ulong *addr, int *len) * using "elfcorehdr=" and retrieve kaslr_offset/phys_base from vmcoreinfo. */ static int -get_kaslr_offset_from_vmcoreinfo(ulong cr3, ulong orig_kaslr_offset, +get_kaslr_offset_from_vmcoreinfo(ulong orig_kaslr_offset, ulong *kaslr_offset, ulong *phys_base) { ulong elfcorehdr_addr = 0; @@ -1916,7 +1916,7 @@ get_kaslr_offset_from_vmcoreinfo(ulong cr3, ulong orig_kaslr_offset, int ret = FALSE; /* Find "elfcorehdr=" in the kernel boot parameter */ - elfcorehdr_addr = get_elfcorehdr(cr3, orig_kaslr_offset); + elfcorehdr_addr = get_elfcorehdr(orig_kaslr_offset); if (!elfcorehdr_addr) return FALSE; @@ -1973,8 +1973,8 @@ quit: * 1) Get IDTR and CR3 value from the dump header. * 2) Get a virtual address of IDT from IDTR value * --- (A) - * 3) Translate (A) to physical address using CR3, which points a top of - * page table. + * 3) Translate (A) to physical address using CR3, the upper 52 bits + * of which points a top of page table. * --- (B) * 4) Get an address of vector0 (Devide Error) interrupt handler from * IDT, which are pointed by (B). @@ -2023,12 +2023,15 @@ quit: * kernel. Retrieve vmcoreinfo from address of "elfcorehdr=" and * get kaslr_offset and phys_base from vmcoreinfo. */ +#define PTI_USER_PGTABLE_BIT PAGE_SHIFT +#define PTI_USER_PGTABLE_MASK (1 << PTI_USER_PGTABLE_BIT) +#define CR3_PCID_MASK 0xFFFull int sadump_calc_kaslr_offset(ulong *kaslr_offset) { ulong phys_base = 0; struct sadump_smram_cpu_state scs; - uint64_t idtr = 0, cr3 = 0, idtr_paddr; + uint64_t idtr = 0, pgd = 0, idtr_paddr; ulong divide_error_vmcore; ulong kaslr_offset_kdump, phys_base_kdump; int ret = FALSE; @@ -2039,7 +2042,10 @@ sadump_calc_kaslr_offset(ulong *kaslr_offset) memset(&scs, 0, sizeof(scs)); get_sadump_smram_cpu_state_any(&scs); - cr3 = scs.Cr3; + if (st->pti_init_vmlinux || st->kaiser_init_vmlinux) + pgd = scs.Cr3 & ~(CR3_PCID_MASK|PTI_USER_PGTABLE_MASK); + else + pgd = scs.Cr3 & ~CR3_PCID_MASK; idtr = ((uint64_t)scs.IdtUpper)<<32 | (uint64_t)scs.IdtLower; /* @@ -2050,12 +2056,12 @@ sadump_calc_kaslr_offset(ulong *kaslr_offset) * * TODO: XEN and 5-level is not supported */ - vt->kernel_pgd[0] = cr3; + vt->kernel_pgd[0] = pgd; machdep->machspec->last_pml4_read = vt->kernel_pgd[0]; machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_2_6; machdep->machspec->pgdir_shift = PGDIR_SHIFT; - if (!readmem(cr3, PHYSADDR, machdep->machspec->pml4, PAGESIZE(), - "cr3", RETURN_ON_ERROR)) + if (!readmem(pgd, PHYSADDR, machdep->machspec->pml4, PAGESIZE(), + "pgd", RETURN_ON_ERROR)) goto quit; /* Convert virtual address of IDT table to physical address */ @@ -2070,7 +2076,7 @@ sadump_calc_kaslr_offset(ulong *kaslr_offset) if (CRASHDEBUG(1)) { fprintf(fp, "calc_kaslr_offset: idtr=%lx\n", idtr); - fprintf(fp, "calc_kaslr_offset: cr3=%lx\n", cr3); + 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); @@ -2084,9 +2090,12 @@ sadump_calc_kaslr_offset(ulong *kaslr_offset) * from vmcoreinfo */ if (get_kaslr_offset_from_vmcoreinfo( - cr3, *kaslr_offset, &kaslr_offset_kdump, &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, "sadump: failed to determine which kernel was running at crash,\n"); + fprintf(fp, "sadump: asssuming the kdump 1st kernel.\n"); } if (CRASHDEBUG(1)) { diff --git a/symbols.c b/symbols.c index 9a3763c..4db9af7 100644 --- a/symbols.c +++ b/symbols.c @@ -3071,10 +3071,14 @@ dump_symbol_table(void) fprintf(fp, "divide_error_vmlinux: %lx\n", st->divide_error_vmlinux); fprintf(fp, " idt_table_vmlinux: %lx\n", st->idt_table_vmlinux); fprintf(fp, "saved_command_line_vmlinux: %lx\n", st->saved_command_line_vmlinux); + fprintf(fp, " pti_init_vmlinux: %lx\n", st->pti_init_vmlinux); + fprintf(fp, " kaiser_init_vmlinux: %lx\n", st->kaiser_init_vmlinux); } else { fprintf(fp, "divide_error_vmlinux: (unused)\n"); fprintf(fp, " idt_table_vmlinux: (unused)\n"); fprintf(fp, "saved_command_line_vmlinux: (unused)\n"); + fprintf(fp, " pti_init_vmlinux: (unused)\n"); + fprintf(fp, " kaiser_init_vmlinux: (unused)\n"); } fprintf(fp, " symval_hash[%d]: %lx\n", SYMVAL_HASH, @@ -12305,6 +12309,11 @@ numeric_forward(const void *P_x, const void *P_y) 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);