FreeRDP
Loading...
Searching...
No Matches
TestFuzzDrdynvc.c
1
15#include <stddef.h>
16#include <stdint.h>
17
18#include <winpr/crt.h>
19#include <winpr/stream.h>
20#include <winpr/wlog.h>
21#include <winpr/wtsapi.h>
22
23#include <freerdp/addin.h>
24#include <freerdp/client.h>
25#include <freerdp/client/channels.h>
26#include <freerdp/channels/drdynvc.h>
27#include <freerdp/dvc.h>
28#include <freerdp/svc.h>
29
30#include "../drdynvc_main.h"
31
32#define FUZZ_LISTENER_NAME "fuzz"
33#define FUZZ_OPEN_HANDLE 1
34#define FUZZ_MAX_RECORDS 256
35
36typedef struct
37{
38 PCHANNEL_INIT_EVENT_EX_FN initEvent;
39 PCHANNEL_OPEN_EVENT_EX_FN openEvent;
40 LPVOID userParam;
41} fuzz_vc;
42
43typedef struct
44{
45 IWTSVirtualChannelCallback iface;
46 IWTSVirtualChannel* channel;
47} fuzz_dvc_callback;
48
49static fuzz_vc g_vc = WINPR_C_ARRAY_INIT;
50static int g_initHandle = 0;
51
52static UINT VCAPITYPE fuzz_init_ex(LPVOID lpUserParam, WINPR_ATTR_UNUSED LPVOID clientContext,
53 WINPR_ATTR_UNUSED LPVOID pInitHandle,
54 WINPR_ATTR_UNUSED PCHANNEL_DEF pChannel,
55 WINPR_ATTR_UNUSED INT channelCount,
56 WINPR_ATTR_UNUSED ULONG versionRequested,
57 PCHANNEL_INIT_EVENT_EX_FN pChannelInitEventProcEx)
58{
59 g_vc.userParam = lpUserParam;
60 g_vc.initEvent = pChannelInitEventProcEx;
61 return CHANNEL_RC_OK;
62}
63
64static UINT VCAPITYPE fuzz_open_ex(WINPR_ATTR_UNUSED LPVOID pInitHandle, LPDWORD pOpenHandle,
65 WINPR_ATTR_UNUSED PCHAR pChannelName,
66 PCHANNEL_OPEN_EVENT_EX_FN pChannelOpenEventProcEx)
67{
68 *pOpenHandle = FUZZ_OPEN_HANDLE;
69 g_vc.openEvent = pChannelOpenEventProcEx;
70 return CHANNEL_RC_OK;
71}
72
73static UINT VCAPITYPE fuzz_close_ex(WINPR_ATTR_UNUSED LPVOID pInitHandle,
74 WINPR_ATTR_UNUSED DWORD openHandle)
75{
76 return CHANNEL_RC_OK;
77}
78
79static UINT VCAPITYPE fuzz_write_ex(WINPR_ATTR_UNUSED LPVOID pInitHandle, DWORD openHandle,
80 WINPR_ATTR_UNUSED LPVOID pData,
81 WINPR_ATTR_UNUSED ULONG dataLength, LPVOID pUserData)
82{
83 /* the channel releases the written stream on CHANNEL_EVENT_WRITE_COMPLETE */
84 if (g_vc.openEvent)
85 g_vc.openEvent(g_vc.userParam, openHandle, CHANNEL_EVENT_WRITE_COMPLETE, pUserData, 0, 0,
86 0);
87 else
88 Stream_Release((wStream*)pUserData);
89 return CHANNEL_RC_OK;
90}
91
92static UINT fuzz_dvc_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
93{
94 fuzz_dvc_callback* callback = (fuzz_dvc_callback*)pChannelCallback;
95 const size_t length = Stream_GetRemainingLength(data);
96
97 /* echo back to exercise the client write and fragmentation path */
98 if ((length == 0) || (length > UINT32_MAX) || !callback->channel)
99 return CHANNEL_RC_OK;
100 return callback->channel->Write(callback->channel, (ULONG)length, Stream_ConstPointer(data),
101 nullptr);
102}
103
104static UINT fuzz_dvc_on_open(WINPR_ATTR_UNUSED IWTSVirtualChannelCallback* pChannelCallback)
105{
106 return CHANNEL_RC_OK;
107}
108
109static UINT fuzz_dvc_on_close(IWTSVirtualChannelCallback* pChannelCallback)
110{
111 free(pChannelCallback);
112 return CHANNEL_RC_OK;
113}
114
115static UINT
116fuzz_on_new_channel_connection(WINPR_ATTR_UNUSED IWTSListenerCallback* pListenerCallback,
117 IWTSVirtualChannel* pChannel, WINPR_ATTR_UNUSED BYTE* Data,
118 BOOL* pbAccept, IWTSVirtualChannelCallback** ppCallback)
119{
120 fuzz_dvc_callback* callback = (fuzz_dvc_callback*)calloc(1, sizeof(fuzz_dvc_callback));
121 if (!callback)
122 return CHANNEL_RC_NO_MEMORY;
123
124 callback->iface.OnDataReceived = fuzz_dvc_on_data_received;
125 callback->iface.OnOpen = fuzz_dvc_on_open;
126 callback->iface.OnClose = fuzz_dvc_on_close;
127 callback->channel = pChannel;
128
129 *pbAccept = TRUE;
130 *ppCallback = &callback->iface;
131 return CHANNEL_RC_OK;
132}
133
134static IWTSListenerCallback g_listener = { fuzz_on_new_channel_connection, nullptr };
135
136static void fuzz_feed(const uint8_t* data, size_t size)
137{
138 wStream buffer = WINPR_C_ARRAY_INIT;
139 wStream* s = Stream_StaticConstInit(&buffer, data, size);
140
141 for (size_t index = 0; index < FUZZ_MAX_RECORDS; index++)
142 {
143 if (Stream_GetRemainingLength(s) < 5)
144 break;
145
146 const UINT8 flags = Stream_Get_UINT8(s);
147 const UINT16 totalLength = Stream_Get_UINT16(s);
148 UINT16 length = Stream_Get_UINT16(s);
149 if (length > Stream_GetRemainingLength(s))
150 length = (UINT16)Stream_GetRemainingLength(s);
151
152 g_vc.openEvent(g_vc.userParam, FUZZ_OPEN_HANDLE, CHANNEL_EVENT_DATA_RECEIVED,
153 Stream_Pointer(s), length, totalLength,
154 flags & (CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST));
155 Stream_Seek(s, length);
156 }
157}
158
159int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
160{
161 if (size > (1u << 20))
162 return 0;
163
164 wLog* root = WLog_GetRoot();
165 (void)WLog_SetLogLevel(root, WLOG_TRACE);
166 (void)WLog_SetLogAppenderType(root, WLOG_APPENDER_CALLBACK);
167
168 RDP_CLIENT_ENTRY_POINTS entry = WINPR_C_ARRAY_INIT;
169 entry.Version = RDP_CLIENT_INTERFACE_VERSION;
170 entry.Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
171 entry.ContextSize = sizeof(rdpContext);
172
173 rdpContext* context = freerdp_client_context_new(&entry);
174 if (!context)
175 return 0;
176
177 /* process PDUs on the calling thread instead of the channel worker thread */
178 if (!freerdp_settings_set_bool(context->settings, FreeRDP_SynchronousDynamicChannels, TRUE))
179 goto fail;
180
181 {
182 PVIRTUALCHANNELENTRYEX entryEx =
183 WINPR_FUNC_PTR_CAST(freerdp_channels_load_static_addin_entry(
184 DRDYNVC_SVC_CHANNEL_NAME, nullptr, nullptr,
185 FREERDP_ADDIN_CHANNEL_STATIC | FREERDP_ADDIN_CHANNEL_ENTRYEX),
186 PVIRTUALCHANNELENTRYEX);
187 if (!entryEx)
188 goto fail;
189
190 CHANNEL_ENTRY_POINTS_FREERDP_EX entryPoints = WINPR_C_ARRAY_INIT;
191 entryPoints.cbSize = sizeof(entryPoints);
192 entryPoints.protocolVersion = VIRTUAL_CHANNEL_VERSION_WIN2000;
193 entryPoints.pVirtualChannelInitEx = fuzz_init_ex;
194 entryPoints.pVirtualChannelOpenEx = fuzz_open_ex;
195 entryPoints.pVirtualChannelCloseEx = fuzz_close_ex;
196 entryPoints.pVirtualChannelWriteEx = fuzz_write_ex;
197 entryPoints.MagicNumber = FREERDP_CHANNEL_MAGIC_NUMBER;
198 entryPoints.context = context;
199
200 const fuzz_vc empty = WINPR_C_ARRAY_INIT;
201 g_vc = empty;
202 if (!entryEx((PCHANNEL_ENTRY_POINTS_EX)&entryPoints, &g_initHandle) || !g_vc.initEvent)
203 goto fail;
204 }
205
206 g_vc.initEvent(g_vc.userParam, &g_initHandle, CHANNEL_EVENT_INITIALIZED, nullptr, 0);
207 g_vc.initEvent(g_vc.userParam, &g_initHandle, CHANNEL_EVENT_CONNECTED, nullptr, 0);
208
209 {
210 drdynvcPlugin* drdynvc = (drdynvcPlugin*)g_vc.userParam;
211 IWTSVirtualChannelManager* mgr = drdynvc->channel_mgr;
212 if (mgr && g_vc.openEvent &&
213 (mgr->CreateListener(mgr, FUZZ_LISTENER_NAME, 0, &g_listener, nullptr) ==
214 CHANNEL_RC_OK))
215 fuzz_feed(data, size);
216 }
217
218 g_vc.initEvent(g_vc.userParam, &g_initHandle, CHANNEL_EVENT_DISCONNECTED, nullptr, 0);
219 /* frees the plugin */
220 g_vc.initEvent(g_vc.userParam, &g_initHandle, CHANNEL_EVENT_TERMINATED, nullptr, 0);
221
222fail:
223 freerdp_client_context_free(context);
224 return 0;
225}
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.
Definition svc.h:60