It's hilarious how this new code has the exact same Windows security bug I gave a talk
about at BlackHat 2-3 years ago (which Microsoft fixed in Vista).
It's sad how this code ignores the exported PsSetProcessWindowStation API and relevant
EPROCESS field.
It's awesome how nothing changes whenever I prop up to see the "progress".
--
Best regards,
Alex Ionescu
On 2011-03-22, at 5:19 AM, gadamopoulos(a)svn.reactos.org wrote:
Author: gadamopoulos
Date: Tue Mar 22 09:19:26 2011
New Revision: 51115
URL:
http://svn.reactos.org/svn/reactos?rev=51115&view=rev
Log:
[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
Modified:
trunk/reactos/ntoskrnl/ex/win32k.c
trunk/reactos/ntoskrnl/ob/obhandle.c
trunk/reactos/ntoskrnl/ps/win32.c
trunk/reactos/subsystems/win32/win32k/include/desktop.h
trunk/reactos/subsystems/win32/win32k/include/win32.h
trunk/reactos/subsystems/win32/win32k/include/winsta.h
trunk/reactos/subsystems/win32/win32k/main/dllmain.c
trunk/reactos/subsystems/win32/win32k/ntuser/desktop.c
trunk/reactos/subsystems/win32/win32k/ntuser/winsta.c
Modified: trunk/reactos/ntoskrnl/ex/win32k.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ex/win32k.c?rev=5…
==============================================================================
--- trunk/reactos/ntoskrnl/ex/win32k.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ex/win32k.c [iso-8859-1] Tue Mar 22 09:19:26 2011
@@ -37,9 +37,45 @@
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
@@ -114,6 +150,7 @@
ObjectTypeInitializer.PoolType = NonPagedPool;
ObjectTypeInitializer.DeleteProcedure = ExpWinStaObjectDelete;
ObjectTypeInitializer.ParseProcedure = ExpWinStaObjectParse;
+ ObjectTypeInitializer.OkayToCloseProcedure = ExpWindowStationOkToClose;
ObCreateObjectType(&Name,
&ObjectTypeInitializer,
NULL,
@@ -124,6 +161,7 @@
ObjectTypeInitializer.GenericMapping = ExpDesktopMapping;
ObjectTypeInitializer.DeleteProcedure = ExpDesktopDelete;
ObjectTypeInitializer.ParseProcedure = NULL;
+ ObjectTypeInitializer.OkayToCloseProcedure = ExpDesktopOkToClose;
ObCreateObjectType(&Name,
&ObjectTypeInitializer,
NULL,
Modified: trunk/reactos/ntoskrnl/ob/obhandle.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ob/obhandle.c?rev…
==============================================================================
--- trunk/reactos/ntoskrnl/ob/obhandle.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ob/obhandle.c [iso-8859-1] Tue Mar 22 09:19:26 2011
@@ -1752,7 +1752,6 @@
/* Detach and return success */
if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
- Status = STATUS_SUCCESS;
}
else
{
Modified: trunk/reactos/ntoskrnl/ps/win32.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ps/win32.c?rev=51…
==============================================================================
--- trunk/reactos/ntoskrnl/ps/win32.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ps/win32.c [iso-8859-1] Tue Mar 22 09:19:26 2011
@@ -20,6 +20,8 @@
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 @@
PspW32ThreadCallout = CalloutData->ThreadCallout;
ExpWindowStationObjectParse = CalloutData->WindowStationParseProcedure;
ExpWindowStationObjectDelete = CalloutData->WindowStationDeleteProcedure;
+ ExpWindowStationObjectOkToClose = CalloutData->WindowStationOkToCloseProcedure;
+ ExpDesktopObjectOkToClose = CalloutData->DesktopOkToCloseProcedure;
ExpDesktopObjectDelete = CalloutData->DesktopDeleteProcedure;
PopEventCallout = CalloutData->PowerEventCallout;
KeGdiFlushUserBatch = CalloutData->BatchFlushRoutine;
Modified: trunk/reactos/subsystems/win32/win32k/include/desktop.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/in…
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/include/desktop.h [iso-8859-1] (original)
+++ trunk/reactos/subsystems/win32/win32k/include/desktop.h [iso-8859-1] Tue Mar 22
09:19:26 2011
@@ -69,6 +69,9 @@
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);
Modified: trunk/reactos/subsystems/win32/win32k/include/win32.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/in…
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/include/win32.h [iso-8859-1] (original)
+++ trunk/reactos/subsystems/win32/win32k/include/win32.h [iso-8859-1] Tue Mar 22
09:19:26 2011
@@ -166,6 +166,7 @@
PCLS pclsPrivateList;
PCLS pclsPublicList;
INT cThreads;
+ HDESK hdeskStartup;
DWORD dwhmodLibLoadedMask;
HANDLE ahmodLibLoaded[CLIBS];
struct _WINSTATION_OBJECT *prpwinsta;
Modified: trunk/reactos/subsystems/win32/win32k/include/winsta.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/in…
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/include/winsta.h [iso-8859-1] (original)
+++ trunk/reactos/subsystems/win32/win32k/include/winsta.h [iso-8859-1] Tue Mar 22
09:19:26 2011
@@ -82,6 +82,9 @@
APIENTRY
IntWinStaObjectParse(PWIN32_PARSEMETHOD_PARAMETERS Parameters);
+NTSTATUS NTAPI
+IntWinstaOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters);
+
NTSTATUS FASTCALL
IntValidateWindowStationHandle(
HWINSTA WindowStation,
@@ -106,4 +109,7 @@
PWINSTATION_OBJECT FASTCALL IntGetWinStaObj(VOID);
+BOOL FASTCALL
+UserSetProcessWindowStation(HWINSTA hWindowStation);
+
/* EOF */
Modified: trunk/reactos/subsystems/win32/win32k/main/dllmain.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/ma…
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/main/dllmain.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/win32/win32k/main/dllmain.c [iso-8859-1] Tue Mar 22 09:19:26
2011
@@ -119,6 +119,7 @@
{
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 @@
{
LogonProcess = NULL;
}
+
+ UserSetProcessWindowStation(NULL);
+
}
RETURN( STATUS_SUCCESS);
@@ -220,25 +224,14 @@
{
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 @@
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);
Modified: trunk/reactos/subsystems/win32/win32k/ntuser/desktop.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/nt…
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/ntuser/desktop.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/win32/win32k/ntuser/desktop.c [iso-8859-1] Tue Mar 22
09:19:26 2011
@@ -166,6 +166,29 @@
RemoveEntryList(&Desktop->ListEntry);
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 **********************************************************/
Modified: trunk/reactos/subsystems/win32/win32k/ntuser/winsta.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/nt…
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/ntuser/winsta.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/win32/win32k/ntuser/winsta.c [iso-8859-1] Tue Mar 22
09:19:26 2011
@@ -187,6 +187,21 @@
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 @@
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 @@
BOOL APIENTRY
NtUserSetProcessWindowStation(HWINSTA hWindowStation)
{
- PWINSTATION_OBJECT NewWinSta;
- NTSTATUS Status;
-
- DPRINT("About to set process window station with handle (0x%X)\n",
- hWindowStation);
-
- if(PsGetCurrentProcess() == CsrProcess)
- {
- DPRINT1("CSRSS is not allowed to change it's window station!!!\n");
- EngSetLastError(ERROR_ACCESS_DENIED);
- return FALSE;
- }
-
- 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;
- }
-
- /*
- * 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;
+ BOOL ret;
+
+ UserEnterExclusive();
+
+ ret = UserSetProcessWindowStation(hWindowStation);
+
+ UserLeave();
+
+ return ret;
}
/*