Paul Gofman : ntdll: Always copy context in call_user_apc_dispatcher() on x64.

Alexandre Julliard julliard at winehq.org
Thu Dec 17 15:50:26 CST 2020


Module: wine
Branch: master
Commit: c72f52d7cc4353498fe5570229231d5d1cb36204
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=c72f52d7cc4353498fe5570229231d5d1cb36204

Author: Paul Gofman <pgofman at codeweavers.com>
Date:   Thu Dec 17 02:05:04 2020 +0300

ntdll: Always copy context in call_user_apc_dispatcher() on x64.

Currently, if call_user_apc_dispatcher() is called with nonzero context,
there is no guarantee that the provided context is stored above the
rsp = context_ptr->Rsp - (sizeof(CONTEXT) + offsetof(frame,ret_addr))
being set.

Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/unix/signal_x86_64.c | 62 +++++++++++++++++++++++++++++++----------
 1 file changed, 48 insertions(+), 14 deletions(-)

diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index 7181b48728c..3ae3b4c141e 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -250,6 +250,22 @@ C_ASSERT((offsetof(struct stack_layout, xstate) == sizeof(struct stack_layout)))
 C_ASSERT( sizeof(XSTATE) == 0x140 );
 C_ASSERT( sizeof(struct stack_layout) == 0x590 ); /* Should match the size in call_user_exception_dispatcher(). */
 
+/* stack layout when calling an user apc function.
+ * FIXME: match Windows ABI. */
+struct apc_stack_layout
+{
+    ULONG64  save_regs[4];
+    void            *func;
+    ULONG64         align;
+    CONTEXT       context;
+    ULONG64           rbp;
+    ULONG64           rip;
+};
+
+/* Should match size and offset in call_user_apc_dispatcher(). */
+C_ASSERT( offsetof(struct apc_stack_layout, context) == 0x30 );
+C_ASSERT( sizeof(struct apc_stack_layout) == 0x510 );
+
 struct syscall_frame
 {
     ULONG64               xmm[10 * 2];  /* xmm6-xmm15 */
@@ -266,6 +282,9 @@ struct syscall_frame
     ULONG64               ret_addr;
 };
 
+/* Should match the offset in call_user_apc_dispatcher(). */
+C_ASSERT( offsetof( struct syscall_frame, ret_addr ) == 0xf0);
+
 struct amd64_thread_data
 {
     DWORD_PTR             dr0;           /* 02f0 debug registers */
@@ -2013,31 +2032,46 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
 /***********************************************************************
  *           call_user_apc_dispatcher
  */
+struct apc_stack_layout * WINAPI setup_user_apc_dispatcher_stack( CONTEXT *context, struct apc_stack_layout *stack )
+{
+    CONTEXT c;
+
+    if (!context)
+    {
+        c.ContextFlags = CONTEXT_FULL;
+        NtGetContextThread( GetCurrentThread(), &c );
+        context = &c;
+    }
+    memmove( &stack->context, context, sizeof(stack->context) );
+    return stack;
+}
+
 __ASM_GLOBAL_FUNC( call_user_apc_dispatcher,
                    "movq 0x28(%rsp),%rsi\n\t"       /* func */
                    "movq 0x30(%rsp),%rdi\n\t"       /* dispatcher */
                    "movq %gs:0x30,%rbx\n\t"
-                   "jrcxz 1f\n\t"
-                   "movq 0x98(%rcx),%rax\n\t"       /* context_ptr->Rsp */
-                   "leaq -0x5c0(%rax),%rsp\n\t"     /* sizeof(CONTEXT) + offsetof(frame,ret_addr) */
-                   "andq $~15,%rsp\n\t"
-                   "jmp 2f\n"
-                   "1:\tmovq 0x328(%rbx),%rax\n\t"  /* amd64_thread_data()->syscall_frame */
-                   "leaq -0x4d0(%rax),%rsp\n\t"
-                   "andq $~15,%rsp\n\t"
                    "movq %rdx,%r12\n\t"             /* ctx */
                    "movq %r8,%r13\n\t"              /* arg1 */
                    "movq %r9,%r14\n\t"              /* arg2 */
-                   "movq %rsp,%rdx\n\t"             /* context */
-                   "movl $0x10000b,0x30(%rdx)\n\t"  /* context.ContextFlags */
-                   "movq $~1,%rcx\n\t"
-                   "call " __ASM_NAME("NtGetContextThread") "\n\t"
-                   "movq %rsp,%rcx\n\t"             /* context */
+                   "jrcxz 1f\n\t"
+                   "movq 0x98(%rcx),%rdx\n\t"        /* context->Rsp */
+                   "jmp 2f\n\t"
+                   "1:\tmovq 0x328(%rbx),%rax\n\t"   /* amd64_thread_data()->syscall_frame */
+                   "leaq 0xf0(%rax),%rdx\n\t"        /* &amd64_thread_data()->syscall_frame->ret_addr */
+                   "2:\tsubq $0x510,%rdx\n\t"        /* sizeof(struct apc_stack_layout) */
+                   "andq $~0xf,%rdx\n\t"
+                   "addq $8,%rsp\n\t"                /* pop return address */
+                   "cmpq %rsp,%rdx\n\t"
+                   "cmovbq %rdx,%rsp\n\t"
+                   "subq $0x20,%rsp\n\t"
+                   "call " __ASM_NAME("setup_user_apc_dispatcher_stack") "\n\t"
+                   "movq %rax,%rsp\n\t"
+                   "leaq 0x30(%rsp),%rcx\n\t"       /* context */
                    "movq $0xc0,0x78(%rcx)\n\t"      /* context.Rax = STATUS_USER_APC */
                    "movq %r12,%rdx\n\t"             /* ctx */
                    "movq %r13,%r8\n\t"              /* arg1 */
                    "movq %r14,%r9\n"                /* arg2 */
-                   "2:\tmovq $0,0x328(%rbx)\n\t"
+                   "movq $0,0x328(%rbx)\n\t"        /* amd64_thread_data()->syscall_frame */
                    "movq %rsi,0x20(%rsp)\n\t"       /* func */
                    "movq 0xa0(%rcx),%rbp\n\t"       /* context.Rbp */
                    "pushq 0xf8(%rcx)\n\t"           /* context.Rip */




More information about the wine-cvs mailing list