Coverage Report

Created: 2026-09-14 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/winpr/libwinpr/clipboard/test/TestFuzzWinPRClipboard.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * libFuzzer harness for the WinPR clipboard format synthesizers
4
 *
5
 * The cliprdr channel hands remote (attacker-controlled) clipboard payloads to
6
 * WinPR's clipboard subsystem, which converts between formats on demand using
7
 * the synthesizers in synthetic.c / synthetic_file.c (CF_DIB <-> bitmap file,
8
 * "HTML Format" <-> text/html, FileGroupDescriptorW <-> text/uri-list, ...).
9
 * Those parsers consume untrusted bytes but are not otherwise fuzzed.
10
 *
11
 * This harness registers a source format, stores the fuzz input under it, then
12
 * requests every other registered format so each applicable synthesizer parses
13
 * the payload.
14
 */
15
16
#include <stddef.h>
17
#include <stdint.h>
18
19
#include <winpr/crt.h>
20
#include <winpr/clipboard.h>
21
#include <winpr/wlog.h>
22
23
static const char* kSourceFormats[] = { "CF_DIB",
24
                                      "CF_DIBV5",
25
                                      "HTML Format",
26
                                      "text/html",
27
                                      "image/bmp",
28
                                      "image/png",
29
                                      "FileGroupDescriptorW",
30
                                      "text/uri-list",
31
                                      "CF_UNICODETEXT",
32
                                      "CF_TEXT",
33
                                      "CF_OEMTEXT" };
34
35
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
36
1.69k
{
37
1.69k
  static BOOL loggingInitialized = FALSE;
38
39
1.69k
  if (!loggingInitialized)
40
1
  {
41
1
    (void)WLog_SetLogLevel(WLog_GetRoot(), WLOG_TRACE);
42
1
    (void)WLog_SetLogAppenderType(WLog_GetRoot(), WLOG_APPENDER_CALLBACK);
43
1
    loggingInitialized = TRUE;
44
1
  }
45
46
1.69k
  if (size < 2)
47
2
    return 0;
48
1.69k
  if (size > (1u << 20))
49
0
    return 0;
50
51
1.69k
  wClipboard* clipboard = ClipboardCreate();
52
1.69k
  if (!clipboard)
53
0
    return 0;
54
55
1.69k
  const size_t count = sizeof(kSourceFormats) / sizeof(kSourceFormats[0]);
56
1.69k
  const char* srcName = kSourceFormats[data[0] % count];
57
58
1.69k
  UINT32 srcId = ClipboardRegisterFormat(clipboard, srcName);
59
1.69k
  if (srcId != 0)
60
1.69k
  {
61
    /* Store the remaining bytes as the (attacker) payload for srcName. */
62
1.69k
    (void)ClipboardSetData(clipboard, srcId, data + 1, (UINT32)(size - 1));
63
64
1.69k
    UINT32* formatIds = nullptr;
65
1.69k
    UINT32 numFormats = ClipboardGetFormatIds(clipboard, &formatIds);
66
67
7.64k
    for (UINT32 i = 0; i < numFormats; i++)
68
5.95k
    {
69
5.95k
      UINT32 outSize = 0;
70
5.95k
      void* out = ClipboardGetData(clipboard, formatIds[i], &outSize);
71
5.95k
      free(out);
72
5.95k
    }
73
1.69k
    free(formatIds);
74
1.69k
  }
75
76
1.69k
  ClipboardDestroy(clipboard);
77
1.69k
  return 0;
78
1.69k
}