diff --git a/apps/desktop/src/platform/windows/screen_capturer/screen_capturer_win.cpp b/apps/desktop/src/platform/windows/screen_capturer/screen_capturer_win.cpp index 3b4c9523..04f05286 100644 --- a/apps/desktop/src/platform/windows/screen_capturer/screen_capturer_win.cpp +++ b/apps/desktop/src/platform/windows/screen_capturer/screen_capturer_win.cpp @@ -1138,6 +1138,18 @@ void ScreenCapturerWin::SecureDesktopCaptureLoop() { max_status_ms = 0; }; std::vector secure_frame; + ULONGLONG last_shared_error_tick = 0; + auto report_shared_error = [&](const char* operation, + const std::string& error) { + const ULONGLONG now = GetTickCount64(); + if (last_shared_error_tick == 0 || now - last_shared_error_tick >= 5000) { + LOG_WARN( + "Windows capturer secure shared capture {} failed; using pipe " + "fallback, stage='{}', session_id={}, error={}", + operation, status.interactive_stage, status.active_session_id, error); + last_shared_error_tick = now; + } + }; while (running_.load(std::memory_order_relaxed)) { // Privacy covers belong to the ordinary desktop. Drop privacy on a @@ -1285,6 +1297,7 @@ void ScreenCapturerWin::SecureDesktopCaptureLoop() { status.interactive_stage, status.interactive_desktop, show_cursor, shared_fps, &error_message); if (!shared_ready) { + report_shared_error("start", error_message); frame_schedule.OnStartFailure(GetTickCount64()); } else if (!was_started) { frame_schedule.Reset(GetTickCount64()); @@ -1304,6 +1317,7 @@ void ScreenCapturerWin::SecureDesktopCaptureLoop() { IsPendingSecureDesktopFrame(error_message); if (frame_pending) ++shared_waits; if (shared_ready && !frame_delivered && !frame_pending) { + report_shared_error("read", error_message); StopSecureDesktopSharedCapture(secure_shared_session_id_); frame_schedule.OnStartFailure(GetTickCount64()); } diff --git a/apps/desktop/src/platform/windows/service/session_helper_main.cpp b/apps/desktop/src/platform/windows/service/session_helper_main.cpp index 1e8bdfc4..ce9aac21 100644 --- a/apps/desktop/src/platform/windows/service/session_helper_main.cpp +++ b/apps/desktop/src/platform/windows/service/session_helper_main.cpp @@ -98,18 +98,18 @@ struct SecureSharedCaptureState { uint32_t sequence = 0; }; -struct PipeSecurityAttributes { - PipeSecurityAttributes() = default; - ~PipeSecurityAttributes() { +struct IpcSecurityAttributes { + IpcSecurityAttributes() = default; + ~IpcSecurityAttributes() { if (security_descriptor_ != nullptr) { LocalFree(security_descriptor_); } } - bool Initialize() { - constexpr wchar_t kPipeSddl[] = L"D:(A;;GA;;;SY)(A;;GA;;;BA)(A;;GRGW;;;AU)"; + bool Initialize(const wchar_t* sddl = + L"D:(A;;GA;;;SY)(A;;GA;;;BA)(A;;GRGW;;;AU)") { if (!ConvertStringSecurityDescriptorToSecurityDescriptorW( - kPipeSddl, SDDL_REVISION_1, &security_descriptor_, nullptr)) { + sddl, SDDL_REVISION_1, &security_descriptor_, nullptr)) { return false; } @@ -453,7 +453,7 @@ std::string BuildHelperStatusResponse(HelperState* helper_state) { void HelperIpcServerLoop(HANDLE stop_event, DWORD session_id, HelperState* helper_state) { - PipeSecurityAttributes security_attributes; + IpcSecurityAttributes security_attributes; SECURITY_ATTRIBUTES* pipe_attributes = nullptr; if (security_attributes.Initialize()) { pipe_attributes = security_attributes.get(); @@ -1471,12 +1471,21 @@ std::vector StartSecureDesktopSharedCapture( return BuildTextResponseBytes(BuildErrorJson("invalid_capture_size")); } - PipeSecurityAttributes security_attributes; + IpcSecurityAttributes security_attributes; SECURITY_ATTRIBUTES* attributes = nullptr; if (security_attributes.Initialize()) { attributes = security_attributes.get(); } + // Event GENERIC_READ/GENERIC_WRITE omit SYNCHRONIZE. The GUI only needs + // to wait for frames; the SYSTEM helper retains permission to signal them. + IpcSecurityAttributes event_security_attributes; + if (!event_security_attributes.Initialize( + L"D:(A;;GA;;;SY)(A;;GA;;;BA)(A;;0x00100000;;;AU)")) { + return BuildTextResponseBytes( + BuildErrorJson("create_frame_event_security_failed", GetLastError())); + } + const std::wstring mapping_name = crossdesk::GetCrossDeskSecureDesktopFrameMappingName( capture_state->session_id); @@ -1503,7 +1512,8 @@ std::vector StartSecureDesktopSharedCapture( } HANDLE frame_ready_event = - CreateEventW(attributes, FALSE, FALSE, event_name.c_str()); + CreateEventW(event_security_attributes.get(), FALSE, FALSE, + event_name.c_str()); if (frame_ready_event == nullptr) { const DWORD error = GetLastError(); UnmapViewOfFile(frame_view); @@ -1665,7 +1675,7 @@ void SecureInputHelperIpcServerLoop(HANDLE stop_event, DWORD session_id) { auto capture_state = std::make_shared(); capture_state->session_id = session_id; - PipeSecurityAttributes security_attributes; + IpcSecurityAttributes security_attributes; SECURITY_ATTRIBUTES* pipe_attributes = nullptr; if (security_attributes.Initialize()) { pipe_attributes = security_attributes.get();