Paul Gofman : ntdll: Preserve syscall frame when calling async IO system APC.

Alexandre Julliard julliard at winehq.org
Wed Dec 23 15:33:16 CST 2020


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

Author: Paul Gofman <pgofman at codeweavers.com>
Date:   Wed Dec 23 14:51:03 2020 +0300

ntdll: Preserve syscall frame when calling async IO system APC.

The frame can currently be reset from ws2_32.dll async IO callbacks
which are still in the user part and are calling 'syscall' functions.
If the user APC is processed after that during the same call to
server_select(), the call_user_apc_dispatcher() faults.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49782
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/unix/server.c        | 16 ++++++++++++++++
 dlls/ntdll/unix/signal_arm.c    |  9 +++++++++
 dlls/ntdll/unix/signal_arm64.c  | 10 ++++++++++
 dlls/ntdll/unix/signal_i386.c   | 10 ++++++++++
 dlls/ntdll/unix/signal_x86_64.c |  9 +++++++++
 dlls/ntdll/unix/unix_private.h  |  3 +++
 6 files changed, 57 insertions(+)

diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c
index 87dd4b10b83..a9608abfb73 100644
--- a/dlls/ntdll/unix/server.c
+++ b/dlls/ntdll/unix/server.c
@@ -389,8 +389,24 @@ static void invoke_system_apc( const apc_call_t *call, apc_result_t *result )
     {
         IO_STATUS_BLOCK *iosb = wine_server_get_ptr( call->async_io.sb );
         NTSTATUS (**user)(void *, IO_STATUS_BLOCK *, NTSTATUS) = wine_server_get_ptr( call->async_io.user );
+        void *saved_frame = get_syscall_frame();
+        void *frame;
+
         result->type = call->type;
         result->async_io.status = (*user)( user, iosb, call->async_io.status );
+
+        if ((frame = get_syscall_frame()) != saved_frame)
+        {
+            /* The frame can be altered by syscalls from ws2_32 async callbacks
+             * which are currently in the user part. */
+            static unsigned int once;
+
+            if (!once++)
+                FIXME( "syscall frame changed in APC function, frame %p, saved_frame %p.\n", frame, saved_frame );
+
+            set_syscall_frame( saved_frame );
+        }
+
         if (result->async_io.status != STATUS_PENDING)
             result->async_io.total = iosb->Information;
         break;
diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c
index e8971d22dbd..487c8501cc7 100644
--- a/dlls/ntdll/unix/signal_arm.c
+++ b/dlls/ntdll/unix/signal_arm.c
@@ -203,6 +203,15 @@ static inline struct arm_thread_data *arm_thread_data(void)
     return (struct arm_thread_data *)ntdll_get_thread_data()->cpu_data;
 }
 
+void *get_syscall_frame(void)
+{
+    return arm_thread_data()->syscall_frame;
+}
+
+void set_syscall_frame(void *frame)
+{
+    arm_thread_data()->syscall_frame = frame;
+}
 
 /***********************************************************************
  *           unwind_builtin_dll
diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c
index 3beef729dca..95042de45e1 100644
--- a/dlls/ntdll/unix/signal_arm64.c
+++ b/dlls/ntdll/unix/signal_arm64.c
@@ -157,6 +157,16 @@ static inline struct arm64_thread_data *arm64_thread_data(void)
     return (struct arm64_thread_data *)ntdll_get_thread_data()->cpu_data;
 }
 
+void *get_syscall_frame(void)
+{
+    return arm64_thread_data()->syscall_frame;
+}
+
+void set_syscall_frame(void *frame)
+{
+    arm64_thread_data()->syscall_frame = frame;
+}
+
 extern void raise_func_trampoline( EXCEPTION_RECORD *rec, CONTEXT *context, void *dispatcher );
 
 /***********************************************************************
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c
index c8690b51f2f..ff9d8a12c14 100644
--- a/dlls/ntdll/unix/signal_i386.c
+++ b/dlls/ntdll/unix/signal_i386.c
@@ -495,6 +495,16 @@ static inline struct x86_thread_data *x86_thread_data(void)
     return (struct x86_thread_data *)ntdll_get_thread_data()->cpu_data;
 }
 
+void *get_syscall_frame(void)
+{
+    return x86_thread_data()->syscall_frame;
+}
+
+void set_syscall_frame(void *frame)
+{
+    x86_thread_data()->syscall_frame = frame;
+}
+
 static inline WORD get_cs(void) { WORD res; __asm__( "movw %%cs,%0" : "=r" (res) ); return res; }
 static inline WORD get_ds(void) { WORD res; __asm__( "movw %%ds,%0" : "=r" (res) ); return res; }
 static inline WORD get_fs(void) { WORD res; __asm__( "movw %%fs,%0" : "=r" (res) ); return res; }
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index 837cd9ed654..1fd26d5bd76 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -306,6 +306,15 @@ static inline struct amd64_thread_data *amd64_thread_data(void)
     return (struct amd64_thread_data *)ntdll_get_thread_data()->cpu_data;
 }
 
+void *get_syscall_frame(void)
+{
+    return amd64_thread_data()->syscall_frame;
+}
+
+void set_syscall_frame(void *frame)
+{
+    amd64_thread_data()->syscall_frame = frame;
+}
 
 /***********************************************************************
  * Definitions for Dwarf unwind tables
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
index 23731f0fdc6..f8f50d0ab27 100644
--- a/dlls/ntdll/unix/unix_private.h
+++ b/dlls/ntdll/unix/unix_private.h
@@ -247,6 +247,9 @@ extern void WINAPI DECLSPEC_NORETURN call_user_exception_dispatcher( EXCEPTION_R
                                                                      NTSTATUS (WINAPI *dispatcher)(EXCEPTION_RECORD*,CONTEXT*) ) DECLSPEC_HIDDEN;
 extern void WINAPI DECLSPEC_NORETURN call_raise_user_exception_dispatcher( NTSTATUS (WINAPI *dispatcher)(void) ) DECLSPEC_HIDDEN;
 
+extern void *get_syscall_frame(void) DECLSPEC_HIDDEN;
+extern void set_syscall_frame(void *frame) DECLSPEC_HIDDEN;
+
 #define TICKSPERSEC 10000000
 #define SECS_1601_TO_1970  ((369 * 365 + 89) * (ULONGLONG)86400)
 




More information about the wine-cvs mailing list