[NTUSER][USER32] Refactor NtUserLoadKeyboardLayoutEx (#5107)

- Split some code of NtUserLoadKeyboardLayoutEx to newly-added co_IntLoadKeyboardLayoutEx helper function.
- Modify NtUserLoadKeyboardLayoutEx prototype.
- Move co_UserImmLoadLayout code.
- Implement KLF_REORDER.
- Rename UserLoadKbdLayout as co_UserLoadKbdLayout.
- Improve LoadKeyboardLayoutEx.
CORE-11700
This commit is contained in:
Katayama Hirofumi MZ 2023-03-05 11:41:32 +09:00 committed by GitHub
parent 0fb580a855
commit 77e6348f5f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 165 additions and 110 deletions

View file

@ -2736,12 +2736,12 @@ NtUserKillTimer(
HKL HKL
NTAPI NTAPI
NtUserLoadKeyboardLayoutEx( NtUserLoadKeyboardLayoutEx(
IN HANDLE Handle, IN HANDLE hFile,
IN DWORD offTable, IN DWORD offTable,
IN PUNICODE_STRING puszKeyboardName, IN PVOID pTables,
IN HKL hKL, IN HKL hOldKL,
IN PUNICODE_STRING puszKLID, IN PUNICODE_STRING puszKLID,
IN DWORD dwKLID, IN DWORD dwNewKL,
IN UINT Flags); IN UINT Flags);
BOOL BOOL

View file

@ -369,12 +369,12 @@ cleanup:
} }
/* /*
* UserLoadKbdLayout * co_UserLoadKbdLayout
* *
* Loads keyboard layout and creates KL object * Loads keyboard layout and creates KL object
*/ */
static PKL static PKL
UserLoadKbdLayout(PUNICODE_STRING pustrKLID, HKL hKL) co_UserLoadKbdLayout(PUNICODE_STRING pustrKLID, HKL hKL)
{ {
LCID lCid; LCID lCid;
CHARSETINFO cs; CHARSETINFO cs;
@ -846,6 +846,129 @@ IntUnloadKeyboardLayout(_Inout_ PWINSTATION_OBJECT pWinSta, _In_ HKL hKL)
return co_IntUnloadKeyboardLayoutEx(pWinSta, pKL, 0); return co_IntUnloadKeyboardLayoutEx(pWinSta, pKL, 0);
} }
PIMEINFOEX FASTCALL co_UserImmLoadLayout(_In_ HKL hKL)
{
PIMEINFOEX piiex;
if (!IS_IME_HKL(hKL) && !IS_CICERO_MODE())
return NULL;
piiex = ExAllocatePoolWithTag(PagedPool, sizeof(IMEINFOEX), USERTAG_IME);
if (!piiex)
return NULL;
if (!co_ClientImmLoadLayout(hKL, piiex))
{
ExFreePoolWithTag(piiex, USERTAG_IME);
return NULL;
}
return piiex;
}
HKL APIENTRY
co_IntLoadKeyboardLayoutEx(
IN OUT PWINSTATION_OBJECT pWinSta,
IN HANDLE hSafeFile,
IN HKL hOldKL,
IN PUNICODE_STRING puszSafeKLID,
IN HKL hNewKL,
IN UINT Flags)
{
PKL pOldKL, pNewKL;
UNREFERENCED_PARAMETER(hSafeFile);
if (hNewKL == NULL || (pWinSta->Flags & WSS_NOIO))
return NULL;
/* If hOldKL is specified, unload it and load new layput as default */
if (hOldKL && hOldKL != hNewKL)
{
pOldKL = UserHklToKbl(hOldKL);
if (pOldKL)
UserUnloadKbl(pOldKL);
}
/* FIXME: It seems KLF_RESET is only supported for WINLOGON */
/* Let's see if layout was already loaded. */
pNewKL = UserHklToKbl(hNewKL);
if (!pNewKL)
{
/* It wasn't, so load it. */
pNewKL = co_UserLoadKbdLayout(puszSafeKLID, hNewKL);
if (!pNewKL)
return NULL;
if (gspklBaseLayout)
{
/* Find last not unloaded layout */
PKL pLastKL = gspklBaseLayout->pklPrev;
while (pLastKL != gspklBaseLayout && (pLastKL->dwKL_Flags & KLF_UNLOAD))
pLastKL = pLastKL->pklPrev;
/* Add new layout to the list */
pNewKL->pklNext = pLastKL->pklNext;
pNewKL->pklPrev = pLastKL;
pNewKL->pklNext->pklPrev = pNewKL;
pNewKL->pklPrev->pklNext = pNewKL;
}
else
{
/* This is the first layout */
pNewKL->pklNext = pNewKL;
pNewKL->pklPrev = pNewKL;
gspklBaseLayout = pNewKL;
}
pNewKL->piiex = co_UserImmLoadLayout(hNewKL);
}
/* If this layout was prepared to unload, undo it */
pNewKL->dwKL_Flags &= ~KLF_UNLOAD;
/* Reorder if necessary */
if (Flags & KLF_REORDER)
IntReorderKeyboardLayouts(pWinSta, pNewKL);
/* Activate this layout in current thread */
if (Flags & KLF_ACTIVATE)
co_UserActivateKbl(PsGetCurrentThreadWin32Thread(), pNewKL, Flags);
/* Send shell message */
if (!(Flags & KLF_NOTELLSHELL))
co_IntShellHookNotify(HSHELL_LANGUAGE, 0, (LPARAM)hNewKL);
/* FIXME: KLF_REPLACELANG */
return hNewKL;
}
HANDLE FASTCALL IntVerifyKeyboardFileHandle(HANDLE hFile)
{
PFILE_OBJECT FileObject;
NTSTATUS Status;
if (hFile == INVALID_HANDLE_VALUE)
return NULL;
Status = ObReferenceObjectByHandle(hFile, FILE_READ_DATA, NULL, UserMode,
(PVOID*)&FileObject, NULL);
if (!NT_SUCCESS(Status))
{
ERR("0x%08X\n", Status);
return NULL;
}
/* FIXME: Is the file in the system directory? */
if (FileObject)
ObDereferenceObject(FileObject);
return hFile;
}
/* EXPORTS *******************************************************************/ /* EXPORTS *******************************************************************/
/* /*
@ -1009,50 +1132,34 @@ cleanup:
return bRet; return bRet;
} }
/* Win: xxxImmLoadLayout */
PIMEINFOEX FASTCALL co_UserImmLoadLayout(_In_ HKL hKL)
{
PIMEINFOEX piiex;
if (!IS_IME_HKL(hKL) && !IS_CICERO_MODE())
return NULL;
piiex = ExAllocatePoolWithTag(PagedPool, sizeof(IMEINFOEX), USERTAG_IME);
if (!piiex)
return NULL;
if (!co_ClientImmLoadLayout(hKL, piiex))
{
ExFreePoolWithTag(piiex, USERTAG_IME);
return NULL;
}
return piiex;
}
/* /*
* NtUserLoadKeyboardLayoutEx * NtUserLoadKeyboardLayoutEx
* *
* Loads keyboard layout with given locale id * Loads keyboard layout with given locale id
* *
* NOTE: We adopt a different design from Microsoft's one for security reason. * NOTE: We adopt a different design from Microsoft's one due to security reason.
* We don't use the 1st and 3rd parameters of NtUserLoadKeyboardLayoutEx. * We don't use the 3rd parameter of NtUserLoadKeyboardLayoutEx.
* See https://bugtraq.securityfocus.com/detail/50056B96.6040306
*/ */
HKL HKL
APIENTRY NTAPI
NtUserLoadKeyboardLayoutEx( NtUserLoadKeyboardLayoutEx(
IN HANDLE Handle, // hFile (See downloads.securityfocus.com/vulnerabilities/exploits/43774.c) IN HANDLE hFile,
IN DWORD offTable, // Offset to KbdTables IN DWORD offTable,
IN PUNICODE_STRING puszKeyboardName, // Not used? IN PVOID pTables,
IN HKL hklUnload, IN HKL hOldKL,
IN PUNICODE_STRING pustrKLID, IN PUNICODE_STRING puszKLID,
IN DWORD hkl, IN DWORD dwNewKL,
IN UINT Flags) IN UINT Flags)
{ {
HKL hklRet = NULL; HKL hRetKL;
PKL pKl = NULL, pklLast;
WCHAR Buffer[KL_NAMELENGTH]; WCHAR Buffer[KL_NAMELENGTH];
UNICODE_STRING ustrSafeKLID; UNICODE_STRING uszSafeKLID;
PWINSTATION_OBJECT pWinSta;
HANDLE hSafeFile;
UNREFERENCED_PARAMETER(offTable);
UNREFERENCED_PARAMETER(pTables);
if (Flags & ~(KLF_ACTIVATE|KLF_NOTELLSHELL|KLF_REORDER|KLF_REPLACELANG| if (Flags & ~(KLF_ACTIVATE|KLF_NOTELLSHELL|KLF_REORDER|KLF_REPLACELANG|
KLF_SUBSTITUTE_OK|KLF_SETFORPROCESS|KLF_UNLOADPREVIOUS| KLF_SUBSTITUTE_OK|KLF_SETFORPROCESS|KLF_UNLOADPREVIOUS|
@ -1063,14 +1170,12 @@ NtUserLoadKeyboardLayoutEx(
return NULL; return NULL;
} }
/* FIXME: It seems KLF_RESET is only supported for WINLOGON */ RtlInitEmptyUnicodeString(&uszSafeKLID, Buffer, sizeof(Buffer));
RtlInitEmptyUnicodeString(&ustrSafeKLID, Buffer, sizeof(Buffer));
_SEH2_TRY _SEH2_TRY
{ {
ProbeForRead(pustrKLID, sizeof(*pustrKLID), 1); ProbeForRead(puszKLID, sizeof(*puszKLID), 1);
ProbeForRead(pustrKLID->Buffer, sizeof(pustrKLID->Length), 1); ProbeForRead(puszKLID->Buffer, sizeof(puszKLID->Length), 1);
RtlCopyUnicodeString(&ustrSafeKLID, pustrKLID); RtlCopyUnicodeString(&uszSafeKLID, puszKLID);
} }
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{ {
@ -1081,67 +1186,19 @@ NtUserLoadKeyboardLayoutEx(
UserEnterExclusive(); UserEnterExclusive();
/* If hklUnload is specified, unload it and load new layput as default */ hSafeFile = (hFile ? IntVerifyKeyboardFileHandle(hFile) : NULL);
if (hklUnload && (hklUnload != UlongToHandle(hkl))) pWinSta = IntGetProcessWindowStation(NULL);
{ hRetKL = co_IntLoadKeyboardLayoutEx(pWinSta,
pKl = UserHklToKbl(hklUnload); hSafeFile,
if (pKl) hOldKL,
UserUnloadKbl(pKl); &uszSafeKLID,
} (HKL)(DWORD_PTR)dwNewKL,
Flags);
if (hSafeFile)
ZwClose(hSafeFile);
/* Let's see if layout was already loaded. */
pKl = UserHklToKbl(UlongToHandle(hkl));
if (!pKl)
{
/* It wasn't, so load it. */
pKl = UserLoadKbdLayout(&ustrSafeKLID, UlongToHandle(hkl));
if (!pKl)
goto cleanup;
if (gspklBaseLayout)
{
/* Find last not unloaded layout */
pklLast = gspklBaseLayout->pklPrev;
while (pklLast != gspklBaseLayout && pklLast->dwKL_Flags & KLF_UNLOAD)
pklLast = pklLast->pklPrev;
/* Add new layout to the list */
pKl->pklNext = pklLast->pklNext;
pKl->pklPrev = pklLast;
pKl->pklNext->pklPrev = pKl;
pKl->pklPrev->pklNext = pKl;
}
else
{
/* This is the first layout */
pKl->pklNext = pKl;
pKl->pklPrev = pKl;
gspklBaseLayout = pKl;
}
pKl->piiex = co_UserImmLoadLayout(UlongToHandle(hkl));
}
/* If this layout was prepared to unload, undo it */
pKl->dwKL_Flags &= ~KLF_UNLOAD;
/* Activate this layout in current thread */
if (Flags & KLF_ACTIVATE)
co_UserActivateKbl(PsGetCurrentThreadWin32Thread(), pKl, Flags);
/* Send shell message */
if (!(Flags & KLF_NOTELLSHELL))
co_IntShellHookNotify(HSHELL_LANGUAGE, 0, (LPARAM)hkl);
/* Return hkl on success */
hklRet = UlongToHandle(hkl);
/* FIXME: KLF_REPLACELANG
KLF_REORDER */
cleanup:
UserLeave(); UserLeave();
return hklRet; return hRetKL;
} }
/* /*

View file

@ -721,9 +721,9 @@ VOID GetSystemLibraryPath(LPWSTR pszPath, INT cchPath, LPCWSTR pszFileName)
/* /*
* @unimplemented * @unimplemented
* *
* NOTE: We adopt a different design from Microsoft's one for security reason. * NOTE: We adopt a different design from Microsoft's one due to security reason.
* See NtUserLoadKeyboardLayoutEx.
*/ */
/* Win: LoadKeyboardLayoutWorker */
HKL APIENTRY HKL APIENTRY
IntLoadKeyboardLayout( IntLoadKeyboardLayout(
_In_ HKL hklUnload, _In_ HKL hklUnload,
@ -733,7 +733,6 @@ IntLoadKeyboardLayout(
_In_ BOOL unknown5) _In_ BOOL unknown5)
{ {
DWORD dwKLID, dwHKL, dwType, dwSize; DWORD dwKLID, dwHKL, dwType, dwSize;
UNICODE_STRING ustrKbdName;
UNICODE_STRING ustrKLID; UNICODE_STRING ustrKLID;
WCHAR wszRegKey[256] = L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\"; WCHAR wszRegKey[256] = L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\";
WCHAR wszLayoutId[10], wszNewKLID[KL_NAMELENGTH], szImeFileName[80]; WCHAR wszLayoutId[10], wszNewKLID[KL_NAMELENGTH], szImeFileName[80];
@ -807,7 +806,7 @@ IntLoadKeyboardLayout(
szImeFileName[_countof(szImeFileName) - 1] = UNICODE_NULL; szImeFileName[_countof(szImeFileName) - 1] = UNICODE_NULL;
GetSystemLibraryPath(szPath, _countof(szPath), szImeFileName); GetSystemLibraryPath(szPath, _countof(szPath), szImeFileName);
/* We don't allow the invalid "IME File" values for security reason */ /* We don't allow the invalid "IME File" values due to security reason */
if (dwType != REG_SZ || szImeFileName[0] == 0 || if (dwType != REG_SZ || szImeFileName[0] == 0 ||
wcscspn(szImeFileName, L":\\/") != wcslen(szImeFileName) || wcscspn(szImeFileName, L":\\/") != wcslen(szImeFileName) ||
GetFileAttributesW(szPath) == INVALID_FILE_ATTRIBUTES) /* Does not exist? */ GetFileAttributesW(szPath) == INVALID_FILE_ATTRIBUTES) /* Does not exist? */
@ -833,9 +832,8 @@ IntLoadKeyboardLayout(
dwHKL = MAKELONG(wLow, wHigh); dwHKL = MAKELONG(wLow, wHigh);
ZeroMemory(&ustrKbdName, sizeof(ustrKbdName));
RtlInitUnicodeString(&ustrKLID, pwszKLID); RtlInitUnicodeString(&ustrKLID, pwszKLID);
hNewKL = NtUserLoadKeyboardLayoutEx(NULL, 0, &ustrKbdName, NULL, &ustrKLID, dwHKL, Flags); hNewKL = NtUserLoadKeyboardLayoutEx(NULL, 0, NULL, hklUnload, &ustrKLID, dwHKL, Flags);
CliImmInitializeHotKeys(SETIMEHOTKEY_ADD, hNewKL); CliImmInitializeHotKeys(SETIMEHOTKEY_ADD, hNewKL);
return hNewKL; return hNewKL;
} }