|
|
/****************************** Module Header ******************************\
* Module Name: validate.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * This module contains functions for validating windows, menus, cursors, etc. * * History: * 01-02-91 DarrinM Created. \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/*
* These defines are used for using the validation macros * StartValidateHandleMacro and EndValidateHandleMacro. */ #define ClientSharedInfo() (&gSharedInfo)
#define ServerInfo() (gpsi)
#include "wow.h"
#if DBG
CRITSTACK gCritStack; #endif
#ifdef USER_PERFORMANCE
__int64 gCSTimeExclusiveWhenEntering; #endif
/***************************************************************************\
* ValidateHwinsta * * Validate windowstation handle * * History: * 03-29-91 JimA Created. * 06-20-95 JimA Kernel-mode objects. \***************************************************************************/ NTSTATUS ValidateHwinsta( HWINSTA hwinsta, KPROCESSOR_MODE AccessMode, ACCESS_MASK amDesired, PWINDOWSTATION *ppwinsta) { NTSTATUS Status;
Status = ObReferenceObjectByHandle(hwinsta, amDesired, *ExWindowStationObjectType, AccessMode, ppwinsta, NULL); if (!NT_SUCCESS(Status)) { RIPNTERR1(Status, RIP_WARNING, "ValidateHwinsta failed for 0x%p", hwinsta); } else if ((*ppwinsta)->dwSessionId != gSessionId) { RIPNTERR3(STATUS_INVALID_HANDLE, RIP_WARNING, "SessionId %d does not match id %d for pwinsta 0x%p", gSessionId, (*ppwinsta)->dwSessionId, *ppwinsta);
ObDereferenceObject(*ppwinsta); return STATUS_INVALID_HANDLE; }
return Status; }
/***************************************************************************\
* ValidateHdesk * * Validate desktop handle * * History: * 03-29-91 JimA Created. * 06-20-95 JimA Kernel-mode objects. \***************************************************************************/
NTSTATUS ValidateHdesk( HDESK hdesk, KPROCESSOR_MODE AccessMode, ACCESS_MASK amDesired, PDESKTOP* ppdesk) { NTSTATUS Status;
Status = ObReferenceObjectByHandle(hdesk, amDesired, *ExDesktopObjectType, AccessMode, ppdesk, NULL); if (NT_SUCCESS(Status)) { if ((*ppdesk)->dwSessionId != gSessionId) { RIPNTERR3(STATUS_INVALID_HANDLE, RIP_WARNING, "SessionId %d does not match id %d for pdesk 0x%p", gSessionId, (*ppdesk)->dwSessionId, *ppdesk);
goto Error; }
LogDesktop(*ppdesk, LDL_VALIDATE_HDESK, TRUE, (ULONG_PTR)PtiCurrent());
if ((*ppdesk)->dwDTFlags & (DF_DESTROYED | DF_DESKWNDDESTROYED | DF_DYING)) { RIPNTERR1(STATUS_INVALID_HANDLE, RIP_WARNING, "ValidateHdesk: destroyed desktop 0x%p", *ppdesk); Error: ObDereferenceObject(*ppdesk);
return STATUS_INVALID_HANDLE; } } else { RIPNTERR1(Status, RIP_WARNING, "ValidateHdesk failed for 0x%p", hdesk); }
return Status; }
/***************************************************************************\
* UserValidateCopyRgn * * Validates a region-handle. This essentially tries to copy the region * in order to verify the region is valid. If hrgn isn't a valid region, * then the combine will fail. We return a copy of the region. * * History: * 24=Jan-1996 ChrisWil Created. \***************************************************************************/ HRGN UserValidateCopyRgn( HRGN hrgn) { HRGN hrgnCopy = NULL;
if (hrgn && (GreValidateServerHandle(hrgn, RGN_TYPE))) { hrgnCopy = CreateEmptyRgn();
if (CopyRgn(hrgnCopy, hrgn) == ERROR) { GreDeleteObject(hrgnCopy); hrgnCopy = NULL; } }
return hrgnCopy; }
/***************************************************************************\
* ValidateHmenu * * Validate menu handle and open it. * * History: * 03-29-91 JimA Created. \***************************************************************************/ PMENU ValidateHmenu( HMENU hmenu) { PTHREADINFO pti = PtiCurrentShared(); PMENU pmenuRet;
pmenuRet = (PMENU)HMValidateHandle(hmenu, TYPE_MENU);
if (pmenuRet != NULL && pmenuRet->head.rpdesk != pti->rpdesk) { RIPERR1(ERROR_INVALID_MENU_HANDLE, RIP_WARNING, "Invalid menu handle 0x%p", hmenu); return NULL; }
return pmenuRet; }
/***************************************************************************\
* ValidateHmonitor * * Validate monitor handle and open it. * * History: * 03-29-91 JimA Created. \***************************************************************************/ PMONITOR ValidateHmonitor( HMONITOR hmonitor) { return (PMONITOR)HMValidateSharedHandle(hmonitor, TYPE_MONITOR); }
/*
* The handle validation routines should be optimized for time, not size, * since they get called so often. */ #pragma optimize("t", on)
/***************************************************************************\
* IsHandleEntrySecure * * Validate a user handle for a restricted process bypassing the routine to * get the handle entry. * * History: * August 22, 97 CLupu Created. \***************************************************************************/ BOOL IsHandleEntrySecure( HANDLE h, PHE phe) { DWORD bCreateFlags; PPROCESSINFO ppiOwner; PPROCESSINFO ppiCurrent; PW32JOB pW32Job; DWORD ind; PULONG_PTR pgh;
ppiCurrent = PpiCurrent(); if (ppiCurrent == NULL) { return TRUE; }
UserAssert(ppiCurrent->pW32Job != NULL); UserAssert(ppiCurrent->W32PF_Flags & W32PF_RESTRICTED);
/*
* Get the process that owns the handle. */
bCreateFlags = gahti[phe->bType].bObjectCreateFlags;
ppiOwner = NULL;
if (bCreateFlags & OCF_PROCESSOWNED) { ppiOwner = (PPROCESSINFO)phe->pOwner; } else if (bCreateFlags & OCF_THREADOWNED) { PTHREADINFO pti = (PTHREADINFO)phe->pOwner;
if (pti != NULL) { ppiOwner = pti->ppi; } }
/*
* If the owner is NULL then consider the handle secure. */ if (ppiOwner == NULL) { return FALSE; }
/*
* If the handle is owned by a process in the same job, then it's secure. */ if (ppiOwner->pW32Job == ppiCurrent->pW32Job) { return TRUE; }
/*
* The handle is not owned by the current process. */ pW32Job = ppiCurrent->pW32Job; if (pW32Job->pgh == NULL) { return FALSE; }
pgh = pW32Job->pgh;
UserAssert(pW32Job->ughCrt <= pW32Job->ughMax);
for (ind = 0; ind < pW32Job->ughCrt; ind++) { if (*(pgh + ind) == (ULONG_PTR)h) { return TRUE; } }
return FALSE; }
/***************************************************************************\
* ValidateHandleSecure * * Validate a user handle for a restricted process. * * History: * July 29, 97 CLupu Created. \***************************************************************************/ BOOL ValidateHandleSecure( HANDLE h) { PVOID pobj;
CheckCritInShared();
StartValidateHandleMacro(h) BeginTypeValidateHandleMacro(pobj, TYPE_GENERIC)
if (IsHandleEntrySecure(h, phe)) { return TRUE; }
EndTypeValidateHandleMacro EndValidateHandleMacro
return FALSE; }
/***************************************************************************\
* ValidateHwnd * * History: * 08-Feb-1991 mikeke \***************************************************************************/ PWND FASTCALL ValidateHwnd( HWND hwnd) { StartValidateHandleMacro(hwnd)
/*
* Now make sure the app is passing the right handle type for this * api. If the handle is TYPE_FREE, this'll catch it. */ if (phe->bType == TYPE_WINDOW) { PTHREADINFO pti = PtiCurrentShared(); PWND pwndRet = (PWND)phe->phead;
/*
* This test establishes that the window belongs to the current * 'desktop'.. The two exceptions are for the desktop-window of * the current desktop, which ends up belonging to another desktop, * and when pti->rpdesk is NULL. This last case happens for * initialization of TIF_SYSTEMTHREAD threads (ie. console windows). * IanJa doesn't know if we should be test TIF_CSRSSTHREAD here, but * JohnC thinks the whole test below is no longer required ??? LATER */
if (pwndRet != NULL) { if (phe->bFlags & HANDLEF_DESTROY) { RIPERR2(ERROR_INVALID_WINDOW_HANDLE, RIP_WARNING,"ValidateHwnd, hwnd %#p, pwnd %#p already destroyed\n", hwnd, pwndRet); return NULL; } if (GETPTI(pwndRet) == pti || ( (pwndRet->head.rpdesk == pti->rpdesk || (pti->TIF_flags & TIF_SYSTEMTHREAD) || // | TIF_CSRSSTHREAD I think
GetDesktopView(pti->ppi, pwndRet->head.rpdesk) != NULL))) {
if (IS_THREAD_RESTRICTED(pti, JOB_OBJECT_UILIMIT_HANDLES)) {
/*
* make sure this window belongs to this process */ if (!IsHandleEntrySecure(hwnd, phe)) { RIPERR1(ERROR_INVALID_WINDOW_HANDLE, RIP_WARNING, "ValidateHwnd: Invalid hwnd (%#p) for restricted process\n", hwnd); pwndRet = NULL; } } return pwndRet; } } }
EndValidateHandleMacro
RIPERR1(ERROR_INVALID_WINDOW_HANDLE, RIP_WARNING, "ValidateHwnd: Invalid hwnd (%#p)", hwnd); return NULL; }
/*
* Switch back to default optimization. */ #pragma optimize("", on)
/******************************Public*Routine******************************\
* * UserCritSec routines * * Exposes an opaque interface to the user critical section for * the WNDOBJ code in GRE * * Exposed as functions because they aren't time critical and it * insulates GRE from rebuilding if the definitions of Enter/LeaveCrit change * * History: * Wed Sep 20 11:19:14 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/
#if DBG
#define GetCallStack() \
{ \ gCritStack.thread = PsGetCurrentThread(); \ gCritStack.nFrames = RtlWalkFrameChain(gCritStack.trace, \ MAX_STACK_CALLS, \ 0); \ }
#define FlushCallStack() \
{ \ gCritStack.thread = NULL; \ gCritStack.nFrames = 0; \ } #else
#define GetCallStack()
#define FlushCallStack()
#endif // DBG
VOID UserEnterUserCritSec( VOID) { EnterCrit(); }
VOID UserLeaveUserCritSec( VOID) { LeaveCrit(); }
#if DBG
VOID UserAssertUserCritSecIn( VOID) { _AssertCritInShared(); }
VOID UserAssertUserCritSecOut( VOID) { _AssertCritOut(); } #endif // DBG
BOOL UserGetCurrentDesktopId( DWORD* pdwDesktopId) { PDESKTOP pdesktop;
CheckCritIn();
/*
* PtiCurrent()->rpdesk can be NULL (in the case of thread shutdown). */
pdesktop = PtiCurrent()->rpdesk;
if (pdesktop != grpdeskRitInput) { RIPMSG0(RIP_WARNING, "UserGetCurrentDesktopId on wrong desktop pdesk\n"); return FALSE; }
*pdwDesktopId = pdesktop->dwDesktopId;
return TRUE; }
#if 0
//
// Temporary arrays used to track critsec frees
//
#define ARRAY_SIZE 20
#define LEAVE_TYPE 0xf00d0000
#define ENTER_TYPE 0x0000dead
typedef struct _DEBUG_STASHCS { RTL_CRITICAL_SECTION Lock; DWORD Type; } DEBUG_STASHCS, *PDEBUG_STASHCS;
DEBUG_STASHCS UserSrvArray[ARRAY_SIZE];
ULONG UserSrvIndex;
VOID DumpArray( HANDLE hCurrentProcess, HANDLE hCurrentThread, DWORD dwCurrentPc, PNTSD_EXTENSION_APIS lpExtensionApis, LPSTR lpArgumentString, LPDWORD IndexAddress, LPDWORD ArrayAddress ) { PNTSD_OUTPUT_ROUTINE Print; PNTSD_GET_EXPRESSION EvalExpression; PNTSD_GET_SYMBOL GetSymbol;
DWORD History; int InitialIndex; PDEBUG_STASHCS Array; BOOL b; PRTL_CRITICAL_SECTION CriticalSection; CHAR Symbol[64], Symbol2[64]; DWORD Displacement, Displacement2; int Position; LPSTR p;
DBG_UNREFERENCED_PARAMETER(hCurrentThread); DBG_UNREFERENCED_PARAMETER(dwCurrentPc);
Print = lpExtensionApis->lpOutputRoutine; EvalExpression = lpExtensionApis->lpGetExpressionRoutine; GetSymbol = lpExtensionApis->lpGetSymbolRoutine;
p = lpArgumentString;
History = 0;
if (*p) { History = EvalExpression(p); } if (History == 0 || History >= ARRAY_SIZE) { History = 10; }
//
// Get the Current Index and the array.
//
b = ReadProcessMemory( hCurrentProcess, (LPVOID)IndexAddress, &InitialIndex, sizeof(InitialIndex), NULL ); if (!b) { return; }
Array = RtlAllocateHeap(RtlProcessHeap(), 0, sizeof(UserSrvArray)); if (!Array) { return; }
b = ReadProcessMemory( hCurrentProcess, (LPVOID)ArrayAddress, Array, sizeof(UserSrvArray), NULL ); if (!b) { RtlFreeHeap(RtlProcessHeap(), 0, Array); return; }
Position = 0; while (History) { InitialIndex--; if (InitialIndex < 0) { InitialIndex = ARRAY_SIZE - 1; }
if (Array[InitialIndex].Type == LEAVE_TYPE) { (Print)("\n(%d) LEAVING Critical Section \n", Position); } else { (Print)("\n(%d) ENTERING Critical Section \n", Position); }
CriticalSection = &Array[InitialIndex].Lock;
if (CriticalSection->LockCount == -1) { (Print)("\tLockCount NOT LOCKED\n"); } else { (Print)("\tLockCount %ld\n", CriticalSection->LockCount); } (Print)("\tRecursionCount %ld\n", CriticalSection->RecursionCount); (Print)("\tOwningThread %lx\n", CriticalSection->OwningThread ); #if DBG
(GetSymbol)(CriticalSection->OwnerBackTrace[0], Symbol, &Displacement); (GetSymbol)(CriticalSection->OwnerBackTrace[1], Symbol2, &Displacement2); (Print)("\tCalling Address %s+%lx\n", Symbol, Displacement); (Print)("\tCallers Caller %s+%lx\n", Symbol2, Displacement2); #endif // DBG
Position--; History--; } RtlFreeHeap(RtlProcessHeap(), 0, Array); }
VOID dsrv( HANDLE hCurrentProcess, HANDLE hCurrentThread, DWORD dwCurrentPc, PNTSD_EXTENSION_APIS lpExtensionApis, LPSTR lpArgumentString ) { DumpArray( hCurrentProcess, hCurrentThread, dwCurrentPc, lpExtensionApis, lpArgumentString, &UserSrvIndex, (LPDWORD)&UserSrvArray[0] ); }
#endif // if 0
#if DBG
/***************************************************************************\
* _EnterCrit * _LeaveCrit * * These are temporary routines that are used by USER.DLL until the critsect, * validation, mapping code is moved to the server-side stubs generated by * SMeans' Thank compiler. * * History: * 01-02-91 DarrinM Created. \***************************************************************************/ VOID _AssertCritIn( VOID) { UserAssert(gpresUser != NULL); UserAssert(ExIsResourceAcquiredExclusiveLite(gpresUser) == TRUE); }
VOID _AssertDeviceInfoListCritIn( VOID) { UserAssert(gpresDeviceInfoList != NULL); UserAssert(ExIsResourceAcquiredExclusiveLite(gpresDeviceInfoList) == TRUE); }
VOID _AssertCritInShared( VOID) { UserAssert(gpresUser != NULL); UserAssert( (ExIsResourceAcquiredExclusiveLite(gpresUser) == TRUE) || (ExIsResourceAcquiredSharedLite(gpresUser) == TRUE)); }
VOID _AssertCritOut( VOID) { UserAssert(gpresUser != NULL); UserAssert(ExIsResourceAcquiredExclusiveLite(gpresUser) == FALSE); }
VOID _AssertDeviceInfoListCritOut( VOID) { UserAssert(gpresDeviceInfoList != NULL); UserAssert(ExIsResourceAcquiredExclusiveLite(gpresDeviceInfoList) == FALSE); }
/***************************************************************************\
* BeginAtomicCheck() * EndAtomicCheck() * * Routine that verify we never leave the critical section and that an * operation is truely atomic with the possiblity of other code being run * because we left the critical section * \***************************************************************************/ VOID BeginAtomicCheck( VOID) { gdwInAtomicOperation++; }
VOID EndAtomicCheck( VOID) { UserAssert(gdwInAtomicOperation > 0); gdwInAtomicOperation--; }
VOID BeginAtomicDeviceInfoListCheck( VOID) { gdwInAtomicDeviceInfoListOperation++; }
VOID EndAtomicDeviceInfoListCheck( VOID) { UserAssert(gdwInAtomicDeviceInfoListOperation > 0); gdwInAtomicDeviceInfoListOperation--; }
#define INCCRITSECCOUNT (gdwCritSecUseCount++)
#define INCDEVICEINFOLISTCRITSECCOUNT (gdwDeviceInfoListCritSecUseCount++)
#else // else DBG
#define INCCRITSECCOUNT
#define INCDEVICEINFOLISTCRITSECCOUNT
#endif // endif DBG
BOOL UserIsUserCritSecIn( VOID) { UserAssert(gpresUser != NULL); return ((ExIsResourceAcquiredExclusiveLite(gpresUser) == TRUE) || (ExIsResourceAcquiredSharedLite(gpresUser) == TRUE)); }
#if DBG
VOID CheckDevLockOut( VOID) { /*
* gpDispInfo can be NULL if Win32UserInitialize fails before allocating * it. hDev is initialized later in InitVideo, after the critical * section has been released at least once, so we better check it too. */ if (gpDispInfo != NULL && gpDispInfo->hDev != NULL) { UserAssert(!GreIsDisplayLocked(gpDispInfo->hDev)); } } #else
#define CheckDevLockOut()
#endif
VOID EnterCrit( VOID) { CheckCritOut(); CheckDeviceInfoListCritOut(); KeEnterCriticalRegion(); ExAcquireResourceExclusiveLite(gpresUser, TRUE); CheckDevLockOut(); UserAssert(!ISATOMICCHECK()); UserAssert(gptiCurrent == NULL); gptiCurrent = ((PTHREADINFO)(W32GetCurrentThread())); INCCRITSECCOUNT; #if defined (USER_PERFORMANCE)
{ __int64 i64Frecv; *(LARGE_INTEGER*)(&gCSTimeExclusiveWhenEntering) = KeQueryPerformanceCounter((LARGE_INTEGER*)&i64Frecv); InterlockedIncrement(&gCSStatistics.cExclusive); } #endif // (USER_PERFORMANCE)
GetCallStack(); }
#if DBG
VOID EnterDeviceInfoListCrit( VOID) { CheckDeviceInfoListCritOut(); KeEnterCriticalRegion(); ExAcquireResourceExclusiveLite(gpresDeviceInfoList, TRUE); UserAssert(!ISATOMICDEVICEINFOLISTCHECK()); INCDEVICEINFOLISTCRITSECCOUNT; } #endif // DBG
VOID EnterSharedCrit( VOID) { KeEnterCriticalRegion(); ExAcquireResourceSharedLite(gpresUser, TRUE); CheckDevLockOut(); UserAssert(!ISATOMICCHECK()); #if defined (USER_PERFORMANCE)
InterlockedIncrement(&gCSStatistics.cShared); #endif // (USER_PERFORMANCE)
INCCRITSECCOUNT; }
VOID LeaveCrit( VOID) { INCCRITSECCOUNT; #if DBG
UserAssert(!ISATOMICCHECK()); UserAssert(IsWinEventNotifyDeferredOK()); CheckDevLockOut(); FlushCallStack(); gptiCurrent = NULL; #endif // DBG
#ifdef USER_PERFORMANCE
/*
* A non null gCSTimeExclusiveWhenEntering means the * critical section is owned exclusive */ if (gCSTimeExclusiveWhenEntering) { __int64 i64Temp, i64Frecv;
*(LARGE_INTEGER*)(&i64Temp) = KeQueryPerformanceCounter((LARGE_INTEGER*)&i64Frecv); gCSStatistics.i64TimeExclusive += i64Temp - gCSTimeExclusiveWhenEntering; gCSTimeExclusiveWhenEntering = 0; } #endif // USER_PERFORMANCE
ExReleaseResourceLite(gpresUser); KeLeaveCriticalRegion(); CheckCritOut(); }
#if DBG
VOID _LeaveDeviceInfoListCrit( VOID) { INCDEVICEINFOLISTCRITSECCOUNT; UserAssert(!ISATOMICDEVICEINFOLISTCHECK());
ExReleaseResourceLite(gpresDeviceInfoList); KeLeaveCriticalRegion(); CheckDeviceInfoListCritOut(); } #endif // DBG
VOID ChangeAcquireResourceType( VOID) {
#if DBG
FlushCallStack(); CheckDevLockOut(); UserAssert(!ISATOMICCHECK()); #endif // DBG
ExReleaseResourceLite(gpresUser); ExAcquireResourceExclusiveLite(gpresUser, TRUE); gptiCurrent = ((PTHREADINFO)(W32GetCurrentThread()));
GetCallStack(); }
#if DBG
PTHREADINFO _ptiCrit( VOID) { UserAssert(gpresUser); UserAssert(ExIsResourceAcquiredExclusiveLite(gpresUser) == TRUE); UserAssert(gptiCurrent); UserAssert(gptiCurrent == ((PTHREADINFO)(W32GetCurrentThread()))); UserAssert(gptiCurrent);
return gptiCurrent; }
PTHREADINFO _ptiCritShared( VOID) { UserAssert(W32GetCurrentThread()); return ((PTHREADINFO)(W32GetCurrentThread())); }
#undef KeUserModeCallback
NTSTATUS _KeUserModeCallback ( IN ULONG ApiNumber, IN PVOID InputBuffer, IN ULONG InputLength, OUT PVOID *OutputBuffer, OUT PULONG OutputLength) {
UserAssert(ExIsResourceAcquiredExclusiveLite(gpresUser) == FALSE);
/*
* Added this so we can detect an erroneous user mode callback * with a checked win32k on top of a free system. */ UserAssert(PsGetCurrentThreadPreviousMode() == UserMode);
return KeUserModeCallback(ApiNumber, InputBuffer, InputLength, OutputBuffer, OutputLength); }
#endif // DBG
|