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

Amit Daniel Kachhap amit.kachhap at arm.com
Tue Apr 21 05:14:30 UTC 2020


This value is used to mask the PAC bits and generate correct backtrace
and symbol name.
(amit.kachhap at arm.com)
---
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 | 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





More information about the Crash-utility mailing list