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);