From 85e292d58f952f7941eed0b3056c94f08a7b53a3 Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Mon, 5 Sep 2022 08:34:00 +0900 Subject: [PATCH] [NTUSER][USER32][IMM32] Initialize pKL->piiex by using ImmLoadLayout (#4645) To recognize IME, we have to initialize pKL->piiex. - Add co_ClientImmLoadLayout and User32CallImmLoadLayoutFromKernel functions to call imm32!ImmLoadLayout on user mode from kernel. - Use co_ClientImmLoadLayout in NtUserLoadKeyboardLayoutEx. - Improve Imm32LoadIME to sanitize the IME table. CORE-11700 --- dll/win32/imm32/ime.c | 26 +++++++++++----- dll/win32/imm32/imm.c | 38 ++++++++++-------------- dll/win32/imm32/utils.c | 1 + win32ss/include/callback.h | 17 ++++++++++- win32ss/user/ntuser/callback.c | 46 +++++++++++++++++++++++++++++ win32ss/user/ntuser/callback.h | 6 ++++ win32ss/user/ntuser/kbdlayout.c | 30 ++++++++++++++++++- win32ss/user/ntuser/ntuser.h | 1 + win32ss/user/user32/misc/dllmain.c | 10 +++++++ win32ss/user/user32/windows/input.c | 24 +++++++++++---- 10 files changed, 161 insertions(+), 38 deletions(-) diff --git a/dll/win32/imm32/ime.c b/dll/win32/imm32/ime.c index 79c40435188..dd3519087a4 100644 --- a/dll/win32/imm32/ime.c +++ b/dll/win32/imm32/ime.c @@ -149,6 +149,15 @@ BOOL APIENTRY Imm32InquireIme(PIMEDPI pImeDpi) return GetClassInfoW(pImeDpi->hInst, pImeDpi->szUIClass, &wcW); } +/* Define stub IME functions */ +#define DEFINE_IME_ENTRY(type, name, params, optional) \ + type APIENTRY Stub##name params { \ + FIXME("%s: Why stub called?\n", #name); \ + return (type)0; \ + } +#include "imetable.h" +#undef DEFINE_IME_ENTRY + // Win: LoadIME BOOL APIENTRY Imm32LoadIME(PIMEINFOEX pImeInfoEx, PIMEDPI pImeDpi) { @@ -160,18 +169,19 @@ BOOL APIENTRY Imm32LoadIME(PIMEINFOEX pImeInfoEx, PIMEDPI pImeDpi) if (!Imm32GetSystemLibraryPath(szPath, _countof(szPath), pImeInfoEx->wszImeFile)) return FALSE; - hIME = GetModuleHandleW(szPath); + pImeDpi->hInst = hIME = LoadLibraryW(szPath); if (hIME == NULL) { - hIME = LoadLibraryW(szPath); - if (hIME == NULL) - { - ERR("Imm32LoadIME: LoadLibraryW(%S) failed\n", szPath); - return FALSE; - } + ERR("Imm32LoadIME: LoadLibraryW(%s) failed\n", debugstr_w(szPath)); + return FALSE; } - pImeDpi->hInst = hIME; + /* Populate the table by stub IME functions */ +#define DEFINE_IME_ENTRY(type, name, params, optional) pImeDpi->name = Stub##name; +#include "imetable.h" +#undef DEFINE_IME_ENTRY + + /* Populate the table by real IME functions */ #define DEFINE_IME_ENTRY(type, name, params, optional) \ do { \ fn = GetProcAddress(hIME, #name); \ diff --git a/dll/win32/imm32/imm.c b/dll/win32/imm32/imm.c index 94a1afcd488..13512cadb11 100644 --- a/dll/win32/imm32/imm.c +++ b/dll/win32/imm32/imm.c @@ -53,57 +53,49 @@ BOOL WINAPI ImmRegisterClient(PSHAREDINFO ptr, HINSTANCE hMod) */ BOOL WINAPI ImmLoadLayout(HKL hKL, PIMEINFOEX pImeInfoEx) { - DWORD cbData; - HKEY hLayoutKey = NULL, hLayoutsKey = NULL; + DWORD cbData, dwType; + HKEY hLayoutKey; LONG error; WCHAR szLayout[MAX_PATH]; TRACE("(%p, %p)\n", hKL, pImeInfoEx); + ZeroMemory(pImeInfoEx, sizeof(IMEINFOEX)); + if (IS_IME_HKL(hKL) || !Imm32IsCiceroMode() || Imm32Is16BitMode()) { - Imm32UIntToStr((DWORD)(DWORD_PTR)hKL, 16, szLayout, _countof(szLayout)); + StringCchPrintfW(szLayout, _countof(szLayout), L"%s\\%08lX", + REGKEY_KEYBOARD_LAYOUTS, HandleToUlong(hKL)); - error = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_KEYBOARD_LAYOUTS, &hLayoutsKey); + error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szLayout, 0, KEY_READ, &hLayoutKey); if (error) { - ERR("RegOpenKeyW: 0x%08lX\n", error); - return FALSE; - } - - error = RegOpenKeyW(hLayoutsKey, szLayout, &hLayoutKey); - if (error) - { - ERR("RegOpenKeyW: 0x%08lX\n", error); - RegCloseKey(hLayoutsKey); + ERR("RegOpenKeyExW: 0x%08lX\n", error); return FALSE; } } else { - error = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_IMM, &hLayoutKey); + error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, REGKEY_IMM, 0, KEY_READ, &hLayoutKey); if (error) { - ERR("RegOpenKeyW: 0x%08lX\n", error); + ERR("RegOpenKeyExW: 0x%08lX\n", error); return FALSE; } } cbData = sizeof(pImeInfoEx->wszImeFile); - error = RegQueryValueExW(hLayoutKey, L"Ime File", 0, 0, + error = RegQueryValueExW(hLayoutKey, L"Ime File", NULL, &dwType, (LPBYTE)pImeInfoEx->wszImeFile, &cbData); - pImeInfoEx->wszImeFile[_countof(pImeInfoEx->wszImeFile) - 1] = 0; + pImeInfoEx->wszImeFile[_countof(pImeInfoEx->wszImeFile) - 1] = UNICODE_NULL; RegCloseKey(hLayoutKey); - if (hLayoutsKey) - RegCloseKey(hLayoutsKey); pImeInfoEx->fLoadFlag = 0; - if (error) + if (error != ERROR_SUCCESS || dwType != REG_SZ) { - ERR("RegQueryValueExW: 0x%08lX\n", error); - pImeInfoEx->hkl = NULL; + ERR("RegQueryValueExW: 0x%lX, 0x%lX\n", error, dwType); return FALSE; } @@ -116,7 +108,7 @@ BOOL WINAPI ImmLoadLayout(HKL hKL, PIMEINFOEX pImeInfoEx) */ BOOL WINAPI ImmFreeLayout(DWORD dwUnknown) { - WCHAR szKBD[9]; + WCHAR szKBD[KL_NAMELENGTH]; UINT iKL, cKLs; HKL hOldKL, hNewKL, *pList; PIMEDPI pImeDpi; diff --git a/dll/win32/imm32/utils.c b/dll/win32/imm32/utils.c index ca9385aed14..9e0c07195dd 100644 --- a/dll/win32/imm32/utils.c +++ b/dll/win32/imm32/utils.c @@ -776,6 +776,7 @@ BOOL APIENTRY Imm32LoadImeVerInfo(PIMEINFOEX pImeInfoEx) hinstVersion = LoadLibraryW(szPath); if (!hinstVersion) return FALSE; + bLoaded = TRUE; } diff --git a/win32ss/include/callback.h b/win32ss/include/callback.h index a75a6de3803..4c4d56323f0 100644 --- a/win32ss/include/callback.h +++ b/win32ss/include/callback.h @@ -20,7 +20,8 @@ #define USER32_CALLBACK_LPK (16) #define USER32_CALLBACK_UMPD (17) #define USER32_CALLBACK_IMMPROCESSKEY (18) -#define USER32_CALLBACK_MAXIMUM (18) +#define USER32_CALLBACK_IMMLOADLAYOUT (19) +#define USER32_CALLBACK_MAXIMUM USER32_CALLBACK_IMMLOADLAYOUT typedef struct _WINDOWPROC_CALLBACK_ARGUMENTS { @@ -178,6 +179,17 @@ typedef struct _IMMPROCESSKEY_CALLBACK_ARGUMENTS DWORD dwHotKeyID; } IMMPROCESSKEY_CALLBACK_ARGUMENTS, *PIMMPROCESSKEY_CALLBACK_ARGUMENTS; +typedef struct _IMMLOADLAYOUT_CALLBACK_ARGUMENTS +{ + HKL hKL; +} IMMLOADLAYOUT_CALLBACK_ARGUMENTS, *PIMMLOADLAYOUT_CALLBACK_ARGUMENTS; + +typedef struct _IMMLOADLAYOUT_CALLBACK_OUTPUT +{ + BOOL ret; + IMEINFOEX iiex; +} IMMLOADLAYOUT_CALLBACK_OUTPUT, *PIMMLOADLAYOUT_CALLBACK_OUTPUT; + NTSTATUS WINAPI User32CallCopyImageFromKernel(PVOID Arguments, ULONG ArgumentLength); NTSTATUS WINAPI @@ -216,4 +228,7 @@ NTSTATUS WINAPI User32CallUMPDFromKernel(PVOID Arguments, ULONG ArgumentLength); NTSTATUS WINAPI User32CallImmProcessKeyFromKernel(PVOID Arguments, ULONG ArgumentLength); +NTSTATUS WINAPI +User32CallImmLoadLayoutFromKernel(PVOID Arguments, ULONG ArgumentLength); + #endif /* __INCLUDE_USER32_CALLBACK_H */ diff --git a/win32ss/user/ntuser/callback.c b/win32ss/user/ntuser/callback.c index 4e1c053e4bf..801e8e971db 100644 --- a/win32ss/user/ntuser/callback.c +++ b/win32ss/user/ntuser/callback.c @@ -1272,4 +1272,50 @@ co_IntImmProcessKey(HWND hWnd, HKL hKL, UINT vKey, LPARAM lParam, DWORD dwHotKey return ret; } +/* Win: ClientImmLoadLayout */ +BOOL +APIENTRY +co_ClientImmLoadLayout( + _In_ HKL hKL, + _Inout_ PIMEINFOEX pImeInfoEx) +{ + BOOL ret; + NTSTATUS Status; + IMMLOADLAYOUT_CALLBACK_ARGUMENTS Common = { hKL }; + ULONG ResultLength = sizeof(IMMLOADLAYOUT_CALLBACK_OUTPUT); + PIMMLOADLAYOUT_CALLBACK_OUTPUT ResultPointer = NULL; + + RtlZeroMemory(pImeInfoEx, sizeof(IMEINFOEX)); + + UserLeaveCo(); + Status = KeUserModeCallback(USER32_CALLBACK_IMMLOADLAYOUT, + &Common, + sizeof(Common), + (PVOID*)&ResultPointer, + &ResultLength); + UserEnterCo(); + + if (!NT_SUCCESS(Status) || !ResultPointer || + ResultLength != sizeof(IMMLOADLAYOUT_CALLBACK_OUTPUT)) + { + ERR("0x%lX, %p, %lu\n", Status, ResultPointer, ResultLength); + return FALSE; + } + + _SEH2_TRY + { + ProbeForRead(ResultPointer, ResultLength, 1); + ret = ResultPointer->ret; + if (ret) + RtlCopyMemory(pImeInfoEx, &ResultPointer->iiex, sizeof(IMEINFOEX)); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = FALSE; + } + _SEH2_END; + + return ret; +} + /* EOF */ diff --git a/win32ss/user/ntuser/callback.h b/win32ss/user/ntuser/callback.h index 79217f86425..dde7152a952 100644 --- a/win32ss/user/ntuser/callback.h +++ b/win32ss/user/ntuser/callback.h @@ -80,3 +80,9 @@ BOOL FASTCALL IntMsgCreateStructW(PWND,CREATESTRUCTW*,CREATESTRUCTW*,PVOID*,PVOI DWORD APIENTRY co_IntImmProcessKey(HWND hWnd, HKL hKL, UINT vKey, LPARAM lParam, DWORD dwHotKeyID); + +BOOL +APIENTRY +co_ClientImmLoadLayout( + _In_ HKL hKL, + _Inout_ PIMEINFOEX pImeInfoEx); diff --git a/win32ss/user/ntuser/kbdlayout.c b/win32ss/user/ntuser/kbdlayout.c index 83d89d9632a..d41f53d3472 100644 --- a/win32ss/user/ntuser/kbdlayout.c +++ b/win32ss/user/ntuser/kbdlayout.c @@ -497,6 +497,10 @@ UserUnloadKbl(PKL pKl) pKl->pklPrev->pklNext = pKl->pklNext; pKl->pklNext->pklPrev = pKl->pklPrev; UnloadKbdFile(pKl->spkf); + if (pKl->piiex) + { + ExFreePoolWithTag(pKl->piiex, USERTAG_IME); + } UserDeleteObject(pKl->head.h, TYPE_KBDLAYOUT); return TRUE; } @@ -995,12 +999,34 @@ cleanup: 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 * * Loads keyboard layout with given locale id * * NOTE: We adopt a different design from Microsoft's one for security reason. + * We don't use the 1st and 3rd parameters of NtUserLoadKeyboardLayoutEx. */ HKL APIENTRY @@ -1015,7 +1041,7 @@ NtUserLoadKeyboardLayoutEx( { HKL hklRet = NULL; PKL pKl = NULL, pklLast; - WCHAR Buffer[9]; + WCHAR Buffer[KL_NAMELENGTH]; UNICODE_STRING ustrSafeKLID; if (Flags & ~(KLF_ACTIVATE|KLF_NOTELLSHELL|KLF_REORDER|KLF_REPLACELANG| @@ -1082,6 +1108,8 @@ NtUserLoadKeyboardLayoutEx( pKl->pklPrev = pKl; gspklBaseLayout = pKl; } + + pKl->piiex = co_UserImmLoadLayout(UlongToHandle(hkl)); } /* If this layout was prepared to unload, undo it */ diff --git a/win32ss/user/ntuser/ntuser.h b/win32ss/user/ntuser/ntuser.h index a72571dc26f..5060a661305 100644 --- a/win32ss/user/ntuser/ntuser.h +++ b/win32ss/user/ntuser/ntuser.h @@ -11,6 +11,7 @@ typedef VOID (*TL_FN_FREE)(PVOID); +/* Thread Lock structure */ typedef struct _TL { struct _TL* next; diff --git a/win32ss/user/user32/misc/dllmain.c b/win32ss/user/user32/misc/dllmain.c index 77fc525d913..18dd9ec0710 100644 --- a/win32ss/user/user32/misc/dllmain.c +++ b/win32ss/user/user32/misc/dllmain.c @@ -224,6 +224,7 @@ PVOID apfnDispatch[USER32_CALLBACK_MAXIMUM + 1] = User32CallLPKFromKernel, User32CallUMPDFromKernel, User32CallImmProcessKeyFromKernel, + User32CallImmLoadLayoutFromKernel, }; @@ -725,3 +726,12 @@ User32CallImmProcessKeyFromKernel(PVOID Arguments, ULONG ArgumentLength) return ZwCallbackReturn(&Result, sizeof(DWORD), STATUS_SUCCESS); } + +NTSTATUS WINAPI +User32CallImmLoadLayoutFromKernel(PVOID Arguments, ULONG ArgumentLength) +{ + PIMMLOADLAYOUT_CALLBACK_ARGUMENTS Common = Arguments; + IMMLOADLAYOUT_CALLBACK_OUTPUT Result; + Result.ret = IMM_FN(ImmLoadLayout)(Common->hKL, &Result.iiex); + return ZwCallbackReturn(&Result, sizeof(Result), STATUS_SUCCESS); +} diff --git a/win32ss/user/user32/windows/input.c b/win32ss/user/user32/windows/input.c index 1dfa587602e..a018d3aeca2 100644 --- a/win32ss/user/user32/windows/input.c +++ b/win32ss/user/user32/windows/input.c @@ -638,6 +638,13 @@ LoadKeyboardLayoutA(LPCSTR pszKLID, return LoadKeyboardLayoutW(wszKLID, Flags); } +inline BOOL IsValidKLID(_In_ LPCWSTR pwszKLID) +{ + return (pwszKLID != NULL) && (wcsspn(pwszKLID, L"0123456789ABCDEFabcdef") == (KL_NAMELENGTH - 1)); +} + +#define ENGLISH_US MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) + /* * @unimplemented * @@ -656,12 +663,20 @@ IntLoadKeyboardLayout( UNICODE_STRING ustrKbdName; UNICODE_STRING ustrKLID; WCHAR wszRegKey[256] = L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\"; - WCHAR wszLayoutId[10], wszNewKLID[10], szImeFileName[80]; + WCHAR wszLayoutId[10], wszNewKLID[KL_NAMELENGTH], szImeFileName[80]; + PWCHAR endptr; HKL hNewKL; HKEY hKey; BOOL bIsIME; - dwhkl = wcstoul(pwszKLID, NULL, 16); + if (!IsValidKLID(pwszKLID)) + { + ERR("pwszKLID: %s\n", debugstr_w(pwszKLID)); + return UlongToHandle(MAKELONG(ENGLISH_US, ENGLISH_US)); + } + + dwhkl = wcstoul(pwszKLID, &endptr, 16); + bIsIME = IS_IME_HKL(UlongToHandle(dwhkl)); if (!bIsIME) /* Not IME? */ { @@ -690,8 +705,7 @@ IntLoadKeyboardLayout( StringCbCatW(wszRegKey, sizeof(wszRegKey), pwszKLID); /* Open layout registry key for read */ - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRegKey, 0, - KEY_READ, &hKey) == ERROR_SUCCESS) + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRegKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { dwSize = sizeof(wszLayoutId); if (RegQueryValueExW(hKey, L"Layout Id", NULL, &dwType, (LPBYTE)wszLayoutId, &dwSize) == ERROR_SUCCESS) @@ -744,7 +758,7 @@ HKL WINAPI LoadKeyboardLayoutW(LPCWSTR pwszKLID, UINT Flags) { - TRACE("(%s, 0x%X)", debugstr_w(pwszKLID), Flags); + TRACE("(%s, 0x%X)\n", debugstr_w(pwszKLID), Flags); return IntLoadKeyboardLayout(NULL, pwszKLID, 0, Flags, FALSE); }