mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-09-20 03:11:02 +03:00
harden the format-data path against late/duplicate responses
The format-data rendezvous had the same single-slot race the file-contents path just fixed: the channel thread rewrote clipboard->hmem with no lock while explorer-thread consumers read/freed it, nothing serialized concurrent requests, and no flag told an expected response from a stray one. - Add format_request_mutex (serializes the whole request/response cycle) and hmem_mutex (guards the hmem hand-off and formatDataRespExpected). - cliprdr_send_data_request now takes ownership of the response buffer under hmem_mutex and returns it to the caller, so a later response cannot touch a buffer a consumer is using. All three consumers (GetData, WM_RENDERFORMAT, DELAYED_RENDERING) and the WM_CLIPBOARDUPDATE cleanup use the returned/taken handle instead of the shared slot. - The response handler drops any response arriving while formatDataRespExpected is clear (late/duplicate/unsolicited), consumes the flag on the first response, and no longer dereferences a NULL clipboard in the SetEvent path. Pre-existing issue, not introduced by this branch; generalizes the file-contents hardening to the format-data path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -150,6 +150,34 @@ START_TEST(test_file_contents_response_validates_data)
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_format_data_response_drops_unexpected)
|
||||
{
|
||||
wfClipboard clipboard = { 0 };
|
||||
CliprdrClientContext context = { 0 };
|
||||
CLIPRDR_FORMAT_DATA_RESPONSE response = { 0 };
|
||||
|
||||
clipboard.context = &context;
|
||||
clipboard.hmem_mutex = CreateMutex(NULL, FALSE, NULL);
|
||||
clipboard.formatDataRespEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
context.Custom = &clipboard;
|
||||
|
||||
ck_assert_ptr_nonnull(clipboard.hmem_mutex);
|
||||
ck_assert_ptr_nonnull(clipboard.formatDataRespEvent);
|
||||
|
||||
// With no outstanding request, an unsolicited response must be dropped: it must
|
||||
// not signal the event or write the hmem slot.
|
||||
clipboard.formatDataRespExpected = FALSE;
|
||||
response.msgFlags = CB_RESPONSE_OK;
|
||||
response.dataLen = 0;
|
||||
ck_assert_int_eq(wf_cliprdr_server_format_data_response(&context, &response), CHANNEL_RC_OK);
|
||||
ck_assert_int_eq(WaitForSingleObject(clipboard.formatDataRespEvent, 0), WAIT_TIMEOUT);
|
||||
ck_assert_ptr_null(clipboard.hmem);
|
||||
|
||||
CloseHandle(clipboard.formatDataRespEvent);
|
||||
CloseHandle(clipboard.hmem_mutex);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite *wf_cliprdr_invariant_suite(void)
|
||||
{
|
||||
Suite *s;
|
||||
@@ -166,6 +194,7 @@ Suite *wf_cliprdr_invariant_suite(void)
|
||||
tcase_add_test(tc_core, test_descriptor_size_rejects_extreme_count);
|
||||
tcase_add_test(tc_core, test_file_contents_request_initializes_optional_fields);
|
||||
tcase_add_test(tc_core, test_file_contents_response_validates_data);
|
||||
tcase_add_test(tc_core, test_format_data_response_drops_unexpected);
|
||||
|
||||
suite_add_tcase(s, tc_core);
|
||||
return s;
|
||||
|
||||
Reference in New Issue
Block a user