From 1c2188f80b75c72a091d562eb41d5fa0d5de98ae Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sat, 4 Jul 2026 16:31:32 +0800 Subject: [PATCH] add invariant tests for file contents request/response hardening Cover the zeroed optional request fields, stream ID filtering, oversized/NULL response rejection and the zero-byte EOF path. Co-Authored-By: Claude Fable 5 --- tests/test_invariant_wf_cliprdr.c | 97 +++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/tests/test_invariant_wf_cliprdr.c b/tests/test_invariant_wf_cliprdr.c index 3a75a5f3e..9828210a1 100644 --- a/tests/test_invariant_wf_cliprdr.c +++ b/tests/test_invariant_wf_cliprdr.c @@ -56,6 +56,101 @@ START_TEST(test_descriptor_size_rejects_extreme_count) } END_TEST +static UINT test_client_file_contents_request( + CliprdrClientContext *context, + const CLIPRDR_FILE_CONTENTS_REQUEST *request) +{ + CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; + + ck_assert_int_eq(request->haveClipDataId, FALSE); + ck_assert_int_eq(request->clipDataId, 0); + response.msgFlags = CB_RESPONSE_OK; + response.streamId = request->streamId; + return wf_cliprdr_server_file_contents_response(context, &response); +} + +START_TEST(test_file_contents_request_initializes_optional_fields) +{ + wfClipboard clipboard = { 0 }; + CliprdrClientContext context = { 0 }; + UINT rc; + + clipboard.context = &context; + clipboard.req_f_mutex = CreateMutex(NULL, FALSE, NULL); + clipboard.req_fevent = CreateEvent(NULL, TRUE, FALSE, NULL); + context.Custom = &clipboard; + context.ResponseWaitTimeoutSecs = 1; + context.ClientFileContentsRequest = test_client_file_contents_request; + + ck_assert_ptr_nonnull(clipboard.req_f_mutex); + ck_assert_ptr_nonnull(clipboard.req_fevent); + rc = cliprdr_send_request_filecontents(&clipboard, 1, (const void *)(ULONG_PTR)7, + 0, FILECONTENTS_SIZE, 0, 0, 0); + ck_assert_int_eq(rc, CHANNEL_RC_OK); + ck_assert_int_eq(clipboard.req_f_stream_id_expected, 7); + + CloseHandle(clipboard.req_fevent); + CloseHandle(clipboard.req_f_mutex); +} +END_TEST + +START_TEST(test_file_contents_response_validates_data) +{ + wfClipboard clipboard = { 0 }; + CliprdrClientContext context = { 0 }; + CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; + UINT rc; + + clipboard.context = &context; + clipboard.req_f_mutex = CreateMutex(NULL, FALSE, NULL); + clipboard.req_fevent = CreateEvent(NULL, TRUE, FALSE, NULL); + context.Custom = &clipboard; + context.ResponseWaitTimeoutSecs = 1; + response.msgFlags = CB_RESPONSE_OK; + response.cbRequested = 0; + clipboard.req_f_stream_id_expected = 7; + + ck_assert_ptr_nonnull(clipboard.req_f_mutex); + ck_assert_ptr_nonnull(clipboard.req_fevent); + + response.streamId = 8; + ck_assert_int_eq(wf_cliprdr_server_file_contents_response(&context, &response), + CHANNEL_RC_OK); + ck_assert_int_eq(WaitForSingleObject(clipboard.req_fevent, 0), WAIT_TIMEOUT); + ck_assert_ptr_null(clipboard.req_fdata); + ck_assert_int_eq(clipboard.req_fsize, 0); + ck_assert_int_eq(clipboard.req_f_response_ok, FALSE); + + response.streamId = 7; + ck_assert_int_eq(wf_cliprdr_server_file_contents_response(&context, &response), + CHANNEL_RC_OK); + ck_assert_ptr_null(clipboard.req_fdata); + ck_assert_int_eq(clipboard.req_fsize, 0); + ck_assert_int_eq(clipboard.req_f_response_ok, TRUE); + + rc = wait_response_event(0, &clipboard, clipboard.req_fevent, + &clipboard.req_f_received, (void **)&clipboard.req_fdata, + &clipboard.req_f_response_ok); + ck_assert_int_eq(rc, CHANNEL_RC_OK); + + response.cbRequested = 1; + clipboard.req_f_size_requested = 1; + ck_assert_int_eq(wf_cliprdr_server_file_contents_response(&context, &response), + ERROR_INTERNAL_ERROR); + ck_assert_ptr_null(clipboard.req_fdata); + ck_assert_int_eq(clipboard.req_fsize, 0); + ck_assert_int_eq(clipboard.req_f_response_ok, FALSE); + + rc = wait_response_event(0, &clipboard, clipboard.req_fevent, + &clipboard.req_f_received, (void **)&clipboard.req_fdata, + &clipboard.req_f_response_ok); + ck_assert_int_eq(rc, ERROR_INTERNAL_ERROR); + + CloseHandle(clipboard.req_fevent); + CloseHandle(clipboard.req_f_mutex); +} +END_TEST + Suite *wf_cliprdr_invariant_suite(void) { Suite *s; @@ -70,6 +165,8 @@ Suite *wf_cliprdr_invariant_suite(void) tcase_add_test(tc_core, test_descriptor_size_rejects_stream_count_above_limit); tcase_add_test(tc_core, test_descriptor_size_rejects_truncated_descriptor_array); 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); suite_add_tcase(s, tc_core); return s;