ntdll: Handle ATL thunk emulation in signal handler on i386.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2019-09-12 20:50:16 +02:00
parent df3fad6383
commit 5501055ed5
1 changed files with 43 additions and 66 deletions

View File

@ -1682,9 +1682,9 @@ union atl_thunk
* *
* Check if code destination is an ATL thunk, and emulate it if so. * Check if code destination is an ATL thunk, and emulate it if so.
*/ */
static BOOL check_atl_thunk( EXCEPTION_RECORD *rec, CONTEXT *context ) static BOOL check_atl_thunk( ucontext_t *sigcontext, struct stack_layout *stack )
{ {
const union atl_thunk *thunk = (const union atl_thunk *)rec->ExceptionInformation[1]; const union atl_thunk *thunk = (const union atl_thunk *)stack->rec.ExceptionInformation[1];
union atl_thunk thunk_copy; union atl_thunk thunk_copy;
SIZE_T thunk_len; SIZE_T thunk_len;
@ -1694,62 +1694,61 @@ static BOOL check_atl_thunk( EXCEPTION_RECORD *rec, CONTEXT *context )
if (thunk_len >= sizeof(thunk_copy.t1) && thunk_copy.t1.movl == 0x042444c7 && if (thunk_len >= sizeof(thunk_copy.t1) && thunk_copy.t1.movl == 0x042444c7 &&
thunk_copy.t1.jmp == 0xe9) thunk_copy.t1.jmp == 0xe9)
{ {
if (!virtual_uninterrupted_write_memory( (DWORD *)context->Esp + 1, if (!virtual_uninterrupted_write_memory( (DWORD *)stack->context.Esp + 1,
&thunk_copy.t1.this, sizeof(DWORD) )) &thunk_copy.t1.this, sizeof(DWORD) ))
{ {
context->Eip = (DWORD_PTR)(&thunk->t1.func + 1) + thunk_copy.t1.func; EIP_sig(sigcontext) = (DWORD_PTR)(&thunk->t1.func + 1) + thunk_copy.t1.func;
TRACE( "emulating ATL thunk type 1 at %p, func=%08x arg=%08x\n", TRACE( "emulating ATL thunk type 1 at %p, func=%08x arg=%08x\n",
thunk, context->Eip, thunk_copy.t1.this ); thunk, EIP_sig(sigcontext), thunk_copy.t1.this );
return TRUE; return TRUE;
} }
} }
else if (thunk_len >= sizeof(thunk_copy.t2) && thunk_copy.t2.movl == 0xb9 && else if (thunk_len >= sizeof(thunk_copy.t2) && thunk_copy.t2.movl == 0xb9 &&
thunk_copy.t2.jmp == 0xe9) thunk_copy.t2.jmp == 0xe9)
{ {
context->Ecx = thunk_copy.t2.this; ECX_sig(sigcontext) = thunk_copy.t2.this;
context->Eip = (DWORD_PTR)(&thunk->t2.func + 1) + thunk_copy.t2.func; EIP_sig(sigcontext) = (DWORD_PTR)(&thunk->t2.func + 1) + thunk_copy.t2.func;
TRACE( "emulating ATL thunk type 2 at %p, func=%08x ecx=%08x\n", TRACE( "emulating ATL thunk type 2 at %p, func=%08x ecx=%08x\n",
thunk, context->Eip, context->Ecx ); thunk, EIP_sig(sigcontext), ECX_sig(sigcontext) );
return TRUE; return TRUE;
} }
else if (thunk_len >= sizeof(thunk_copy.t3) && thunk_copy.t3.movl1 == 0xba && else if (thunk_len >= sizeof(thunk_copy.t3) && thunk_copy.t3.movl1 == 0xba &&
thunk_copy.t3.movl2 == 0xb9 && thunk_copy.t3.movl2 == 0xb9 &&
thunk_copy.t3.jmp == 0xe1ff) thunk_copy.t3.jmp == 0xe1ff)
{ {
context->Edx = thunk_copy.t3.this; EDX_sig(sigcontext) = thunk_copy.t3.this;
context->Ecx = thunk_copy.t3.func; ECX_sig(sigcontext) = thunk_copy.t3.func;
context->Eip = thunk_copy.t3.func; EIP_sig(sigcontext) = thunk_copy.t3.func;
TRACE( "emulating ATL thunk type 3 at %p, func=%08x ecx=%08x edx=%08x\n", TRACE( "emulating ATL thunk type 3 at %p, func=%08x ecx=%08x edx=%08x\n",
thunk, context->Eip, context->Ecx, context->Edx ); thunk, EIP_sig(sigcontext), ECX_sig(sigcontext), EDX_sig(sigcontext) );
return TRUE; return TRUE;
} }
else if (thunk_len >= sizeof(thunk_copy.t4) && thunk_copy.t4.movl1 == 0xb9 && else if (thunk_len >= sizeof(thunk_copy.t4) && thunk_copy.t4.movl1 == 0xb9 &&
thunk_copy.t4.movl2 == 0xb8 && thunk_copy.t4.movl2 == 0xb8 &&
thunk_copy.t4.jmp == 0xe0ff) thunk_copy.t4.jmp == 0xe0ff)
{ {
context->Ecx = thunk_copy.t4.this; ECX_sig(sigcontext) = thunk_copy.t4.this;
context->Eax = thunk_copy.t4.func; EAX_sig(sigcontext) = thunk_copy.t4.func;
context->Eip = thunk_copy.t4.func; EIP_sig(sigcontext) = thunk_copy.t4.func;
TRACE( "emulating ATL thunk type 4 at %p, func=%08x eax=%08x ecx=%08x\n", TRACE( "emulating ATL thunk type 4 at %p, func=%08x eax=%08x ecx=%08x\n",
thunk, context->Eip, context->Eax, context->Ecx ); thunk, EIP_sig(sigcontext), EAX_sig(sigcontext), ECX_sig(sigcontext) );
return TRUE; return TRUE;
} }
else if (thunk_len >= sizeof(thunk_copy.t5) && thunk_copy.t5.inst1 == 0xff515859 && else if (thunk_len >= sizeof(thunk_copy.t5) && thunk_copy.t5.inst1 == 0xff515859 &&
thunk_copy.t5.inst2 == 0x0460) thunk_copy.t5.inst2 == 0x0460)
{ {
DWORD func, stack[2]; DWORD func, sp[2];
if (virtual_uninterrupted_read_memory( (DWORD *)context->Esp, if (virtual_uninterrupted_read_memory( (DWORD *)stack->context.Esp, sp, sizeof(sp) ) == sizeof(sp) &&
stack, sizeof(stack) ) == sizeof(stack) && virtual_uninterrupted_read_memory( (DWORD *)sp[1] + 1, &func, sizeof(DWORD) ) == sizeof(DWORD) &&
virtual_uninterrupted_read_memory( (DWORD *)stack[1] + 1, !virtual_uninterrupted_write_memory( (DWORD *)stack->context.Esp + 1, &sp[0], sizeof(sp[0]) ))
&func, sizeof(DWORD) ) == sizeof(DWORD) &&
!virtual_uninterrupted_write_memory( (DWORD *)context->Esp + 1, &stack[0], sizeof(stack[0]) ))
{ {
context->Ecx = stack[0]; ECX_sig(sigcontext) = sp[0];
context->Eax = stack[1]; EAX_sig(sigcontext) = sp[1];
context->Esp = context->Esp + sizeof(DWORD); ESP_sig(sigcontext) += sizeof(DWORD);
context->Eip = func; EIP_sig(sigcontext) = func;
TRACE( "emulating ATL thunk type 5 at %p, func=%08x eax=%08x ecx=%08x esp=%08x\n", TRACE( "emulating ATL thunk type 5 at %p, func=%08x eax=%08x ecx=%08x esp=%08x\n",
thunk, context->Eip, context->Eax, context->Ecx, context->Esp ); thunk, EIP_sig(sigcontext), EAX_sig(sigcontext),
ECX_sig(sigcontext), ESP_sig(sigcontext) );
return TRUE; return TRUE;
} }
} }
@ -1901,41 +1900,6 @@ static inline DWORD get_fpu_code( const CONTEXT *context )
} }
/**********************************************************************
* raise_segv_exception
*/
static void WINAPI raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
{
NTSTATUS status;
switch(rec->ExceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION:
if (rec->NumberParameters == 2)
{
if (rec->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT)
{
ULONG flags;
NtQueryInformationProcess( GetCurrentProcess(), ProcessExecuteFlags,
&flags, sizeof(flags), NULL );
if (!(flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION) && check_atl_thunk( rec, context ))
goto done;
/* send EXCEPTION_EXECUTE_FAULT only if data execution prevention is enabled */
if (!(flags & MEM_EXECUTE_OPTION_DISABLE))
rec->ExceptionInformation[0] = EXCEPTION_READ_FAULT;
}
}
break;
}
status = NtRaiseException( rec, context, TRUE );
raise_status( status, rec );
done:
set_cpu_context( context );
}
/********************************************************************** /**********************************************************************
* raise_generic_exception * raise_generic_exception
* *
@ -2065,9 +2029,22 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
stack->rec.NumberParameters = 2; stack->rec.NumberParameters = 2;
stack->rec.ExceptionInformation[0] = (get_error_code(context) >> 1) & 0x09; stack->rec.ExceptionInformation[0] = (get_error_code(context) >> 1) & 0x09;
stack->rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr; stack->rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr;
if (!(stack->rec.ExceptionCode = virtual_handle_fault( (void *)stack->rec.ExceptionInformation[1], stack->rec.ExceptionCode = virtual_handle_fault( (void *)stack->rec.ExceptionInformation[1],
stack->rec.ExceptionInformation[0], FALSE ))) stack->rec.ExceptionInformation[0], FALSE );
return; if (!stack->rec.ExceptionCode) return;
if (stack->rec.ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
stack->rec.ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT)
{
ULONG flags;
NtQueryInformationProcess( GetCurrentProcess(), ProcessExecuteFlags,
&flags, sizeof(flags), NULL );
if (!(flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION) && check_atl_thunk( context, stack ))
return;
/* send EXCEPTION_EXECUTE_FAULT only if data execution prevention is enabled */
if (!(flags & MEM_EXECUTE_OPTION_DISABLE))
stack->rec.ExceptionInformation[0] = EXCEPTION_READ_FAULT;
}
break; break;
case TRAP_x86_ALIGNFLT: /* Alignment check exception */ case TRAP_x86_ALIGNFLT: /* Alignment check exception */
/* FIXME: pass through exception handler first? */ /* FIXME: pass through exception handler first? */
@ -2091,7 +2068,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
break; break;
} }
done: done:
setup_raise_exception( context, stack, raise_segv_exception ); setup_raise_exception( context, stack, raise_generic_exception );
} }