Coverage Report

Created: 2026-07-16 07:09

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_OFF);
42
1
    loggingInitialized = TRUE;
43
1
  }
44
45
1.69k
  if (size < 2)
46
2
    return 0;
47
1.69k
  if (size > (1u << 20))
48
0
    return 0;
49
50
1.69k
  wClipboard* clipboard = ClipboardCreate();
51
1.69k
  if (!clipboard)
52
0
    return 0;
53
54
1.69k
  const size_t count = sizeof(kSourceFormats) / sizeof(kSourceFormats[0]);
55
1.69k
  const char* srcName = kSourceFormats[data[0] % count];
56
57
1.69k
  UINT32 srcId = ClipboardRegisterFormat(clipboard, srcName);
58
1.69k
  if (srcId != 0)
59
1.69k
  {
60
    /* Store the remaining bytes as the (attacker) payload for srcName. */
61
1.69k
    (void)ClipboardSetData(clipboard, srcId, data + 1, (UINT32)(size - 1));
62
63
1.69k
    UINT32* formatIds = nullptr;
64
1.69k
    UINT32 numFormats = ClipboardGetFormatIds(clipboard, &formatIds);
65
66
7.64k
    for (UINT32 i = 0; i < numFormats; i++)
67
5.95k
    {
68
5.95k
      UINT32 outSize = 0;
69
5.95k
      void* out = ClipboardGetData(clipboard, formatIds[i], &outSize);
70
5.95k
      free(out);
71
5.95k
    }
72
1.69k
    free(formatIds);
73
1.69k
  }
74
75
1.69k
  ClipboardDestroy(clipboard);
76
1.69k
  return 0;
77
1.69k
}