[WIN32K] Use KeStackAttachProcess
[reactos.git] / win32ss / user / ntuser / hook.c
index 11d5cac..792d195 100644 (file)
@@ -2,7 +2,7 @@
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  * PURPOSE:          Window hooks
- * FILE:             subsystems/win32/win32k/ntuser/hook.c
+ * FILE:             win32ss/user/ntuser/hook.c
  * PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
  *                   James Tabor (james.tabor@rectos.org)
  *                   Rafal Harabien (rafalh@reactos.org)
@@ -35,7 +35,7 @@ IntLoadHookModule(int iHookID, HHOOK hHook, BOOL Unload)
 
    ppi = PsGetCurrentProcessWin32Process();
 
-   ERR("IntLoadHookModule. Client PID: %d\n", PsGetProcessId(ppi->peProcess));
+   TRACE("IntLoadHookModule. Client PID: %p\n", PsGetProcessId(ppi->peProcess));
 
     /* Check if this is the api hook */
     if(iHookID == WH_APIHOOK)
@@ -92,7 +92,7 @@ IntHookModuleUnloaded(PDESKTOP pdesk, int iHookID, HHOOK hHook)
     PLIST_ENTRY ListEntry;
     PPROCESSINFO ppiCsr;
 
-    ERR("IntHookModuleUnloaded: iHookID=%d\n", iHookID);
+    TRACE("IntHookModuleUnloaded: iHookID=%d\n", iHookID);
 
     ppiCsr = PsGetProcessWin32Process(gpepCSRSS);
 
@@ -103,13 +103,13 @@ IntHookModuleUnloaded(PDESKTOP pdesk, int iHookID, HHOOK hHook)
 
         /* FIXME: Do some more security checks here */
 
