[Crash-utility] [PATCH v3] Determine the ARM64 kernel's Pointer Authentication mask value by reading the new KERNELPACMASK vmcoreinfo entry.

Dave Anderson anderson at redhat.com
Fri Apr 24 17:18:45 UTC 2020



----- 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.kachhap at 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.kachhap at 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
> 
> 




More information about the Crash-utility mailing list