Coverage Report

Created: 2026-07-30 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/channels/drdynvc/client/test/TestFuzzDrdynvc.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * libFuzzer harness for DVC wire framing
4
 */
5
6
#include <stddef.h>
7
#include <stdint.h>
8
9
#include <winpr/stream.h>
10
#include <winpr/wtypes.h>
11
12
static UINT32 fuzz_var_uint_bytes(UINT8 cbLen)
13
8.91k
{
14
8.91k
  switch (cbLen)
15
8.91k
  {
16
5.03k
    case 0:
17
5.03k
      return 1;
18
1.71k
    case 1:
19
1.71k
      return 2;
20
2.16k
    default:
21
2.16k
      return 4;
22
8.91k
  }
23
8.91k
}
24
25
static UINT32 fuzz_read_variable_uint(wStream* s, UINT8 cbLen)
26
5.81k
{
27
5.81k
  UINT32 value = 0;
28
29
5.81k
  switch (cbLen)
30
5.81k
  {
31
2.44k
    case 0:
32
2.44k
      value = Stream_Get_UINT8(s);
33
2.44k
      break;
34
1.50k
    case 1:
35
1.50k
      value = Stream_Get_UINT16(s);
36
1.50k
      break;
37
1.85k
    default:
38
1.85k
      value = Stream_Get_UINT32(s);
39
1.85k
      break;
40
5.81k
  }
41
42
5.81k
  return value;
43
5.81k
}
44
45
enum
46
{
47
  CREATE_REQUEST_PDU = 0x01,
48
  DATA_FIRST_PDU = 0x02,
49
  DATA_PDU = 0x03,
50
  CLOSE_REQUEST_PDU = 0x04,
51
  CAPABILITY_REQUEST_PDU = 0x05,
52
  DATA_FIRST_COMPRESSED_PDU = 0x06,
53
  DATA_COMPRESSED_PDU = 0x07
54
};
55
56
static int fuzz_process_one_pdu(wStream* s)
57
7.13k
{
58
7.13k
  const size_t required = 1;
59
60
7.13k
  if (!Stream_CheckAndLogRequiredLength("fuzz", s, required))
61
0
    return -1;
62
63
7.13k
  UINT8 header = Stream_Get_UINT8(s);
64
7.13k
  UINT8 command = (header & 0xf0) >> 4;
65
7.13k
  UINT8 spacing = (header & 0x0c) >> 2;
66
7.13k
  UINT8 cbChId = (header & 0x03);
67
7.13k
  size_t needed = fuzz_var_uint_bytes(cbChId);
68
69
7.13k
  switch (command)
70
7.13k
  {
71
851
    case DATA_FIRST_PDU:
72
1.78k
    case DATA_FIRST_COMPRESSED_PDU:
73
1.78k
      if (!Stream_CheckAndLogRequiredLength("fuzz", s, needed + fuzz_var_uint_bytes(spacing)))
74
30
        return -1;
75
1.75k
      (void)fuzz_read_variable_uint(s, cbChId);
76
1.75k
      (void)fuzz_read_variable_uint(s, spacing);
77
1.75k
      break;
78
453
    case DATA_PDU:
79
1.09k
    case DATA_COMPRESSED_PDU:
80
1.75k
    case CLOSE_REQUEST_PDU:
81
2.35k
    case CREATE_REQUEST_PDU:
82
2.35k
      if (!Stream_CheckAndLogRequiredLength("fuzz", s, needed))
83
42
        return -1;
84
2.30k
      (void)fuzz_read_variable_uint(s, cbChId);
85
2.30k
      break;
86
213
    case CAPABILITY_REQUEST_PDU:
87
213
      if (!Stream_CheckAndLogRequiredLength("fuzz", s, 2))
88
4
        return -1;
89
209
      Stream_Seek(s, 2);
90
209
      break;
91
2.79k
    default:
92
2.79k
      break;
93
7.13k
  }
94
95
7.06k
  if (!Stream_CheckAndLogRequiredLength("fuzz", s, 2))
96
94
    return -1;
97
98
6.96k
  {
99
6.96k
    size_t bodyLen = Stream_Get_UINT16(s);
100
6.96k
    const size_t remaining = Stream_GetRemainingLength(s);
101
6.96k
    if (bodyLen > remaining)
102
177
      bodyLen = remaining;
103
6.96k
    Stream_Seek(s, bodyLen);
104
6.96k
  }
105
106
6.96k
  return 0;
107
7.06k
}
108
109
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
110
395
{
111
395
  if ((size == 0) || (size > (1u << 20)))
112
0
    return 0;
113
114
395
  wStream buffer = WINPR_C_ARRAY_INIT;
115
395
  wStream* s = Stream_StaticConstInit(&buffer, data, size);
116
395
  if (!s)
117
0
    return 0;
118
119
7.36k
  for (size_t index = 0; index < 64; index++)
120
7.32k
  {
121
7.32k
    if (Stream_GetRemainingLength(s) == 0)
122
188
      break;
123
7.13k
    if (fuzz_process_one_pdu(s) != 0)
124
170
      break;
125
7.13k
  }
126
127
395
  return 0;
128
395
}