----- Original Message ----- > This value is used to mask the PAC bits and generate correct backtrace > and symbol name. > (amit.kachhap@xxxxxxx) > --- > Changes since v1: > * Moved PAC mask code from arm64_print_stackframe_entry to > arm64_unwind_frame. > * PAC mask check on all kernel text during complete stack parsing > with bt -t <pid> command. > * dump_machdep_table now prints CONFIG_ARM64_KERNELPACMASK. > > The kernel version for the corresponding vmcoreinfo entry is posted here[1]. > > [1]: https://lore.kernel.org/patchwork/patch/1211981/ Hi Amit, I'm still a bit confused here -- please help me out... For the lack of a better term, in the following discussion, I'm going to refer to the text values without the KERNELPACMASK applied as "obfuscated". Now, as I understand it, when a running function calls another function and leaves its text return address on the stack, the processor obfuscates the text return value before it pushes it on the stack. But here's where I'm confused: when an in-kernel exception frame occurs, and the processor lays down the full register set on the stack, are both the PC and LR (regs[30]) text values written on the stack as obfuscated values? Here's why I'm asking... When looking for the starting stack hooks in a dumpfile, your patch takes the PC from the in-kernel exception frame unmodified: static int arm64_get_dumpfile_stackframe(struct bt_info *bt, struct arm64_stackframe *frame) { struct machine_specific *ms = machdep->machspec; struct arm64_pt_regs *ptregs; if (!ms->panic_task_regs || (!ms->panic_task_regs[bt->tc->processor].sp && !ms->panic_task_regs[bt->tc->processor].pc)) { bt->flags |= BT_REGS_NOT_FOUND; return FALSE; } ptregs = &ms->panic_task_regs[bt->tc->processor]; =======> frame->pc = ptregs->pc; ... That PC value comes from an exception frame. Will that ptregs->pc value be obfuscated? When it gathers the starting hooks for non-active tasks, it does this: static int arm64_get_stackframe(struct bt_info *bt, struct arm64_stackframe *frame) { if (!fill_task_struct(bt->task)) return FALSE; frame->sp = ULONG(tt->task_struct + OFFSET(task_struct_thread_context_sp)); frame->pc = ULONG(tt->task_struct + OFFSET(task_struct_thread_context_pc)); frame->fp = ULONG(tt->task_struct + OFFSET(task_struct_thread_context_fp)); return TRUE; } When a task is put to sleep, is the PC text address in the task's thread_struct.cpu_context obfuscated? And then when trying to determine whether the current stack pointer is pointing to an in-kernel exception frame, the possible regs->pc and regs[30] values are both transformed with the mask, so it seems that both of them will have been obfuscated by the processor when creating the frame on the stack: static int arm64_is_kernel_exception_frame(struct bt_info *bt, ulong stkptr) { struct arm64_pt_regs *regs; struct machine_specific *ms = machdep->machspec; regs = (struct arm64_pt_regs *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(stkptr))]; if (INSTACK(regs->sp, bt) && INSTACK(regs->regs[29], bt) && !(regs->pstate & (0xffffffff00000000ULL | PSR_MODE32_BIT)) && ========> is_kernel_text(regs->pc | ms->CONFIG_ARM64_KERNELPACMASK) && ========> is_kernel_text(regs->regs[30] | ms->CONFIG_ARM64_KERNELPACMASK)) { switch (regs->pstate & PSR_MODE_MASK) { case PSR_MODE_EL1t: case PSR_MODE_EL1h: case PSR_MODE_EL2t: case PSR_MODE_EL2h: return TRUE; } } return FALSE; } But here when when displaying an exception frame, the LR is masked if it "make sense", but the unmodified PC value is checked without transforming it: static void arm64_print_exception_frame(struct bt_info *bt, ulong pt_regs, int mode, FILE *ofp) { ... LR = regs->regs[30]; =======> if (is_kernel_text (LR | ms->CONFIG_ARM64_KERNELPACMASK)) LR |= ms->CONFIG_ARM64_KERNELPACMASK; ... case KERNEL_MODE: fprintf(ofp, " PC: %016lx ", (ulong)regs->pc); =======> if (is_kernel_text(regs->pc) && (sp = value_search(regs->pc, &offset))) { fprintf(ofp, "[%s", sp->name); if (offset) fprintf(ofp, (*gdb_output_radix == 16) ? "+0x%lx" : "+%ld", offset); fprintf(ofp, "]\n"); } else fprintf(ofp, "[unknown or invalid address]\n"); fprintf(ofp, " LR: %016lx ", LR); =======> if (is_kernel_text(LR) && (sp = value_search(LR, &offset))) { fprintf(ofp, "[%s", sp->name); if (offset) fprintf(ofp, (*gdb_output_radix == 16) ? "+0x%lx" : "+%ld", offset); fprintf(ofp, "]\n"); } else fprintf(ofp, "[unknown or invalid address]\n"); So that would lead me to believe that the exception frame PC is in NOT obfuscated. Hence my confusion... Thanks, Dave > > arm64.c | 52 ++++++++++++++++++++++++++++++++++++++++++---------- > defs.h | 1 + > 2 files changed, 43 insertions(+), 10 deletions(-) > > diff --git a/arm64.c b/arm64.c > index 7662d71..326b8e0 100644 > --- a/arm64.c > +++ b/arm64.c > @@ -84,6 +84,7 @@ static int arm64_get_kvaddr_ranges(struct vaddr_range *); > static void arm64_get_crash_notes(void); > static void arm64_calc_VA_BITS(void); > static int arm64_is_uvaddr(ulong, struct task_context *); > +static void arm64_calc_KERNELPACMASK(void); > > > /* > @@ -213,6 +214,7 @@ arm64_init(int when) > machdep->pagemask = ~((ulonglong)machdep->pageoffset); > > arm64_calc_VA_BITS(); > + arm64_calc_KERNELPACMASK(); > ms = machdep->machspec; > if (ms->VA_BITS_ACTUAL) { > ms->page_offset = ARM64_PAGE_OFFSET_ACTUAL; > @@ -472,6 +474,7 @@ arm64_init(int when) > case LOG_ONLY: > machdep->machspec = &arm64_machine_specific; > arm64_calc_VA_BITS(); > + arm64_calc_KERNELPACMASK(); > arm64_calc_phys_offset(); > machdep->machspec->page_offset = ARM64_PAGE_OFFSET; > break; > @@ -659,6 +662,11 @@ arm64_dump_machdep_table(ulong arg) > fprintf(fp, "%ld\n", ms->VA_BITS_ACTUAL); > else > fprintf(fp, "(unused)\n"); > + fprintf(fp, "CONFIG_ARM64_KERNELPACMASK: "); > + if (ms->CONFIG_ARM64_KERNELPACMASK) > + fprintf(fp, "%lx\n", ms->CONFIG_ARM64_KERNELPACMASK); > + else > + fprintf(fp, "(unused)\n"); > fprintf(fp, " userspace_top: %016lx\n", ms->userspace_top); > fprintf(fp, " page_offset: %016lx\n", ms->page_offset); > fprintf(fp, " vmalloc_start_addr: %016lx\n", ms->vmalloc_start_addr); > @@ -1774,13 +1782,14 @@ static int > arm64_is_kernel_exception_frame(struct bt_info *bt, ulong stkptr) > { > struct arm64_pt_regs *regs; > + struct machine_specific *ms = machdep->machspec; > > regs = (struct arm64_pt_regs > *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(stkptr))]; > > if (INSTACK(regs->sp, bt) && INSTACK(regs->regs[29], bt) && > !(regs->pstate & (0xffffffff00000000ULL | PSR_MODE32_BIT)) && > - is_kernel_text(regs->pc) && > - is_kernel_text(regs->regs[30])) { > + is_kernel_text(regs->pc | ms->CONFIG_ARM64_KERNELPACMASK) && > + is_kernel_text(regs->regs[30] | ms->CONFIG_ARM64_KERNELPACMASK)) { > switch (regs->pstate & PSR_MODE_MASK) > { > case PSR_MODE_EL1t: > @@ -1924,6 +1933,7 @@ arm64_print_stackframe_entry(struct bt_info *bt, int > level, struct arm64_stackfr > * See, for example, "bl schedule" before ret_to_user(). > */ > branch_pc = frame->pc - 4; > + > name = closest_symbol(branch_pc); > name_plus_offset = NULL; > > @@ -2135,7 +2145,7 @@ arm64_unwind_frame(struct bt_info *bt, struct > arm64_stackframe *frame) > unsigned long stack_mask; > unsigned long irq_stack_ptr, orig_sp; > struct arm64_pt_regs *ptregs; > - struct machine_specific *ms; > + struct machine_specific *ms = machdep->machspec; > > stack_mask = (unsigned long)(ARM64_STACK_SIZE) - 1; > fp = frame->fp; > @@ -2149,6 +2159,8 @@ arm64_unwind_frame(struct bt_info *bt, struct > arm64_stackframe *frame) > frame->sp = fp + 0x10; > frame->fp = GET_STACK_ULONG(fp); > frame->pc = GET_STACK_ULONG(fp + 8); > + if (is_kernel_text(frame->pc | ms->CONFIG_ARM64_KERNELPACMASK)) > + frame->pc |= ms->CONFIG_ARM64_KERNELPACMASK; > > if ((frame->fp == 0) && (frame->pc == 0)) > return FALSE; > @@ -2200,7 +2212,6 @@ arm64_unwind_frame(struct bt_info *bt, struct > arm64_stackframe *frame) > * irq_stack_ptr = IRQ_STACK_PTR(raw_smp_processor_id()); > * orig_sp = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr); (pt_regs pointer on > process stack) > */ > - ms = machdep->machspec; > irq_stack_ptr = ms->irq_stacks[bt->tc->processor] + ms->irq_stack_size - > 16; > > if (frame->sp == irq_stack_ptr) { > @@ -2802,6 +2813,8 @@ arm64_print_text_symbols(struct bt_info *bt, struct > arm64_stackframe *frame, FIL > char buf2[BUFSIZE]; > char *name; > ulong start; > + ulong val; > + struct machine_specific *ms = machdep->machspec; > > if (bt->flags & BT_TEXT_SYMBOLS_ALL) > start = bt->stackbase; > @@ -2816,8 +2829,10 @@ arm64_print_text_symbols(struct bt_info *bt, struct > arm64_stackframe *frame, FIL > > for (i = (start - bt->stackbase)/sizeof(ulong); i < LONGS_PER_STACK; i++) { > up = (ulong *)(&bt->stackbuf[i*sizeof(ulong)]); > - if (is_kernel_text(*up)) { > - name = closest_symbol(*up); > + val = *up; > + if (is_kernel_text(val | ms->CONFIG_ARM64_KERNELPACMASK)) { > + val |= ms->CONFIG_ARM64_KERNELPACMASK; > + name = closest_symbol(val); > fprintf(ofp, " %s[%s] %s at %lx", > bt->flags & BT_ERROR_MASK ? > " " : "", > @@ -2826,13 +2841,13 @@ arm64_print_text_symbols(struct bt_info *bt, struct > arm64_stackframe *frame, FIL > MKSTR(bt->stackbase + > (i * sizeof(long)))), > bt->flags & BT_SYMBOL_OFFSET ? > - value_to_symstr(*up, buf2, bt->radix) : > - name, *up); > - if (module_symbol(*up, NULL, &lm, NULL, 0)) > + value_to_symstr(val, buf2, bt->radix) : > + name, val); > + if (module_symbol(val, NULL, &lm, NULL, 0)) > fprintf(ofp, " [%s]", lm->mod_name); > fprintf(ofp, "\n"); > if (BT_REFERENCE_CHECK(bt)) > - arm64_do_bt_reference_check(bt, *up, name); > + arm64_do_bt_reference_check(bt, val, name); > } > } > } > @@ -3135,6 +3150,7 @@ arm64_print_exception_frame(struct bt_info *bt, ulong > pt_regs, int mode, FILE *o > struct syment *sp; > ulong LR, SP, offset; > char buf[BUFSIZE]; > + struct machine_specific *ms = machdep->machspec; > > if (CRASHDEBUG(1)) > fprintf(ofp, "pt_regs: %lx\n", pt_regs); > @@ -3150,6 +3166,8 @@ arm64_print_exception_frame(struct bt_info *bt, ulong > pt_regs, int mode, FILE *o > rows = 4; > } else { > LR = regs->regs[30]; > + if (is_kernel_text (LR | ms->CONFIG_ARM64_KERNELPACMASK)) > + LR |= ms->CONFIG_ARM64_KERNELPACMASK; > SP = regs->sp; > top_reg = 29; > is_64_bit = TRUE; > @@ -4058,6 +4076,20 @@ arm64_swp_offset(ulong pte) > return pte; > } > > +static void arm64_calc_KERNELPACMASK(void) > +{ > + ulong value; > + char *string; > + > + if ((string = pc->read_vmcoreinfo("NUMBER(KERNELPACMASK)"))) { > + value = htol(string, QUIET, NULL); > + free(string); > + machdep->machspec->CONFIG_ARM64_KERNELPACMASK = value; > + if (CRASHDEBUG(1)) > + fprintf(fp, "CONFIG_ARM64_KERNELPACMASK=%lx\n", value); > + } > +} > + > #endif /* ARM64 */ > > > diff --git a/defs.h b/defs.h > index ac24a5d..4c3e509 100644 > --- a/defs.h > +++ b/defs.h > @@ -3263,6 +3263,7 @@ struct machine_specific { > ulong machine_kexec_end; > ulong VA_BITS_ACTUAL; > ulong CONFIG_ARM64_VA_BITS; > + ulong CONFIG_ARM64_KERNELPACMASK; > ulong VA_START; > }; > > -- > 2.17.1 > > -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility