From 31bd06cb42dd1aa44b14cd475ef4f6b9d9464948 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Wed, 17 Jun 2015 13:52:46 +0200 Subject: [PATCH] Added patch to fix wineserver crash when pipe server object is destroyed before client (fixes Wine Staging Bug #393). --- debian/changelog | 2 + ...erver-crash-when-pipe-server-object-.patch | 120 ++++++++++++++++++ patches/patchinstall.sh | 2 + 3 files changed, 124 insertions(+) create mode 100644 patches/kernel32-Named_Pipe/0023-server-Fix-wineserver-crash-when-pipe-server-object-.patch diff --git a/debian/changelog b/debian/changelog index 4dbed85e..c34fcb3e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,6 +3,8 @@ wine-staging (1.7.46) UNRELEASED; urgency=low * Added patch to improve IoGetDeviceObjectPointer stub to appease SecuROM 5.x. * Added patch to globally invalidate key state on changes in other threads. * Added patch to fix possible use-after-free in wineserver device IPR code. + * Added patch to fix wineserver crash when pipe server object is destroyed + before client (fixes Wine Staging Bug #393). * Removed patch for implementation of GdipCreateRegionRgnData (accepted upstream). * Removed patch to fix output buffer size for IOCTL_DVD_READ_STRUCTURE diff --git a/patches/kernel32-Named_Pipe/0023-server-Fix-wineserver-crash-when-pipe-server-object-.patch b/patches/kernel32-Named_Pipe/0023-server-Fix-wineserver-crash-when-pipe-server-object-.patch new file mode 100644 index 00000000..eaef55f0 --- /dev/null +++ b/patches/kernel32-Named_Pipe/0023-server-Fix-wineserver-crash-when-pipe-server-object-.patch @@ -0,0 +1,120 @@ +From b2a17b581c4d8452a605b494f8ff7884fcb3a481 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Wed, 17 Jun 2015 13:50:59 +0200 +Subject: server: Fix wineserver crash when pipe server object is destroyed + before client. + +--- + dlls/kernel32/tests/pipe.c | 35 +++++++++++++++++++++++++++++++++++ + server/named_pipe.c | 14 ++++++++++++-- + 2 files changed, 47 insertions(+), 2 deletions(-) + +diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c +index ddad351..06242aa 100644 +--- a/dlls/kernel32/tests/pipe.c ++++ b/dlls/kernel32/tests/pipe.c +@@ -1162,6 +1162,8 @@ static void test_CloseNamedPipe(void) + char ibuf[32]; + DWORD written; + DWORD readden; ++ DWORD state; ++ BOOL ret; + + hnp = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, +@@ -1196,6 +1198,14 @@ static void test_CloseNamedPipe(void) + ok(readden == sizeof(obuf), "got %d bytes\n", readden); + /* pipe is empty now */ + ++ ret = GetNamedPipeHandleStateA(hFile, &state, NULL, NULL, NULL, NULL, 0); ++ todo_wine ++ ok(ret, "GetNamedPipeHandleState failed with %d\n", GetLastError()); ++ state = PIPE_READMODE_MESSAGE | PIPE_WAIT; ++ ret = SetNamedPipeHandleState(hFile, &state, NULL, NULL); ++ todo_wine ++ ok(ret, "SetNamedPipeHandleState failed with %d\n", GetLastError()); ++ + SetLastError(0xdeadbeef); + ok(!ReadFile(hFile, ibuf, 0, &readden, NULL), "ReadFile() succeeded\n"); + ok(GetLastError() == ERROR_BROKEN_PIPE, "GetLastError() returned %08x, expected ERROR_BROKEN_PIPE\n", GetLastError()); +@@ -1233,6 +1243,14 @@ static void test_CloseNamedPipe(void) + ok(readden == 0, "got %d bytes\n", readden); + /* pipe is empty now */ + ++ ret = GetNamedPipeHandleStateA(hFile, &state, NULL, NULL, NULL, NULL, 0); ++ todo_wine ++ ok(ret, "GetNamedPipeHandleState failed with %d\n", GetLastError()); ++ state = PIPE_READMODE_MESSAGE | PIPE_WAIT; ++ ret = SetNamedPipeHandleState(hFile, &state, NULL, NULL); ++ todo_wine ++ ok(ret, "SetNamedPipeHandleState failed with %d\n", GetLastError()); ++ + SetLastError(0xdeadbeef); + ok(!ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n"); + ok(GetLastError() == ERROR_BROKEN_PIPE, "GetLastError() returned %08x, expected ERROR_BROKEN_PIPE\n", GetLastError()); +@@ -1277,6 +1295,14 @@ static void test_CloseNamedPipe(void) + ok(readden == sizeof(obuf), "got %d bytes\n", readden); + /* pipe is empty now */ + ++ ret = GetNamedPipeHandleStateA(hnp, &state, NULL, NULL, NULL, NULL, 0); ++ ok(ret, "GetNamedPipeHandleState failed with %d\n", GetLastError()); ++ SetLastError(0xdeadbeef); ++ state = PIPE_READMODE_MESSAGE | PIPE_WAIT; ++ ret = SetNamedPipeHandleState(hFile, &state, NULL, NULL); ++ ok(!ret, "SetNamedPipeHandleState unexpectedly succeeded\n"); ++ ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError() returned %08x, expected ERROR_INVALID_HANDLE\n", GetLastError()); ++ + SetLastError(0xdeadbeef); + ok(!ReadFile(hnp, ibuf, 0, &readden, NULL), "ReadFile() succeeded\n"); + ok(GetLastError() == ERROR_BROKEN_PIPE, "GetLastError() returned %08x, expected ERROR_BROKEN_PIPE\n", GetLastError()); +@@ -1314,6 +1340,15 @@ static void test_CloseNamedPipe(void) + ok(readden == 0, "got %d bytes\n", readden); + /* pipe is empty now */ + ++ ret = GetNamedPipeHandleStateA(hnp, &state, NULL, NULL, NULL, NULL, 0); ++ ok(ret, "GetNamedPipeHandleState failed with %d\n", GetLastError()); ++ ret = SetNamedPipeHandleState(hFile, &state, NULL, NULL); ++ SetLastError(0xdeadbeef); ++ state = PIPE_READMODE_MESSAGE | PIPE_WAIT; ++ ret = SetNamedPipeHandleState(hFile, &state, NULL, NULL); ++ ok(!ret, "SetNamedPipeHandleState unexpectedly succeeded\n"); ++ ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError() returned %08x, expected ERROR_INVALID_HANDLE\n", GetLastError()); ++ + SetLastError(0xdeadbeef); + ok(!ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n"); + ok(GetLastError() == ERROR_BROKEN_PIPE, "GetLastError() returned %08x, expected ERROR_BROKEN_PIPE\n", GetLastError()); +diff --git a/server/named_pipe.c b/server/named_pipe.c +index 4718d1b..53bec02 100644 +--- a/server/named_pipe.c ++++ b/server/named_pipe.c +@@ -1105,7 +1105,12 @@ DECL_HANDLER(get_named_pipe_info) + client = (struct pipe_client *)get_handle_obj( current->process, req->handle, + 0, &pipe_client_ops ); + if (!client) return; +- server = client->server; ++ if (!(server = client->server)) ++ { ++ release_object( client ); ++ set_error( STATUS_INVALID_HANDLE ); ++ return; ++ } + } + + reply->flags = client ? client->pipe_flags : server->pipe_flags; +@@ -1142,7 +1147,12 @@ DECL_HANDLER(set_named_pipe_info) + client = (struct pipe_client *)get_handle_obj( current->process, req->handle, + 0, &pipe_client_ops ); + if (!client) return; +- server = client->server; ++ if (!(server = client->server)) ++ { ++ release_object( client ); ++ set_error( STATUS_INVALID_HANDLE ); ++ return; ++ } + } + + if ((req->flags & ~(NAMED_PIPE_MESSAGE_STREAM_READ | NAMED_PIPE_NONBLOCKING_MODE)) || +-- +2.4.3 + diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 38eda68f..f82cf796 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -3147,6 +3147,7 @@ if test "$enable_kernel32_Named_Pipe" -eq 1; then patch_apply kernel32-Named_Pipe/0020-kernel32-tests-Add-tests-for-behaviour-of-WriteFile-.patch patch_apply kernel32-Named_Pipe/0021-server-Return-correct-error-codes-for-NtWriteFile-wh.patch patch_apply kernel32-Named_Pipe/0022-ntdll-Pre-cache-file-descriptors-after-opening-a-fil.patch + patch_apply kernel32-Named_Pipe/0023-server-Fix-wineserver-crash-when-pipe-server-object-.patch ( echo '+ { "Dan Kegel", "kernel32: ConnectNamedPort should return FALSE and set ERROR_PIPE_CONNECTED on success in overlapped mode.", 1 },'; echo '+ { "Sebastian Lackner", "kernel32/tests: Add tests for PeekNamedPipe with partial received messages.", 1 },'; @@ -3170,6 +3171,7 @@ if test "$enable_kernel32_Named_Pipe" -eq 1; then echo '+ { "Sebastian Lackner", "kernel32/tests: Add tests for behaviour of WriteFile on closed pipe.", 1 },'; echo '+ { "Sebastian Lackner", "server: Return correct error codes for NtWriteFile when pipes are closed without disconnecting.", 1 },'; echo '+ { "Sebastian Lackner", "ntdll: Pre-cache file descriptors after opening a file.", 1 },'; + echo '+ { "Sebastian Lackner", "server: Fix wineserver crash when pipe server object is destroyed before client.", 1 },'; ) >> "$patchlist" fi