[ntoskrnl]

- Implement calling OkayToCloseProcedure callouts to win32k for desktop and window station objects
- Fix a bug that caused ObpCloseHandle to return success even when OkayToCloseProcedure failed

[win32k]
- Rewrite SetProcessWindowStation to actually set the current window station and close the previous one
- Implement OkayToCloseProcedure callouts from the kernel to prevent closing the current desktop or window station

svn path=/trunk/; revision=51115
This commit is contained in:
Giannis Adamopoulos 2011-03-22 09:19:26 +00:00
parent eb3ddf59b3
commit 8cf95d1319
9 changed files with 154 additions and 48 deletions

View file

@ -37,10 +37,46 @@ GENERIC_MAPPING ExpDesktopMapping =
PKWIN32_PARSEMETHOD_CALLOUT ExpWindowStationObjectParse = NULL;
PKWIN32_DELETEMETHOD_CALLOUT ExpWindowStationObjectDelete = NULL;
PKWIN32_OKTOCLOSEMETHOD_CALLOUT ExpWindowStationObjectOkToClose = NULL;
PKWIN32_OKTOCLOSEMETHOD_CALLOUT ExpDesktopObjectOkToClose = NULL;
PKWIN32_DELETEMETHOD_CALLOUT ExpDesktopObjectDelete = NULL;
/* FUNCTIONS ****************************************************************/
NTSTATUS
NTAPI
ExpDesktopOkToClose( IN PEPROCESS Process OPTIONAL,
IN PVOID Object,
IN HANDLE Handle,
IN KPROCESSOR_MODE AccessMode)
{
WIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters;
Parameters.Process = Process;
Parameters.Object = Object;
Parameters.Handle = Handle;
Parameters.PreviousMode = AccessMode;
return ExpDesktopObjectOkToClose(&Parameters);
}
NTSTATUS
NTAPI
ExpWindowStationOkToClose( IN PEPROCESS Process OPTIONAL,
IN PVOID Object,
IN HANDLE Handle,
IN KPROCESSOR_MODE AccessMode)
{
WIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters;
Parameters.Process = Process;
Parameters.Object = Object;
Parameters.Handle = Handle;
Parameters.PreviousMode = AccessMode;
return ExpWindowStationObjectOkToClose(&Parameters);
}
VOID
NTAPI
ExpWinStaObjectDelete(PVOID DeletedObject)
@ -114,6 +150,7 @@ ExpWin32kInit(VOID)
ObjectTypeInitializer.PoolType = NonPagedPool;
ObjectTypeInitializer.DeleteProcedure = ExpWinStaObjectDelete;
ObjectTypeInitializer.ParseProcedure = ExpWinStaObjectParse;
ObjectTypeInitializer.OkayToCloseProcedure = ExpWindowStationOkToClose;
ObCreateObjectType(&Name,
&ObjectTypeInitializer,
NULL,
@ -124,6 +161,7 @@ ExpWin32kInit(VOID)
ObjectTypeInitializer.GenericMapping = ExpDesktopMapping;
ObjectTypeInitializer.DeleteProcedure = ExpDesktopDelete;
ObjectTypeInitializer.ParseProcedure = NULL;
ObjectTypeInitializer.OkayToCloseProcedure = ExpDesktopOkToClose;
ObCreateObjectType(&Name,
&ObjectTypeInitializer,
NULL,

View file

@ -1752,7 +1752,6 @@ ObpCloseHandle(IN HANDLE Handle,
/* Detach and return success */
if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
Status = STATUS_SUCCESS;
}
else
{

View file

@ -20,6 +20,8 @@ PKWIN32_THREAD_CALLOUT PspW32ThreadCallout = NULL;
PGDI_BATCHFLUSH_ROUTINE KeGdiFlushUserBatch = NULL;
extern PKWIN32_PARSEMETHOD_CALLOUT ExpWindowStationObjectParse;
extern PKWIN32_DELETEMETHOD_CALLOUT ExpWindowStationObjectDelete;
extern PKWIN32_OKTOCLOSEMETHOD_CALLOUT ExpWindowStationObjectOkToClose;
extern PKWIN32_OKTOCLOSEMETHOD_CALLOUT ExpDesktopObjectOkToClose;
extern PKWIN32_DELETEMETHOD_CALLOUT ExpDesktopObjectDelete;
extern PKWIN32_POWEREVENT_CALLOUT PopEventCallout;
@ -116,6 +118,8 @@ PsEstablishWin32Callouts(IN PWIN32_CALLOUTS_FPNS CalloutData)
PspW32ThreadCallout = CalloutData->ThreadCallout;
ExpWindowStationObjectParse = CalloutData->WindowStationParseProcedure;
ExpWindowStationObjectDelete = CalloutData->WindowStationDeleteProcedure;
ExpWindowStationObjectOkToClose = CalloutData->WindowStationOkToCloseProcedure;
ExpDesktopObjectOkToClose = CalloutData->DesktopOkToCloseProcedure;
ExpDesktopObjectDelete = CalloutData->DesktopDeleteProcedure;
PopEventCallout = CalloutData->PowerEventCallout;
KeGdiFlushUserBatch = CalloutData->BatchFlushRoutine;

View file

@ -69,6 +69,9 @@ IntDesktopObjectParse(IN PVOID ParseObject,
VOID APIENTRY
IntDesktopObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters);
NTSTATUS NTAPI
IntDesktopOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters);
LRESULT CALLBACK
IntDesktopWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

View file

@ -166,6 +166,7 @@ typedef struct _PROCESSINFO
PCLS pclsPrivateList;
PCLS pclsPublicList;
INT cThreads;
HDESK hdeskStartup;
DWORD dwhmodLibLoadedMask;
HANDLE ahmodLibLoaded[CLIBS];
struct _WINSTATION_OBJECT *prpwinsta;

View file

@ -82,6 +82,9 @@ NTSTATUS
APIENTRY
IntWinStaObjectParse(PWIN32_PARSEMETHOD_PARAMETERS Parameters);
NTSTATUS NTAPI
IntWinstaOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters);
NTSTATUS FASTCALL
IntValidateWindowStationHandle(
HWINSTA WindowStation,
@ -106,4 +109,7 @@ IntGetFullWindowStationName(
PWINSTATION_OBJECT FASTCALL IntGetWinStaObj(VOID);
BOOL FASTCALL
UserSetProcessWindowStation(HWINSTA hWindowStation);
/* EOF */

View file

@ -119,6 +119,7 @@ Win32kProcessCallback(struct _EPROCESS *Process,
{
DPRINT("Destroying W32 process PID:%d at IRQ level: %lu\n", Process->UniqueProcessId, KeGetCurrentIrql());
Win32Process->W32PF_flags |= W32PF_TERMINATED;
if (Win32Process->InputIdleEvent)
{
EngFreeMem((PVOID)Win32Process->InputIdleEvent);
@ -144,6 +145,9 @@ Win32kProcessCallback(struct _EPROCESS *Process,
{
LogonProcess = NULL;
}
UserSetProcessWindowStation(NULL);
}
RETURN( STATUS_SUCCESS);
@ -220,25 +224,14 @@ Win32kThreadCallback(struct _ETHREAD *Thread,
{
if(hWinSta != NULL)
{
if(Process != CsrProcess)
if(!UserSetProcessWindowStation(hWinSta))
{
HWINSTA hProcessWinSta = (HWINSTA)InterlockedCompareExchangePointer((PVOID)&Process->Win32WindowStation, (PVOID)hWinSta, NULL);
if(hProcessWinSta != NULL)
{
/* our process is already assigned to a different window station, we don't need the handle anymore */
NtClose(hWinSta);
}
}
else
{
NtClose(hWinSta);
DPRINT1("Failed to set process window station\n");
}
}
if (hDesk != NULL)
{
Win32Thread->rpdesk = NULL;
Win32Thread->hdesk = NULL;
if (!IntSetThreadDesktop(hDesk, FALSE))
{
DPRINT1("Unable to set thread desktop\n");
@ -441,6 +434,8 @@ DriverEntry(
CalloutData.ProcessCallout = Win32kProcessCallback;
CalloutData.ThreadCallout = Win32kThreadCallback;
CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch;
CalloutData.DesktopOkToCloseProcedure = IntDesktopOkToClose;
CalloutData.WindowStationOkToCloseProcedure = IntWinstaOkToClose;
/* Register our per-process and per-thread structures. */
PsEstablishWin32Callouts((PWIN32_CALLOUTS_FPNS)&CalloutData);

View file

@ -168,6 +168,29 @@ IntDesktopObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters)
IntFreeDesktopHeap(Desktop);
}
NTSTATUS NTAPI
IntDesktopOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters)
{
PTHREADINFO pti;
pti = PsGetCurrentThreadWin32Thread();
if( pti == NULL)
{
/* This happens when we leak desktop handles */
return TRUE;
}
/* Do not allow the current desktop or the initial desktop to be closed */
if( Parameters->Handle == pti->ppi->hdeskStartup ||
Parameters->Handle == pti->hdesk)
{
return FALSE;
}
return TRUE;
}
/* PRIVATE FUNCTIONS **********************************************************/
INIT_FUNCTION

View file

@ -187,6 +187,21 @@ IntWinStaObjectParse(PWIN32_PARSEMETHOD_PARAMETERS Parameters)
return STATUS_OBJECT_TYPE_MISMATCH;
}
NTSTATUS NTAPI
IntWinstaOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters)
{
PPROCESSINFO ppi;
ppi = PsGetCurrentProcessWin32Process();
if(Parameters->Handle == ppi->hwinsta)
{
return FALSE;
}
return TRUE;
}
/* PRIVATE FUNCTIONS **********************************************************/
/*
@ -915,6 +930,57 @@ IntGetWinStaObj(VOID)
return WinStaObj;
}
BOOL FASTCALL
UserSetProcessWindowStation(HWINSTA hWindowStation)
{
PPROCESSINFO ppi;
NTSTATUS Status;
HWINSTA hwinstaOld;
PWINSTATION_OBJECT NewWinSta = NULL, OldWinSta;
ppi = PsGetCurrentProcessWin32Process();
if(hWindowStation !=NULL)
{
Status = IntValidateWindowStationHandle( hWindowStation,
KernelMode,
0,
&NewWinSta);
if (!NT_SUCCESS(Status))
{
DPRINT("Validation of window station handle (0x%X) failed\n",
hWindowStation);
SetLastNtError(Status);
return FALSE;
}
}
OldWinSta = ppi->prpwinsta;
hwinstaOld = ppi->hwinsta;
/*
* FIXME - don't allow changing the window station if there are threads that are attached to desktops and own gui objects
*/
InterlockedExchangePointer(&PsGetCurrentProcess()->Win32WindowStation, hWindowStation);
ppi->prpwinsta = NewWinSta;
ppi->hwinsta = hWindowStation;
if(OldWinSta != NULL)
{
ObDereferenceObject(OldWinSta);
}
if(hwinstaOld != NULL)
{
ZwClose(hwinstaOld);
}
return TRUE;
}
/*
* NtUserSetProcessWindowStation
*
@ -934,44 +1000,15 @@ IntGetWinStaObj(VOID)
BOOL APIENTRY
NtUserSetProcessWindowStation(HWINSTA hWindowStation)
{
PWINSTATION_OBJECT NewWinSta;
NTSTATUS Status;
BOOL ret;
DPRINT("About to set process window station with handle (0x%X)\n",
hWindowStation);
UserEnterExclusive();
if(PsGetCurrentProcess() == CsrProcess)
{
DPRINT1("CSRSS is not allowed to change it's window station!!!\n");
EngSetLastError(ERROR_ACCESS_DENIED);
return FALSE;
}
ret = UserSetProcessWindowStation(hWindowStation);
Status = IntValidateWindowStationHandle(
hWindowStation,
KernelMode,
0,
&NewWinSta);
UserLeave();
if (!NT_SUCCESS(Status))
{
DPRINT("Validation of window station handle (0x%X) failed\n",
hWindowStation);
SetLastNtError(Status);
return FALSE;
}
/*
* FIXME - don't allow changing the window station if there are threads that are attached to desktops and own gui objects
*/
/* FIXME - dereference the old window station, etc... */
InterlockedExchangePointer(&PsGetCurrentProcess()->Win32WindowStation, hWindowStation);
DPRINT("PsGetCurrentProcess()->Win32WindowStation 0x%X\n",
PsGetCurrentProcess()->Win32WindowStation);
return TRUE;
return ret;
}
/*