[WIN32K:NTUSER] In UserSetProcessWindowStation(), use a duplicated window station handle to be set in the EPROCESS:Win32WindowStation cache.

Fixes most of the user32:desktop window station handle reference count tests.
This commit is contained in:
Hermès Bélusca-Maïto 2018-07-23 01:17:14 +02:00
parent e3b9152935
commit d0632b0bca
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0

View file

@ -972,7 +972,6 @@ NtUserCloseWindowStation(
0, 0,
&Object, &Object,
NULL); NULL);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
ERR("Validation of window station handle (%p) failed\n", hWinSta); ERR("Validation of window station handle (%p) failed\n", hWinSta);
@ -1319,11 +1318,11 @@ NtUserGetProcessWindowStation(VOID)
BOOL FASTCALL BOOL FASTCALL
UserSetProcessWindowStation(HWINSTA hWindowStation) UserSetProcessWindowStation(HWINSTA hWindowStation)
{ {
PPROCESSINFO ppi;
NTSTATUS Status; NTSTATUS Status;
HWINSTA hwinstaOld; PPROCESSINFO ppi;
OBJECT_HANDLE_INFORMATION ObjectHandleInfo; OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
PWINSTATION_OBJECT NewWinSta = NULL, OldWinSta; PWINSTATION_OBJECT NewWinSta = NULL, OldWinSta;
HWINSTA hCacheWinSta;
ppi = PsGetCurrentProcessWin32Process(); ppi = PsGetCurrentProcessWin32Process();
@ -1337,15 +1336,14 @@ UserSetProcessWindowStation(HWINSTA hWindowStation)
&ObjectHandleInfo); &ObjectHandleInfo);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
TRACE("Validation of window station handle (%p) failed\n", TRACE("Validation of window station handle 0x%p failed\n", hWindowStation);
hWindowStation);
SetLastNtError(Status); SetLastNtError(Status);
return FALSE; return FALSE;
} }
} }
OldWinSta = ppi->prpwinsta; OldWinSta = ppi->prpwinsta;
hwinstaOld = PsGetProcessWin32WindowStation(ppi->peProcess); hCacheWinSta = PsGetProcessWin32WindowStation(ppi->peProcess);
/* Dereference the previous window station */ /* Dereference the previous window station */
if (OldWinSta != NULL) if (OldWinSta != NULL)
@ -1353,17 +1351,64 @@ UserSetProcessWindowStation(HWINSTA hWindowStation)
ObDereferenceObject(OldWinSta); ObDereferenceObject(OldWinSta);
} }
/* Check if we have a stale handle (it should happen for console apps) */
if (hwinstaOld != ppi->hwinsta)
{
ObCloseHandle(hwinstaOld, UserMode);
}
/* /*
* FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects. * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects?
*/ */
PsSetProcessWindowStation(ppi->peProcess, hWindowStation); /* Close the cached EPROCESS window station handle if needed */
if (hCacheWinSta != NULL)
{
/* Reference the window station */
Status = ObReferenceObjectByHandle(hCacheWinSta,
0,
ExWindowStationObjectType,
UserMode,
(PVOID*)&OldWinSta,
NULL);
if (!NT_SUCCESS(Status))
{
ERR("Failed to reference the inherited window station, Status 0x%08lx\n", Status);
/* We failed, reset the cache */
hCacheWinSta = NULL;
PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
}
else
{
/*
* Close the old handle and reset the cache only
* if we are setting a different window station.
*/
if (NewWinSta != OldWinSta)
{
ObCloseHandle(hCacheWinSta, UserMode);
hCacheWinSta = NULL;
PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
}
/* Dereference the window station */
ObDereferenceObject(OldWinSta);
}
}
/* Duplicate and save a new cached EPROCESS window station handle */
if ((hCacheWinSta == NULL) && (hWindowStation != NULL))
{
Status = ZwDuplicateObject(ZwCurrentProcess(),
hWindowStation,
ZwCurrentProcess(),
(PHANDLE)&hCacheWinSta,
0,
0,
DUPLICATE_SAME_ACCESS);
if (!NT_SUCCESS(Status))
{
ERR("UserSetProcessWindowStation: Failed to duplicate the window station handle, Status 0x%08lx\n", Status);
}
else
{
PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
}
}
ppi->prpwinsta = NewWinSta; ppi->prpwinsta = NewWinSta;
ppi->hwinsta = hWindowStation; ppi->hwinsta = hWindowStation;
@ -1383,7 +1428,7 @@ UserSetProcessWindowStation(HWINSTA hWindowStation)
{ {
ppi->W32PF_flags |= W32PF_IOWINSTA; ppi->W32PF_flags |= W32PF_IOWINSTA;
} }
else // Might be closed if the handle is null. else /* Might be closed if the handle is NULL */
{ {
ppi->W32PF_flags &= ~W32PF_IOWINSTA; ppi->W32PF_flags &= ~W32PF_IOWINSTA;
} }