From b87a3351a45e94bf72558127ce1f04c24129d585 Mon Sep 17 00:00:00 2001 From: Doug Lyons Date: Mon, 13 May 2024 22:55:54 -0500 Subject: [PATCH] [NTUSER] Implement BroadcastSystemMessage with 'Environment' parameter CORE-19372 CORE-19583 --- win32ss/user/ntuser/message.c | 54 ++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) 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; } }