-        /* FIXME: The first check is a reactos specific hack for system threads */
+        /* FIXME: HACK: The first check is a reactos specific hack for system threads */
         if(!PsIsSystemProcess(ptiCurrent->ppi->peProcess) &&
            ptiCurrent->ppi != ppiCsr)
         {
             if(ptiCurrent->ppi->W32PF_flags & W32PF_APIHOOKLOADED)
             {
-                TRACE("IntHookModuleUnloaded: sending message to PID %d, ppi=0x%x\n", PsGetProcessId(ptiCurrent->ppi->peProcess), ptiCurrent->ppi);
+                TRACE("IntHookModuleUnloaded: sending message to PID %p, ppi=%p\n", PsGetProcessId(ptiCurrent->ppi->peProcess), ptiCurrent->ppi);
                 co_MsqSendMessageAsync( ptiCurrent,
                                         0,
                                         iHookID,
@@ -155,7 +155,7 @@ UserRegisterUserApiHook(
         return FALSE;
     }
 
-    ERR("UserRegisterUserApiHook. Server PID: %d\n", PsGetProcessId(pti->ppi->peProcess));
+    TRACE("UserRegisterUserApiHook. Server PID: %p\n", PsGetProcessId(pti->ppi->peProcess));
 
     /* Register the api hook */
     gpsi->dwSRVIFlags |= SRVINFO_APIHOOK;
@@ -222,7 +222,7 @@ UserUnregisterUserApiHook(VOID)
         return FALSE;
     }
 
-    ERR("UserUnregisterUserApiHook. Server PID: %d\n", PsGetProcessId(pti->ppi->peProcess));
+    TRACE("UserUnregisterUserApiHook. Server PID: %p\n", PsGetProcessId(pti->ppi->peProcess));
 
     /* Unregister the api hook */
     gpsi->dwSRVIFlags &= ~SRVINFO_APIHOOK;
@@ -295,7 +295,7 @@ co_IntCallLowLevelHook(PHOOK Hook,
 
     /* FIXME: Should get timeout from
      * HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */
-    Status = co_MsqSendMessage( pti->MessageQueue,
+    Status = co_MsqSendMessage( pti,
                                 IntToPtr(Code), // hWnd
                                 Hook->HookId,   // Msg
                                 wParam,
@@ -318,13 +318,13 @@ co_IntCallLowLevelHook(PHOOK Hook,
 // Dispatch MsgQueue Hook Call processor!
 //
 LRESULT
-FASTCALL
+APIENTRY
 co_CallHook( INT HookId,
              INT Code,
              WPARAM wParam,
              LPARAM lParam)
 {
-    LRESULT Result;
+    LRESULT Result = 0;
     PHOOK phk;
     PHOOKPACK pHP = (PHOOKPACK)lParam;
 
@@ -335,23 +335,27 @@ co_CallHook( INT HookId,
     {
        case WH_JOURNALPLAYBACK:
        case WH_JOURNALRECORD:
-       case WH_KEYBOARD:
        case WH_KEYBOARD_LL:
        case WH_MOUSE_LL:
        case WH_MOUSE:
           lParam = (LPARAM)pHP->pHookStructs;
+       case WH_KEYBOARD:
           break;
     }
 
+    if (!UserObjectInDestroy(UserHMGetHandle(phk))) //// Fix CORE-10549.
+    {
     /* The odds are high for this to be a Global call. */
     Result = co_IntCallHookProc( HookId,
                                  Code,
                                  wParam,
                                  lParam,
                                  phk->Proc,
+                                 phk->ihmod,
+                                 phk->offPfn,
                                  phk->Ansi,
                                 &phk->ModuleName);
-
+    }
     /* The odds so high, no one is waiting for the results. */
     if (pHP->pHookStructs) ExFreePoolWithTag(pHP->pHookStructs, TAG_HOOK);
     ExFreePoolWithTag(pHP, TAG_HOOK);
@@ -360,7 +364,7 @@ co_CallHook( INT HookId,
 
 static
 LRESULT
-FASTCALL
+APIENTRY
 co_HOOK_CallHookNext( PHOOK Hook,
                       INT Code,
                       WPARAM wParam,
@@ -373,6 +377,8 @@ co_HOOK_CallHookNext( PHOOK Hook,
                                wParam,
                                lParam,
                                Hook->Proc,
+                               Hook->ihmod,
+                               Hook->offPfn,
                                Hook->Ansi,
                               &Hook->ModuleName);
 }
@@ -512,7 +518,7 @@ co_IntCallDebugHook(PHOOK Hook,
 
 static
 LRESULT
-FASTCALL
+APIENTRY
 co_UserCallNextHookEx(PHOOK Hook,
                     int Code,
                     WPARAM wParam,
@@ -717,7 +723,8 @@ co_UserCallNextHookEx(PHOOK Hook,
 
                             if (!IS_ATOM(pcbtcww->lpcs->lpszClass))
                             {
-                               ProbeForRead( pcbtcww->lpcs->lpszClass,
+                                _Analysis_assume_(pcbtcww->lpcs->lpszClass != NULL);
+                                ProbeForRead(pcbtcww->lpcs->lpszClass,
                                              sizeof(CHAR),
                                              1);
                             }
@@ -736,7 +743,8 @@ co_UserCallNextHookEx(PHOOK Hook,
 
                             if (!IS_ATOM(pcbtcww->lpcs->lpszClass))
                             {
-                               ProbeForRead( pcbtcww->lpcs->lpszClass,
+                                _Analysis_assume_(pcbtcww->lpcs->lpszClass != NULL);
+                                ProbeForRead(pcbtcww->lpcs->lpszClass,
                                              sizeof(WCHAR),
                                              1);
                             }
@@ -937,7 +945,7 @@ IntGetHookObject(HHOOK hHook)
        return NULL;
     }
 
-    Hook = (PHOOK)UserGetObject(gHandleTable, hHook, otHook);
+    Hook = (PHOOK)UserGetObject(gHandleTable, hHook, TYPE_HOOK);
     if (!Hook)
     {
        EngSetLastError(ERROR_INVALID_HOOK_HANDLE);
@@ -965,15 +973,16 @@ IntGetGlobalHookHandles(PDESKTOP pdo, int HookId)
       ++cHooks;
 
     pList = ExAllocatePoolWithTag(PagedPool, (cHooks + 1) * sizeof(HHOOK), TAG_HOOK);
-    if(!pList)
+    if (!pList)
     {
         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
         return NULL;
-}
+    }
 
     for (pElem = pLastHead->Flink; pElem != pLastHead; pElem = pElem->Flink)
-{
+    {
         pHook = CONTAINING_RECORD(pElem, HOOK, Chain);
+        NT_ASSERT(i < cHooks);
         pList[i++] = pHook->head.h;
     }
     pList[i] = NULL;
@@ -1020,119 +1029,77 @@ IntFreeHook(PHOOK Hook)
        Hook->ModuleName.Buffer = NULL;
     }
     /* Close handle */
-    UserDeleteObject(UserHMGetHandle(Hook), otHook);
+    UserDeleteObject(UserHMGetHandle(Hook), TYPE_HOOK);
 }
 
 /* Remove a hook, freeing it from the chain */
-static
-VOID
-FASTCALL
-IntRemoveHook(PHOOK Hook)
+BOOLEAN
+IntRemoveHook(PVOID Object)
 {
     INT HookId;
-    PTHREADINFO pti;
+    PTHREADINFO ptiHook, pti;
     PDESKTOP pdo;
+    PHOOK Hook = Object;
+
+    NT_ASSERT(UserIsEnteredExclusive());
 
     HookId = Hook->HookId;
+    pti = PsGetCurrentThreadWin32Thread();
 
     if (Hook->ptiHooked) // Local
     {
-       pti = Hook->ptiHooked;
+        ptiHook = Hook->ptiHooked;
 
-       IntFreeHook( Hook);
+        IntFreeHook(Hook);
 
-       if ( IsListEmpty(&pti->aphkStart[HOOKID_TO_INDEX(HookId)]) )
-       {
-          pti->fsHooks &= ~HOOKID_TO_FLAG(HookId);
-          _SEH2_TRY
-          {
-             pti->pClientInfo->fsHooks = pti->fsHooks;
-          }
-          _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-          {
-          }
-          _SEH2_END;
+        if (IsListEmpty(&ptiHook->aphkStart[HOOKID_TO_INDEX(HookId)]))
+        {
+            BOOL bOtherProcess;
+            KAPC_STATE ApcState;
+
+            ptiHook->fsHooks &= ~HOOKID_TO_FLAG(HookId);
+            bOtherProcess = (ptiHook->ppi != pti->ppi);
+
+            if (bOtherProcess)
+                KeStackAttachProcess(&ptiHook->ppi->peProcess->Pcb, &ApcState);
+
+            _SEH2_TRY
+            {
+                ptiHook->pClientInfo->fsHooks = ptiHook->fsHooks;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Do nothing */
+                (void)0;
+            }
+            _SEH2_END;
+
+            if (bOtherProcess)
+                KeUnstackDetachProcess(&ApcState);
        }
     }
     else // Global
     {
-       IntFreeHook( Hook);
+        IntFreeHook(Hook);
 
-       pdo = IntGetActiveDesktop();
+        pdo = IntGetActiveDesktop();
 
-       if ( pdo &&
-            pdo->pDeskInfo &&
-            IsListEmpty(&pdo->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)]) )
-       {
-          pdo->pDeskInfo->fsHooks &= ~HOOKID_TO_FLAG(HookId);
-       }
+        if (pdo &&
+             pdo->pDeskInfo &&
+             IsListEmpty(&pdo->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)]))
+        {
+            pdo->pDeskInfo->fsHooks &= ~HOOKID_TO_FLAG(HookId);
+        }
     }
-}
 
-VOID
-FASTCALL
-HOOK_DestroyThreadHooks(PETHREAD Thread)
-{
-   PTHREADINFO pti;
-   PDESKTOP pdo;
-   int HookId;
-   PHOOK HookObj;
-   PLIST_ENTRY pElem;
-
-   pti = Thread->Tcb.Win32Thread;
-   pdo = IntGetActiveDesktop();
-
-   if (!pti || !pdo)
-   {
-      ERR("Kill Thread Hooks pti 0x%x pdo 0x%x\n",pti,pdo);
-      return;
-   }
-
-// Local Thread cleanup.
-   if (pti->fsHooks)
-   {
-      for (HookId = WH_MINHOOK; HookId <= WH_MAXHOOK; HookId++)
-      {
-         PLIST_ENTRY pLastHead = &pti->aphkStart[HOOKID_TO_INDEX(HookId)];
-
-         pElem = pLastHead->Flink;
-         while (pElem != pLastHead)
-         {
-            HookObj = CONTAINING_RECORD(pElem, HOOK, Chain);
-            pElem = HookObj->Chain.Flink; // get next element before hook is destroyed
-            IntRemoveHook(HookObj);
-         }
-      }
-      pti->fsHooks = 0;
-      pti->pClientInfo->fsHooks = 0;
-   }
-// Global search based on Thread and cleanup.
-   if (pdo->pDeskInfo->fsHooks)
-   {
-      for (HookId = WH_MINHOOK; HookId <= WH_MAXHOOK; HookId++)
-      {
-         PLIST_ENTRY pGLE = &pdo->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)];
-
-         pElem = pGLE->Flink;
-         while (pElem != pGLE)
-         {
-            HookObj = CONTAINING_RECORD(pElem, HOOK, Chain);
-            pElem = HookObj->Chain.Flink; // Get next element before hook is destroyed
-            if (HookObj->head.pti == pti)
-            {
-               IntRemoveHook(HookObj);
-            }
-         }
-      }
-   }
-   return;
+    return TRUE;
 }
 
 /*
   Win32k Kernel Space Hook Caller.
  */
 LRESULT
-FASTCALL
+APIENTRY
 co_HOOK_CallHooks( INT HookId,
                    INT Code,
                    WPARAM wParam,
@@ -1202,6 +1169,8 @@ co_HOOK_CallHooks( INT HookId,
        }
 
        Hook = CONTAINING_RECORD(pLastHead->Flink, HOOK, Chain);
+       ObReferenceObject(pti->pEThread);
+       IntReferenceThreadInfo(pti);
        UserRefObjectCo(Hook, &Ref);
 
        ClientInfo = pti->pClientInfo;
@@ -1231,6 +1200,8 @@ co_HOOK_CallHooks( INT HookId,
                                     wParam,
                                     lParam,
                                     Hook->Proc,
+                                    Hook->ihmod,
+                                    Hook->offPfn,
                                     Hook->Ansi,
                                    &Hook->ModuleName);
        if (ClientInfo)
@@ -1241,12 +1212,16 @@ co_HOOK_CallHooks( INT HookId,
           }
           _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
           {
+              /* Do nothing */
+              (void)0;
           }
           _SEH2_END;
        }
        pti->sphkCurrent = SaveHook;
        Hook->phkNext = NULL;
        UserDerefObjectCo(Hook);
+       IntDereferenceThreadInfo(pti);
+       ObDereferenceObject(pti->pEThread);
     }
 
     if ( Global )
@@ -1266,22 +1241,22 @@ co_HOOK_CallHooks( INT HookId,
        */
        for(i = 0; pHookHandles[i]; ++i)
        {
-          Hook = (PHOOK)UserGetObject(gHandleTable, pHookHandles[i], otHook);
+          Hook = (PHOOK)UserGetObject(gHandleTable, pHookHandles[i], TYPE_HOOK);
           if(!Hook)
           {
               ERR("Invalid hook!\n");
               continue;
           }
-          UserRefObjectCo(Hook, &Ref);
 
          /* Hook->Thread is null, we hax around this with Hook->head.pti. */
           ptiHook = Hook->head.pti;
 
           if ( (pti->TIF_flags & TIF_DISABLEHOOKS) || (ptiHook->TIF_flags & TIF_INCLEANUP))
           {
-             TRACE("Next Hook 0x%x, 0x%x\n",ptiHook->rpdesk,pdo);
+             TRACE("Next Hook %p, %p\n", ptiHook->rpdesk, pdo);
              continue;
           }
+          UserRefObjectCo(Hook, &Ref);
 
           if (ptiHook != pti )
           {
@@ -1296,17 +1271,40 @@ co_HOOK_CallHooks( INT HookId,
                 TRACE("\nGlobal Hook posting to another Thread! %d\n",HookId );
                 Result = co_IntCallLowLevelHook(Hook, Code, wParam, lParam);
              }
+             else if (ptiHook->ppi == pti->ppi)
+             {
+                TRACE("\nGlobal Hook calling to another Thread! %d\n",HookId );
+                ObReferenceObject(ptiHook->pEThread);
+                IntReferenceThreadInfo(ptiHook);
+                Result = co_IntCallHookProc( HookId,
+                                             Code,
+                                             wParam,
+                                             lParam,
+                                             Hook->Proc,
+                                             Hook->ihmod,
+                                             Hook->offPfn,
+                                             Hook->Ansi,
+                                            &Hook->ModuleName);
+                IntDereferenceThreadInfo(ptiHook);
+                ObDereferenceObject(ptiHook->pEThread);
+             }
           }
           else
           { /* Make the direct call. */
-             TRACE("Local Hook calling to Thread! %d\n",HookId );
+             TRACE("Global going Local Hook calling to Thread! %d\n",HookId );
+             ObReferenceObject(pti->pEThread);
+             IntReferenceThreadInfo(pti);
              Result = co_IntCallHookProc( HookId,
                                           Code,
                                           wParam,
                                           lParam,
                                           Hook->Proc,
+                                          Hook->ihmod,
+                                          Hook->offPfn,
                                           Hook->Ansi,
                                          &Hook->ModuleName);
+             IntDereferenceThreadInfo(pti);
+             ObDereferenceObject(pti->pEThread);
           }
           UserDerefObjectCo(Hook);
        }
@@ -1340,12 +1338,14 @@ IntUnhookWindowsHook(int HookId, HOOKPROC pfnFilterProc)
        {
           Hook = CONTAINING_RECORD(pElement, HOOK, Chain);
 
+          /* Get the next element now, we might free the hook in what follows */
+          pElement = Hook->Chain.Flink;
+
           if (Hook->Proc == pfnFilterProc)
           {
              if (Hook->head.pti == pti)
              {
                 IntRemoveHook(Hook);
-                UserDereferenceObject(Hook);
                 return TRUE;
              }
              else
@@ -1354,8 +1354,6 @@ IntUnhookWindowsHook(int HookId, HOOKPROC pfnFilterProc)
                 return FALSE;
              }
           }
-
-          pElement = Hook->Chain.Flink;
        }
     }
     return FALSE;
@@ -1448,11 +1446,10 @@ NtUserSetWindowsHookEx( HINSTANCE Mod,
                         BOOL Ansi)
 {
     PWINSTATION_OBJECT WinStaObj;
-    PHOOK Hook;
+    PHOOK Hook = NULL;
     UNICODE_STRING ModuleName;
     NTSTATUS Status;
     HHOOK Handle;
-    PETHREAD Thread = NULL;
     PTHREADINFO pti, ptiHook = NULL;
     DECLARE_RETURN(HHOOK);
 
@@ -1481,21 +1478,19 @@ NtUserSetWindowsHookEx( HINSTANCE Mod,
             HookId == WH_MOUSE_LL ||
             HookId == WH_SYSMSGFILTER)
        {
-           ERR("Local hook installing Global HookId: %d\n",HookId);
+           TRACE("Local hook installing Global HookId: %d\n",HookId);
            /* these can only be global */
            EngSetLastError(ERROR_GLOBAL_ONLY_HOOK);
            RETURN( NULL);
        }
 
-       if (!NT_SUCCESS(PsLookupThreadByThreadId((HANDLE)(DWORD_PTR) ThreadId, &Thread)))
+       if ( !(ptiHook = IntTID2PTI( UlongToHandle(ThreadId) )))
        {
           ERR("Invalid thread id 0x%x\n", ThreadId);
           EngSetLastError(ERROR_INVALID_PARAMETER);
           RETURN( NULL);
        }
 
-       ptiHook = Thread->Tcb.Win32Thread;
-
        if ( ptiHook->rpdesk != pti->rpdesk) // gptiCurrent->rpdesk)
        {
           ERR("Local hook wrong desktop HookId: %d\n",HookId);
@@ -1503,7 +1498,7 @@ NtUserSetWindowsHookEx( HINSTANCE Mod,
           RETURN( NULL);
        }
 
-       if (Thread->ThreadsProcess != PsGetCurrentProcess())
+       if (ptiHook->ppi != pti->ppi)
        {
           if ( !Mod &&
               (HookId == WH_GETMESSAGE ||
@@ -1556,9 +1551,10 @@ NtUserSetWindowsHookEx( HINSTANCE Mod,
     }
 
     Status = IntValidateWindowStationHandle( PsGetCurrentProcess()->Win32WindowStation,
-                                             KernelMode,
+                                             UserMode,
                                              0,
-                                            &WinStaObj);
+                                            &WinStaObj,
+                                             0);
 
     if (!NT_SUCCESS(Status))
     {
@@ -1567,21 +1563,21 @@ NtUserSetWindowsHookEx( HINSTANCE Mod,
     }
     ObDereferenceObject(WinStaObj);
 
-    Hook = UserCreateObject(gHandleTable, NULL, NULL, (PHANDLE)&Handle, otHook, sizeof(HOOK));
+    Hook = UserCreateObject(gHandleTable, NULL, ptiHook, (PHANDLE)&Handle, TYPE_HOOK, sizeof(HOOK));
 
     if (!Hook)
     {
        RETURN( NULL);
     }
 
-    Hook->ihmod   = (INT)Mod; // Module Index from atom table, Do this for now.
+    Hook->ihmod   = (INT_PTR)Mod; // Module Index from atom table, Do this for now.
     Hook->HookId  = HookId;
     Hook->rpdesk  = ptiHook->rpdesk;
     Hook->phkNext = NULL; /* Dont use as a chain! Use link lists for chaining. */
     Hook->Proc    = HookProc;
     Hook->Ansi    = Ansi;
 
-    TRACE("Set Hook Desk 0x%x DeskInfo 0x%x Handle Desk 0x%x\n",pti->rpdesk, pti->pDeskInfo,Hook->head.rpdesk);
+    TRACE("Set Hook Desk %p DeskInfo %p Handle Desk %p\n", pti->rpdesk, pti->pDeskInfo, Hook->head.rpdesk);
 
     if (ThreadId)  /* Thread-local hook */
     {
@@ -1607,7 +1603,9 @@ NtUserSetWindowsHookEx( HINSTANCE Mod,
           }
           else
           {
-             KeAttachProcess(&ptiHook->ppi->peProcess->Pcb);
+             KAPC_STATE ApcState;
+
+             KeStackAttachProcess(&ptiHook->ppi->peProcess->Pcb, &ApcState);
              _SEH2_TRY
              {
                 ptiHook->pClientInfo->fsHooks = ptiHook->fsHooks;
@@ -1618,7 +1616,7 @@ NtUserSetWindowsHookEx( HINSTANCE Mod,
                 ERR("Problem writing to Remote ClientInfo!\n");
              }
              _SEH2_END;
-             KeDetachProcess();
+             KeUnstackDetachProcess(&ApcState);
           }
        }
     }
@@ -1670,6 +1668,9 @@ NtUserSetWindowsHookEx( HINSTANCE Mod,
        }
 
        Hook->ModuleName.Length = ModuleName.Length;
+       //// FIXME: Need to load from user32 to verify hMod before calling hook with hMod set!!!!
+       //// Mod + offPfn == new HookProc Justin Case module is from another process.
+       FIXME("NtUserSetWindowsHookEx Setting process hMod instance addressing.\n");
        /* Make proc relative to the module base */
        Hook->offPfn = (ULONG_PTR)((char *)HookProc - (char *)Mod);
     }
@@ -1680,8 +1681,9 @@ NtUserSetWindowsHookEx( HINSTANCE Mod,
     RETURN( Handle);
 
 CLEANUP:
-    TRACE("Leave NtUserSetWindowsHookEx, ret=%i\n",_ret_);
-    if (Thread) ObDereferenceObject(Thread);
+    if (Hook)
+        UserDereferenceObject(Hook);
+    TRACE("Leave NtUserSetWindowsHookEx, ret=%p\n", _ret_);
     UserLeave();
     END_CLEANUP;
 }