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

2020-04-22 Thread Dave Anderson
Hi Amit,

Two more questions below...

- Original Message -

> > 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?
> > 
> 
> In arm64 case arch/arm64/include/asm/kexec.h + crash_setup_regs()
> function sets up the kernel exception frame. As can be seen PC does not
> have obfuscated (PAC) values but LR can be obfuscated.

Ok, so that's when it's setting up the registers for a kexec/kdump operation.

But what about exceptions that occur during the normal course of events, such as
when an interrupt or page fault occurs?

> > ...
> >
> > 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)crash_setup_regs
> >{
> >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 again, what happens in this case?

Thanks,
  Dave

--
Crash-utility mailing list
Crash-utility@redhat.com
https://www.redhat.com/mailman/listinfo/crash-utility



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

2020-04-22 Thread Amit Kachhap



Hi Dave,
On 4/22/20 1:55 AM, Dave Anderson wrote:


- Original Message -

This value is used to mask the PAC bits and generate correct backtrace
and symbol name.
(amit.kach...@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  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".

ok


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.


yes correct.



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?



In arm64 case arch/arm64/include/asm/kexec.h + crash_setup_regs() 
function sets up the kernel exception frame. As can be seen PC does not 
have obfuscated (PAC) values but LR can be obfuscated.



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 = >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?


I suppose no.



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 *)>stackbuf[(ulong)(STACK_OFFSET_TYPE(stkptr))];
   
   if (INSTACK(regs->sp, bt) && INSTACK(regs->regs[29], bt) &&

   !(regs->pstate & (0xULL | PSR_MODE32_BIT)) &&
> is_kernel_text(regs->pc | ms->CONFIG_ARM64_KERNELPACMASK) &&


Yes good catch. Masking can be removed from here.


> 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, ))) {
   fprintf(ofp, "[%s", sp->name);