[WIN32SS:NTUSER] Use the 2nd parameter of NtUserGetThreadDesktop() as fallback. ... 1065/head
authorAndrew Boyarshin <andrew.boyarshin@gmail.com>
Mon, 26 Nov 2018 12:49:15 +0000 (19:49 +0700)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 28 Apr 2019 17:27:45 +0000 (19:27 +0200)
- The 2nd parameter is already passed in user-mode by GetThreadDesktop().
  It is then used by NtUserGetThreadDesktop() as a fallback for console
  threads.

- Lookup and validate the thread by using the IntTID2PTI() helper.
- Don't reference the desktop with too many access rights.
- Get rid of the old-school DECLARE_RETURN() & co. macros.

Co-authored-by: Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
win32ss/include/ntuser.h
win32ss/user/ntuser/desktop.c
win32ss/user/user32/misc/desktop.c

index 68f37eb..81a0b91 100644 (file)
@@ -2439,7 +2439,7 @@ HDESK
 NTAPI
 NtUserGetThreadDesktop(
     DWORD dwThreadId,
-    DWORD Unknown1);
+    HDESK hConsoleDesktop);
 
 enum ThreadStateRoutines
 {
index 875cc4b..f1aec1b 100644 (file)
@@ -2981,14 +2981,14 @@ CLEANUP:
  */
 
 HDESK APIENTRY
-NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
+NtUserGetThreadDesktop(DWORD dwThreadId, HDESK hConsoleDesktop)
 {
+    HDESK hDesk;
     NTSTATUS Status;
-    PETHREAD Thread;
+    PTHREADINFO pti;
+    PEPROCESS Process;
     PDESKTOP DesktopObject;
-    HDESK hDesk, hThreadDesktop;
     OBJECT_HANDLE_INFORMATION HandleInformation;
-    DECLARE_RETURN(HDESK);
 
     UserEnterExclusive();
     TRACE("Enter NtUserGetThreadDesktop\n");
@@ -2996,67 +2996,97 @@ NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
     if (!dwThreadId)
     {
         EngSetLastError(ERROR_INVALID_PARAMETER);
-        RETURN(0);
+        hDesk = NULL;
+        goto Quit;
     }
 
-    Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)dwThreadId, &Thread);
-    if (!NT_SUCCESS(Status))
+    /* Validate the Win32 thread and retrieve its information */
+    pti = IntTID2PTI(UlongToHandle(dwThreadId));
+    if (pti)
+    {
+        /* Get the desktop handle of the thread */
+        hDesk = pti->hdesk;
+        Process = pti->ppi->peProcess;
+    }
+    else if (hConsoleDesktop)
+    {
+        /*
+         * The thread may belong to a console, so attempt to use the provided
+         * console desktop handle as a fallback. Otherwise this means that the
+         * thread is either not Win32 or invalid.
+         */
+        hDesk = hConsoleDesktop;
+        Process = gpepCSRSS;
+    }
+    else
     {
         EngSetLastError(ERROR_INVALID_PARAMETER);
-        RETURN(0);
+        hDesk = NULL;
+        goto Quit;
     }
 
-    if (Thread->ThreadsProcess == PsGetCurrentProcess())
+    if (!hDesk)
     {
-        /* Just return the handle, we queried the desktop handle of a thread running
-           in the same context */
-        hDesk = ((PTHREADINFO)Thread->Tcb.Win32Thread)->hdesk;
-        ObDereferenceObject(Thread);
-        RETURN(hDesk);
+        ERR("Desktop information of thread 0x%x broken!?\n", dwThreadId);
+        goto Quit;
     }
 
-    /* Get the desktop handle and the desktop of the thread */
-    if (!(hThreadDesktop = ((PTHREADINFO)Thread->Tcb.Win32Thread)->hdesk) ||
-        !(DesktopObject = ((PTHREADINFO)Thread->Tcb.Win32Thread)->rpdesk))
+    if (Process == PsGetCurrentProcess())
     {
-        ObDereferenceObject(Thread);
-        ERR("Desktop information of thread 0x%x broken!?\n", dwThreadId);
-        RETURN(NULL);
+        /*
+         * Just return the handle, since we queried the desktop handle
+         * of a thread running in the same context.
+         */
+        goto Quit;
     }
 
-    /* We could just use DesktopObject instead of looking up the handle, but latter
-       may be a bit safer (e.g. when the desktop is being destroyed */
-    /* Switch into the context of the thread we're trying to get the desktop from,
-       so we can use the handle */
-    KeAttachProcess(&Thread->ThreadsProcess->Pcb);
-    Status = ObReferenceObjectByHandle(hThreadDesktop,
-                                       GENERIC_ALL,
+    /*
+     * We could just use the cached rpdesk instead of looking up the handle,
+     * but it may actually be safer to validate the desktop and get a temporary
+     * reference to it so that it does not disappear under us (e.g. when the
+     * desktop is being destroyed) during the operation.
+     */
+    /*
+     * Switch into the context of the thread we are trying to get
+     * the desktop from, so we can use the handle.
+     */
+    KeAttachProcess(&Process->Pcb);
+    Status = ObReferenceObjectByHandle(hDesk,
+                                       0,
                                        ExDesktopObjectType,
                                        UserMode,
                                        (PVOID*)&DesktopObject,
                                        &HandleInformation);
     KeDetachProcess();
 
-    /* The handle couldn't be found, there's nothing to get... */
-    if (!NT_SUCCESS(Status))
+    if (NT_SUCCESS(Status))
     {
-        ObDereferenceObject(Thread);
-        RETURN(NULL);
-    }
+        /*
+         * Lookup our handle table if we can find a handle to the desktop object.
+         * If not, create one.
+         * QUESTION: Do we really need to create a handle in case it doesn't exist??
+         */
+        hDesk = IntGetDesktopObjectHandle(DesktopObject);
 
-    /* Lookup our handle table if we can find a handle to the desktop object,
-       if not, create one */
-    hDesk = IntGetDesktopObjectHandle(DesktopObject);
+        /* All done, we got a valid handle to the desktop */
+        ObDereferenceObject(DesktopObject);
+    }
+    else
+    {
+        /* The handle could not be found, there is nothing to get... */
+        hDesk = NULL;
+    }
 
-    /* All done, we got a valid handle to the desktop */
-    ObDereferenceObject(DesktopObject);
-    ObDereferenceObject(Thread);
-    RETURN(hDesk);
+    if (!hDesk)
+    {
+        ERR("Could not retrieve or access desktop for thread 0x%x\n", dwThreadId);
+        EngSetLastError(ERROR_ACCESS_DENIED);
+    }
 
-CLEANUP:
-    TRACE("Leave NtUserGetThreadDesktop, ret=%p\n",_ret_);
+Quit:
+    TRACE("Leave NtUserGetThreadDesktop, hDesk = 0x%p\n", hDesk);
     UserLeave();
-    END_CLEANUP;
+    return hDesk;
 }
 
 static NTSTATUS
index bd3ca78..862ff16 100644 (file)
@@ -563,7 +563,7 @@ GetThreadDesktop(
     }
 
     return NtUserGetThreadDesktop(dwThreadId,
-                                  (DWORD_PTR)GetThreadConsoleDesktopRequest->ConsoleDesktop);
+                                  GetThreadConsoleDesktopRequest->ConsoleDesktop);
 }