ntdll: Handle aarch64 pointer authentication in unwind info.

These were docmented in [1] (with the user-facing name of the opcode
adjusted later in [2]).

Since MSVC 2022, the precompiled runtimes (both runtimes such as
vcruntime140*.dll and the statically linked code from e.g. libcmt.lib)
are built with pointer authentication enabled.

To correctly handle unwinding through such functions, even on HW that
don't support the pointer authentication mechanism itself, wine needs
to at least be aware of it (for handling the cases with packed unwind
info with CR==2 simiarly to CR==3).

This patch has been tested on Linux on HW supporting pointer
authentication too, with binaries built with MSVC.

[1] f510c83085
[2] cac237d3f3
This commit is contained in:
Martin Storsjö 2023-03-03 11:45:34 +02:00 committed by Alexandre Julliard
parent 26163c10bb
commit 7f7f06fe61

View file

@ -690,6 +690,20 @@ static void restore_fpregs( int reg, int count, int pos, CONTEXT *context,
}
static void do_pac_auth( CONTEXT *context )
{
register DWORD64 x17 __asm__( "x17" ) = context->u.s.Lr;
register DWORD64 x16 __asm__( "x16" ) = context->Sp;
/* This is the autib1716 instruction. The hint instruction is used here
* as gcc does not assemble autib1716 for pre armv8.3a targets. For
* pre-armv8.3a targets, this is just treated as a hint instruction, which
* is ignored. */
__asm__( "hint 0xe" : "+r"(x17) : "r"(x16) );
context->u.s.Lr = x17;
}
/***********************************************************************
* process_unwind_codes
*/
@ -773,6 +787,10 @@ static void process_unwind_codes( BYTE *ptr, BYTE *end, CONTEXT *context,
{
memcpy( context, (DWORD64 *)context->Sp, sizeof(CONTEXT) );
}
else if (*ptr == 0xfc) /* pac_sign_lr */
{
do_pac_auth( context );
}
else
{
WARN( "unsupported code %02x\n", *ptr );
@ -820,6 +838,9 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, RUNTIME_FUNCTION
len = (int_size + 8) / 16 + (fp_size + 8) / 16;
switch (func->u.s.CR)
{
case 2:
len++; /* pacibsp */
/* fall through */
case 3:
len++; /* mov x29,sp */
len++; /* stp x29,lr,[sp,0] */
@ -845,7 +866,7 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, RUNTIME_FUNCTION
if (!skip)
{
if (func->u.s.CR == 3)
if (func->u.s.CR == 3 || func->u.s.CR == 2)
{
DWORD64 *fp = (DWORD64 *) context->u.s.Fp; /* u.X[29] */
context->Sp = context->u.s.Fp;
@ -864,6 +885,7 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, RUNTIME_FUNCTION
switch (func->u.s.CR)
{
case 3:
case 2:
/* mov x29,sp */
if (pos++ >= skip) context->Sp = context->u.s.Fp;
if (local_size <= 512)
@ -932,6 +954,7 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, RUNTIME_FUNCTION
restore_regs( 19, 2, -saved_regs, context, ptrs );
}
}
if (func->u.s.CR == 2) do_pac_auth( context );
return NULL;
}