From 7cf357b20c5d2a8d4a2709ee878e9ad425d733ee Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Wed, 21 Oct 2015 18:56:08 +0200 Subject: [PATCH] Added patch to block interruption of system APC in server_select. --- README.md | 3 +- debian/changelog | 1 + ...-signals-while-executing-system-APCs.patch | 122 ++++++++++++++++++ patches/ntdll-Wait_User_APC/definition | 1 + patches/patchinstall.sh | 5 + 5 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 patches/ntdll-Wait_User_APC/0003-ntdll-Block-signals-while-executing-system-APCs.patch diff --git a/README.md b/README.md index 9a248225..4e6b0cb1 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,9 @@ Wine. All those differences are also documented on the Included bug fixes and improvements ----------------------------------- -**Bug fixes and features included in the next upcoming release [3]:** +**Bug fixes and features included in the next upcoming release [4]:** +* Do not allow interruption of system APC in server_select ([Wine Bug #14697](https://bugs.winehq.org/show_bug.cgi?id=14697)) * Implement stub for ProcessQuotaLimits info class * Release capture before sending WM_COMMAND ([Wine Bug #39296](https://bugs.winehq.org/show_bug.cgi?id=39296)) * Use wrapper function for consolidation callback during unwinding. ([Wine Bug #39449](https://bugs.winehq.org/show_bug.cgi?id=39449)) diff --git a/debian/changelog b/debian/changelog index 2cb846fd..75fd6a0b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,6 +3,7 @@ wine-staging (1.7.54) UNRELEASED; urgency=low unwinding. * Added patch to implement stub for ProcessQuotaLimits info class. * Added patch to release capture before sending WM_COMMAND. + * Added patch to block interruption of system APC in server_select. * Removed patch to implement kernel32.GetPhysicallyInstalledSystemMemory (accepted upstream). * Partially removed patches for ws2_32 TransmitFile (accepted upstream). diff --git a/patches/ntdll-Wait_User_APC/0003-ntdll-Block-signals-while-executing-system-APCs.patch b/patches/ntdll-Wait_User_APC/0003-ntdll-Block-signals-while-executing-system-APCs.patch new file mode 100644 index 00000000..34400f77 --- /dev/null +++ b/patches/ntdll-Wait_User_APC/0003-ntdll-Block-signals-while-executing-system-APCs.patch @@ -0,0 +1,122 @@ +From db7522d47373208237a1b8806c72d06a21b3bb66 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Wed, 21 Oct 2015 18:53:58 +0200 +Subject: ntdll: Block signals while executing system APCs. + +--- + dlls/ntdll/server.c | 46 +++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 39 insertions(+), 7 deletions(-) + +diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c +index 7d8d1e9..d46d023 100644 +--- a/dlls/ntdll/server.c ++++ b/dlls/ntdll/server.c +@@ -371,13 +371,30 @@ static int wait_select_reply( void *cookie ) + + + /*********************************************************************** ++ * is_system_apc ++ * ++ * Checks if an APC call is a system APC. ++ */ ++static BOOL is_system_apc( const apc_call_t *call ) ++{ ++ switch (call->type) ++ { ++ case APC_USER: ++ case APC_TIMER: ++ return FALSE; ++ default: ++ return TRUE; ++ } ++} ++ ++ ++/*********************************************************************** + * invoke_apc + * + * Invoke a single APC. Return TRUE if a user APC has been run. + */ +-static BOOL invoke_apc( const apc_call_t *call, apc_result_t *result ) ++static void invoke_apc( const apc_call_t *call, apc_result_t *result ) + { +- BOOL user_apc = FALSE; + SIZE_T size; + void *addr; + +@@ -391,7 +408,6 @@ static BOOL invoke_apc( const apc_call_t *call, apc_result_t *result ) + { + void (WINAPI *func)(ULONG_PTR,ULONG_PTR,ULONG_PTR) = wine_server_get_ptr( call->user.func ); + func( call->user.args[0], call->user.args[1], call->user.args[2] ); +- user_apc = TRUE; + break; + } + case APC_TIMER: +@@ -399,7 +415,6 @@ static BOOL invoke_apc( const apc_call_t *call, apc_result_t *result ) + void (WINAPI *func)(void*, unsigned int, unsigned int) = wine_server_get_ptr( call->timer.func ); + func( wine_server_get_ptr( call->timer.arg ), + (DWORD)call->timer.time, (DWORD)(call->timer.time >> 32) ); +- user_apc = TRUE; + break; + } + case APC_ASYNC_IO: +@@ -574,7 +589,6 @@ static BOOL invoke_apc( const apc_call_t *call, apc_result_t *result ) + server_protocol_error( "get_apc_request: bad type %d\n", call->type ); + break; + } +- return user_apc; + } + + +@@ -590,10 +604,12 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT + obj_handle_t apc_handle = 0; + apc_call_t call; + apc_result_t result; ++ sigset_t old_set; + timeout_t abs_timeout = timeout ? timeout->QuadPart : TIMEOUT_INFINITE; + + memset( &result, 0, sizeof(result) ); + ++ pthread_sigmask( SIG_BLOCK, &server_block_set, &old_set ); + for (;;) + { + SERVER_START_REQ( select ) +@@ -610,10 +626,25 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT + call = reply->call; + } + SERVER_END_REQ; +- if (ret == STATUS_PENDING) ret = wait_select_reply( &cookie ); ++ if (ret == STATUS_PENDING) ++ { ++ pthread_sigmask( SIG_SETMASK, &old_set, NULL ); ++ ret = wait_select_reply( &cookie ); ++ pthread_sigmask( SIG_BLOCK, &server_block_set, &old_set ); ++ } + if (ret != STATUS_USER_APC) break; +- if (invoke_apc( &call, &result )) ++ ++ if (is_system_apc( &call )) + { ++ /* execute system APC without releasing the lock */ ++ invoke_apc( &call, &result ); ++ } ++ else ++ { ++ pthread_sigmask( SIG_SETMASK, &old_set, NULL ); ++ invoke_apc( &call, &result ); ++ pthread_sigmask( SIG_BLOCK, &server_block_set, &old_set ); ++ + /* if we ran a user apc, we have to check once more if + * additional apcs are queued, but we don't want to wait */ + abs_timeout = 0; +@@ -625,6 +656,7 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT + if (size >= sizeof(select_op->signal_and_wait) && select_op->op == SELECT_SIGNAL_AND_WAIT) + size = offsetof( select_op_t, signal_and_wait.signal ); + } ++ pthread_sigmask( SIG_SETMASK, &old_set, NULL ); + + if (ret == STATUS_TIMEOUT && user_apc) ret = STATUS_USER_APC; + +-- +2.6.1 + diff --git a/patches/ntdll-Wait_User_APC/definition b/patches/ntdll-Wait_User_APC/definition index 40d2b6e7..ea1520a8 100644 --- a/patches/ntdll-Wait_User_APC/definition +++ b/patches/ntdll-Wait_User_APC/definition @@ -1 +1,2 @@ Fixes: Do not check if object was signaled after user APC in server_select +Fixes: [14697] Do not allow interruption of system APC in server_select diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 57477508..4ec2c3ec 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -4384,15 +4384,20 @@ fi # Patchset ntdll-Wait_User_APC # | +# | This patchset fixes the following Wine bugs: +# | * [#14697] Do not allow interruption of system APC in server_select +# | # | Modified files: # | * dlls/kernel32/tests/sync.c, dlls/ntdll/server.c # | if test "$enable_ntdll_Wait_User_APC" -eq 1; then patch_apply ntdll-Wait_User_APC/0001-kernel32-tests-Add-test-to-show-that-multiple-user-A.patch patch_apply ntdll-Wait_User_APC/0002-ntdll-Do-not-check-if-object-was-signaled-after-user.patch + patch_apply ntdll-Wait_User_APC/0003-ntdll-Block-signals-while-executing-system-APCs.patch ( echo '+ { "Sebastian Lackner", "kernel32/tests: Add test to show that multiple user APCs are processed at once.", 1 },'; echo '+ { "Sebastian Lackner", "ntdll: Do not check if object was signaled after user APC in server_select.", 1 },'; + echo '+ { "Sebastian Lackner", "ntdll: Block signals while executing system APCs.", 1 },'; ) >> "$patchlist" fi