This series of patches enable Adobe PDF Reader 11 protected mode, which is essentially a Chromium sandbox, to work properly.
From: Zhiyi Zhang zzhang@codeweavers.com
Chromium creates a suspended sandbox process with a token of limited access. Then it sets a token with normal access for the main thread of the newly created process. Without this change, explorer is started with the process token of limited access and fails to create a desktop window. --- dlls/win32u/winstation.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 9b97a4b4076..f1e16326b96 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -445,7 +445,8 @@ HWND get_desktop_window(void) static const WCHAR system_dir[] = {'C',':','\','w','i','n','d','o','w','s','\', 's','y','s','t','e','m','3','2','\',0}; RTL_USER_PROCESS_PARAMETERS params = { sizeof(params), sizeof(params) }; - PS_ATTRIBUTE_LIST ps_attr; + ULONG_PTR buffer[offsetof( PS_ATTRIBUTE_LIST, Attributes[2] ) / sizeof(ULONG_PTR)]; + PS_ATTRIBUTE_LIST *ps_attr = (PS_ATTRIBUTE_LIST *)buffer; PS_CREATE_INFO create_info; WCHAR desktop[MAX_PATH]; PEB *peb = NtCurrentTeb()->Peb; @@ -478,24 +479,30 @@ HWND get_desktop_window(void) RtlInitUnicodeString( ¶ms.WindowTitle, appnameW + 4 ); RtlInitUnicodeString( ¶ms.Desktop, desktop );
- ps_attr.TotalLength = sizeof(ps_attr); - ps_attr.Attributes[0].Attribute = PS_ATTRIBUTE_IMAGE_NAME; - ps_attr.Attributes[0].Size = sizeof(appnameW) - sizeof(WCHAR); - ps_attr.Attributes[0].ValuePtr = (WCHAR *)appnameW; - ps_attr.Attributes[0].ReturnLength = NULL; + ps_attr->Attributes[0].Attribute = PS_ATTRIBUTE_IMAGE_NAME; + ps_attr->Attributes[0].Size = sizeof(appnameW) - sizeof(WCHAR); + ps_attr->Attributes[0].ValuePtr = (WCHAR *)appnameW; + ps_attr->Attributes[0].ReturnLength = NULL; + + ps_attr->Attributes[1].Attribute = PS_ATTRIBUTE_TOKEN; + ps_attr->Attributes[1].Size = sizeof(HANDLE); + ps_attr->Attributes[1].ValuePtr = GetCurrentThreadEffectiveToken(); + ps_attr->Attributes[1].ReturnLength = NULL; + + ps_attr->TotalLength = offsetof( PS_ATTRIBUTE_LIST, Attributes[2] );
if (NtCurrentTeb64() && !NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR]) { NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR] = TRUE; status = NtCreateUserProcess( &process, &thread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS, NULL, NULL, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED, ¶ms, - &create_info, &ps_attr ); + &create_info, ps_attr ); NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR] = FALSE; } else status = NtCreateUserProcess( &process, &thread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS, NULL, NULL, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED, ¶ms, - &create_info, &ps_attr ); + &create_info, ps_attr ); if (!status) { NtResumeThread( thread, NULL );
From: Zhiyi Zhang zzhang@codeweavers.com
Test that processes running with an invisible window station have physical monitor information instead of the virtual monitor information used for services. --- dlls/user32/tests/winstation.c | 72 ++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+)
diff --git a/dlls/user32/tests/winstation.c b/dlls/user32/tests/winstation.c index e33a3252494..5902743c6ca 100644 --- a/dlls/user32/tests/winstation.c +++ b/dlls/user32/tests/winstation.c @@ -1026,8 +1026,71 @@ static void test_foregroundwindow(void) ok(timeout == timeout_old, "unexpected timeout %ld\n", timeout); }
+static void test_invisible_winstation_child(char *expected_info) +{ + char buffer[MAX_PATH]; + HDESK desktop; + int ret; + + desktop = GetThreadDesktop(GetCurrentThreadId()); + ok(!!desktop, "GetThreadDesktop failed, error %lu.\n", GetLastError()); + + ret = GetUserObjectInformationA(desktop, UOI_NAME, &buffer, sizeof(buffer), NULL); + ok(ret, "GetUserObjectInformationA failed, error %lu.\n", GetLastError()); + ok(!strcmp(buffer, "invisible_winstation_desktop"), "Got unexpected desktop %s.\n", buffer); + + sprintf(buffer, "%d,%d,%d,%d,%d", GetSystemMetrics(SM_XVIRTUALSCREEN), + GetSystemMetrics(SM_YVIRTUALSCREEN), GetSystemMetrics(SM_CXVIRTUALSCREEN), + GetSystemMetrics(SM_CYVIRTUALSCREEN), GetSystemMetrics(SM_CMONITORS)); + todo_wine_if(strcmp(buffer, "0,0,1024,768,1")) + ok(!strcmp(buffer, expected_info), "Expected %s, got %s.\n", expected_info, buffer); +} + +static void test_invisible_winstation(char **argv) +{ + char buffer[MAX_PATH], desktop_name[MAX_PATH]; + HWINSTA old_winstation, winstation; + PROCESS_INFORMATION pi = {0}; + STARTUPINFOA si = {0}; + HDESK desktop; + BOOL ret; + + old_winstation = GetProcessWindowStation(); + ok(!!old_winstation, "GetProcessWindowStation failed, error %lu.\n", GetLastError()); + winstation = CreateWindowStationW(NULL, 0, GENERIC_READ | WINSTA_CREATEDESKTOP, NULL); + ok(!!winstation, "CreateWindowStationW failed, error %lu.\n", GetLastError()); + ret = SetProcessWindowStation(winstation); + ok(ret, "SetProcessWindowStation failed, error %lu.\n", GetLastError()); + desktop = CreateDesktopA("invisible_winstation_desktop", NULL, NULL, 0, DESKTOP_CREATEWINDOW, NULL); + ok(!!desktop, "CreateDesktopA failed, error %lu.\n", GetLastError()); + + ret = GetUserObjectInformationA(winstation, UOI_NAME, buffer, sizeof(buffer), NULL); + ok(ret, "GetUserObjectInformationA failed, error %lu.\n", GetLastError()); + strcpy(desktop_name, buffer); + strcat(desktop_name, "\invisible_winstation_desktop"); + + si.cb = sizeof(si); + si.lpDesktop = desktop_name; + + sprintf(buffer, ""%s" %s invisible %d,%d,%d,%d,%d", argv[0], argv[1], + GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN), + GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN), + GetSystemMetrics(SM_CMONITORS)); + ret = CreateProcessA(argv[0], buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + ok(ret, "CreateProcessA failed, error %lu.\n", GetLastError()); + + wait_child_process(pi.hProcess); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + CloseDesktop(desktop); + CloseWindowStation(winstation); + SetProcessWindowStation(old_winstation); +} + START_TEST(winstation) { + char **argv; + int argc; HMODULE hntdll = GetModuleHandleA("ntdll.dll"); pNtQueryObject = (void *)GetProcAddress(hntdll, "NtQueryObject");
@@ -1041,6 +1104,14 @@ START_TEST(winstation) return; }
+ argc = winetest_get_mainargs(&argv); + if (argc > 2) + { + if (!lstrcmpA(argv[2], "invisible")) + test_invisible_winstation_child(argv[3]); + + return; + } test_inputdesktop(); test_inputdesktop2(); test_enumstations(); @@ -1048,4 +1119,5 @@ START_TEST(winstation) test_handles(); test_getuserobjectinformation(); test_foregroundwindow(); + test_invisible_winstation(argv); }
From: Zhiyi Zhang zzhang@codeweavers.com
Having an invisible window station doesn't mean an application is running in a service context. For example, Chromium creates a sandbox process to run in an invisible window station and still expect the physical monitor information to be returned, instead of the virtual monitor information for services. --- dlls/user32/tests/winstation.c | 1 - dlls/win32u/sysparams.c | 8 +++++--- 2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/dlls/user32/tests/winstation.c b/dlls/user32/tests/winstation.c index 5902743c6ca..7829e3364b3 100644 --- a/dlls/user32/tests/winstation.c +++ b/dlls/user32/tests/winstation.c @@ -1042,7 +1042,6 @@ static void test_invisible_winstation_child(char *expected_info) sprintf(buffer, "%d,%d,%d,%d,%d", GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN), GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN), GetSystemMetrics(SM_CMONITORS)); - todo_wine_if(strcmp(buffer, "0,0,1024,768,1")) ok(!strcmp(buffer, expected_info), "Expected %s, got %s.\n", expected_info, buffer); }
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index acda600b43c..233e5bb934b 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -1994,14 +1994,16 @@ static BOOL desktop_update_display_devices( BOOL force, struct device_manager_ct
BOOL update_display_cache( BOOL force ) { + static const WCHAR wine_service_station_name[] = + {'_','_','w','i','n','e','s','e','r','v','i','c','e','_','w','i','n','s','t','a','t','i','o','n',0}; HWINSTA winstation = NtUserGetProcessWindowStation(); struct device_manager_ctx ctx = {0}; BOOL was_virtual_desktop, ret; - USEROBJECTFLAGS flags; + WCHAR name[MAX_PATH];
/* services do not have any adapters, only a virtual monitor */ - if (NtUserGetObjectInformation( winstation, UOI_FLAGS, &flags, sizeof(flags), NULL ) - && !(flags.dwFlags & WSF_VISIBLE)) + if (NtUserGetObjectInformation( winstation, UOI_NAME, name, sizeof(name), NULL ) + && !wcscmp( name, wine_service_station_name )) { pthread_mutex_lock( &display_lock ); clear_display_devices();
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/user32/tests/winstation.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/dlls/user32/tests/winstation.c b/dlls/user32/tests/winstation.c index 7829e3364b3..ab64556a754 100644 --- a/dlls/user32/tests/winstation.c +++ b/dlls/user32/tests/winstation.c @@ -1030,6 +1030,7 @@ static void test_invisible_winstation_child(char *expected_info) { char buffer[MAX_PATH]; HDESK desktop; + HWND hwnd; int ret;
desktop = GetThreadDesktop(GetCurrentThreadId()); @@ -1043,6 +1044,13 @@ static void test_invisible_winstation_child(char *expected_info) GetSystemMetrics(SM_YVIRTUALSCREEN), GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN), GetSystemMetrics(SM_CMONITORS)); ok(!strcmp(buffer, expected_info), "Expected %s, got %s.\n", expected_info, buffer); + + hwnd = GetDesktopWindow(); + ok(!!hwnd, "GetDesktopWindow failed, error %lu.\n", GetLastError()); + + ret = SendMessageW(hwnd, WM_NCHITTEST, 0, 0); + todo_wine + ok(ret == HTCLIENT, "SendMessageW failed, error %lu.\n", GetLastError()); }
static void test_invisible_winstation(char **argv)
From: Zhiyi Zhang zzhang@codeweavers.com
The graphics driver information is stored as a property in the desktop window. When the server get_desktop_window handler simply returns a window handle when the window station is invisible, the window handle doesn't have the graphics driver property, which is set in desktop_window_proc() when handling WM_NCCREATE. Removing the invisible window station check allows an invisible explorer desktop window to be created and with the required property. --- dlls/user32/tests/winstation.c | 1 - server/window.c | 8 ++------ 2 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/dlls/user32/tests/winstation.c b/dlls/user32/tests/winstation.c index ab64556a754..5f0925a7712 100644 --- a/dlls/user32/tests/winstation.c +++ b/dlls/user32/tests/winstation.c @@ -1049,7 +1049,6 @@ static void test_invisible_winstation_child(char *expected_info) ok(!!hwnd, "GetDesktopWindow failed, error %lu.\n", GetLastError());
ret = SendMessageW(hwnd, WM_NCHITTEST, 0, 0); - todo_wine ok(ret == HTCLIENT, "SendMessageW failed, error %lu.\n", GetLastError()); }
diff --git a/server/window.c b/server/window.c index 328e3dfc64c..242e93f303a 100644 --- a/server/window.c +++ b/server/window.c @@ -2151,14 +2151,10 @@ DECL_HANDLER(destroy_window) DECL_HANDLER(get_desktop_window) { struct desktop *desktop = get_thread_desktop( current, 0 ); - int force;
if (!desktop) return;
- /* if winstation is invisible, then avoid roundtrip */ - force = req->force || !(desktop->winstation->flags & WSF_VISIBLE); - - if (!desktop->top_window && force) /* create it */ + if (!desktop->top_window && req->force) /* create it */ { if ((desktop->top_window = create_window( NULL, NULL, DESKTOP_ATOM, 0 ))) { @@ -2167,7 +2163,7 @@ DECL_HANDLER(get_desktop_window) } }
- if (!desktop->msg_window && force) /* create it */ + if (!desktop->msg_window && req->force) /* create it */ { static const WCHAR messageW[] = {'M','e','s','s','a','g','e'}; static const struct unicode_str name = { messageW, sizeof(messageW) };
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=134167
Your paranoid android.
=== debian11 (build log) ===
WineRunWineTest.pl:error: The task timed out
=== debian11b (build log) ===
WineRunWineTest.pl:error: The task timed out
On Mon Jun 26 11:49:58 2023 +0000, **** wrote:
Marvin replied on the mailing list:
Hi, It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated. The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=134167 Your paranoid android. === debian11 (build log) === WineRunWineTest.pl:error: The task timed out === debian11b (build log) === WineRunWineTest.pl:error: The task timed out
I will take a look at this. It's caused by 5/5 but it works fine locally.
Nitpick: Should be "a real" in the last commit message, not "an real".