----- Original Message -----
> Pointer authentication support is added in the recent versions of the arm64
> kernel. This basically add PAC bits to the top unused bits of the lr
> register in the stack to prevent ROP kind of attack.
>
> However the presence of PAC bits fails to match with the correct symbol
> name. Hence a KERNELPACMASK field is added in the vmcoreinfo to help
> in masking out this PAC details.
>
> This patch fetches the KERNELPACMASK info and use it to mask the PAC bits
> and generate correct backtrace and symbol name.
> (amit.kach...@arm.com)
Queued for crash-7.2.9:
https://github.com/crash-utility/crash/commit/41d61189d60e0fdd6509b96dc8160795263f3229
Thanks,
Dave
> ---
>
> Changes sice v2:
> * Removed PAC mask check from arm64_is_kernel_exception_frame function
> * More details in commit.
>
> 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/
>
>
> arm64.c | 50 +++++++++++++++++++++++++++++++++++++++++---------
> defs.h | 1 +
> 2 files changed, 42 insertions(+), 9 deletions(-)
>
> diff --git a/arm64.c b/arm64.c
> index 7662d71..e0a5cf2 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->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);Prepare for the introduction of
> ARM64 8.3 Pointer Authentication
as in-kernel feature. The value of CONFIG_ARM64_KERNELPACMASK
will be exported as a vmcoreinfo entry, and will be used with text
return addresses on the kernel stack.
(amit.kach...@arm.com)
> + 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@redhat.com
https://www.redhat.com/mailman/listinfo/crash-utility