[1/5] server: Add an extra step to desktop shutdowns that explorer can interrupt.

Vincent Povirk madewokherd at gmail.com
Tue Feb 18 16:57:08 CST 2014


Since I've been told not to add any new internal exports to user32,
I've taken the approach of using DestroyWindow. This should make
DestroyWindow(GetDesktopWindow()) succeed if the desktop window
belongs to the current thread and there are no other processes in the
current thread desktop. If there is a process, DestroyWindow fails,
and that way we avoid any race conditions with newly-created
processes.

It makes me nervous sending such a drastic change to the way desktop
shutdowns work, but I don't know any reason this approach can't work.
-------------- next part --------------
From f8b80aaba8509c3d8adf376d7b0032851a65fae5 Mon Sep 17 00:00:00 2001
From: Vincent Povirk <vincent at codeweavers.com>
Date: Fri, 24 Jan 2014 13:39:09 -0600
Subject: [PATCH 1/6] server: Add an extra step to desktop shutdowns that
 explorer can interrupt.

---
 dlls/user32/win.c           | 13 ++++++++++++-
 programs/explorer/desktop.c |  4 ++++
 server/protocol.def         |  5 +++++
 server/winstation.c         | 22 ++++++++++++++++++++--
 4 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/dlls/user32/win.c b/dlls/user32/win.c
index 275b93c..4f23255 100644
--- a/dlls/user32/win.c
+++ b/dlls/user32/win.c
@@ -1800,7 +1800,7 @@ BOOL WINAPI DestroyWindow( HWND hwnd )
 {
     BOOL is_child;
 
-    if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
+    if (!(hwnd = WIN_IsCurrentThread( hwnd )))
     {
         SetLastError( ERROR_ACCESS_DENIED );
         return FALSE;
@@ -1808,6 +1808,17 @@ BOOL WINAPI DestroyWindow( HWND hwnd )
 
     TRACE("(%p)\n", hwnd);
 
+    if (is_desktop_window( hwnd ))
+    {
+        BOOL ret;
+        SERVER_START_REQ( unlink_desktop )
+        {
+            ret = !wine_server_call_err( req );
+        }
+        SERVER_END_REQ;
+        if (!ret) return FALSE;
+    }
+
       /* Call hooks */
 
     if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c
index 474e93e..7afc8d9 100644
--- a/programs/explorer/desktop.c
+++ b/programs/explorer/desktop.c
@@ -511,6 +511,10 @@ static LRESULT WINAPI desktop_wnd_proc( HWND hwnd, UINT message, WPARAM wp, LPAR
         return 0;
 
     case WM_CLOSE:
+        DestroyWindow( hwnd );
+        return 0;
+
+    case WM_DESTROY:
         PostQuitMessage(0);
         return 0;
 
diff --git a/server/protocol.def b/server/protocol.def
index fec5e75..0e5c608 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2755,6 +2755,11 @@ enum coords_relative
 @END
 
 
+/* Prevent new processes from accessing the thread desktop */
+ at REQ(unlink_desktop)
+ at END
+
+
 /* Get/set information about a user object (window station or desktop) */
 @REQ(set_user_object_info)
     obj_handle_t handle;          /* handle to the object */
diff --git a/server/winstation.c b/server/winstation.c
index 08389bb..83f6d21 100644
--- a/server/winstation.c
+++ b/server/winstation.c
@@ -305,8 +305,7 @@ static void close_desktop_timeout( void *private )
     struct desktop *desktop = private;
 
     desktop->close_timeout = NULL;
-    unlink_named_object( &desktop->obj );  /* make sure no other process can open it */
-    post_desktop_message( desktop, WM_CLOSE, 0, 0 );  /* and signal the owner to quit */
+    post_desktop_message( desktop, WM_CLOSE, 0, 0 );  /* signal the owner to quit */
 }
 
 /* add a user of the desktop and cancel the close timeout */
@@ -724,3 +723,22 @@ DECL_HANDLER(enum_desktop)
     release_object( winstation );
     set_error( STATUS_NO_MORE_ENTRIES );
 }
+
+
+/* Prevent new processes from accessing a desktop */
+DECL_HANDLER(unlink_desktop)
+{
+    struct desktop *desktop;
+
+    if ((desktop = get_thread_desktop(current, 0)))
+    {
+        /* Fail if there are other processes still in the desktop. */
+        if (desktop->users > 1)
+            set_error( STATUS_DEVICE_BUSY );
+        else
+            unlink_named_object( &desktop->obj );
+
+        release_object( desktop );
+    }
+}
+
-- 
1.8.3.2



More information about the wine-patches mailing list