diff --git "a/win32ss/user/ntuser/message.c" "b/win32ss/user/ntuser/message.c" index ce9da97c1a5..e02837c33bb 100644 --- "a/win32ss/user/ntuser/message.c" +++ "b/win32ss/user/ntuser/message.c" @@ -12,9 +12,33 @@ DBG_DEFAULT_CHANNEL(UserMsg); #define PM_BADMSGFLAGS ~((QS_RAWINPUT << 16)|PM_QS_SENDMESSAGE|PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_QS_INPUT|PM_NOYIELD|PM_REMOVE) +#define EXCEPTION_ACCESS_VIOLATION ((DWORD)0xC0000005) + +/* Strings that are OK to pass between user and kernel mode + * There may be other strings needed that can easily be added here. */ +WCHAR StrUserKernel[3][20] = {{L"intl"}, {L"Environment"}, {L"Policy"}}; /* FUNCTIONS *****************************************************************/ +/* PosInArray checks for strings that can pass between user and kernel mode. + * See: https://learn.microsoft.com/en-us/windows/win32/winmsg/wm-settingchange + * It mentions 'Environment', 'intl', and 'Policy'. + * These strings are enumerated in the StrUserKernel definition. + * Returns: A positive integer indicating its position in the array if the + * string is found, or returns a minus one (-1) if the string is not found. */ +INT PosInArray(WCHAR String[]) +{ + INT i; + INT End = ARRAYSIZE(StrUserKernel); + + for (i = 0; i < End; ++i) + { + if (wcsncmp(String, StrUserKernel[i], sizeof(StrUserKernel[0])) == 0) + return i; + } + return -1; +} + NTSTATUS FASTCALL IntInitMessageImpl(VOID) { @@ -459,8 +483,30 @@ CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEnt /* Copy data if required */ if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_READ)) { + WCHAR lParamMsg[sizeof(StrUserKernel[0])/2 + 1] = { 0 }; + TRACE("Copy Message %u from usermode buffer\n", KernelModeMsg->message); - Status = MmCopyFromCaller(KernelMem, (PVOID) UserModeMsg->lParam, Size); + + _SEH2_TRY + { + if (UserModeMsg->lParam) + RtlCopyMemory( lParamMsg, (WCHAR*)UserModeMsg->lParam, sizeof(lParamMsg)); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + _SEH2_YIELD(return EXCEPTION_ACCESS_VIOLATION); + } + _SEH2_END; + + if (UserModeMsg->lParam && !UserModeMsg->wParam && + PosInArray(lParamMsg) >= 0) + { + TRACE("Copy String '%S' from usermode buffer\n", lParamMsg); + wcscpy(KernelMem, lParamMsg); + return STATUS_SUCCESS; + } + else + Status = MmCopyFromCaller(KernelMem, (PVOID) UserModeMsg->lParam, Size); if (! NT_SUCCESS(Status)) { ERR("Failed to copy message to kernel: invalid usermode lParam buffer\n"); @@ -2721,6 +2767,12 @@ NtUserMessageCall( HWND hWnd, } ExFreePoolWithTag(List, USERTAG_WINDOWLIST); } + if (lParam && !wParam && wcscmp((WCHAR*)lParam, L"Environment") == 0) + { + /* Handle Broadcast of WM_SETTINGCHAGE for Environment */ + co_IntDoSendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, + 0, (LPARAM)L"Environment", 0); + } Ret = TRUE; } }