19#include <winpr/stream.h>
20#include <winpr/wlog.h>
21#include <winpr/wtsapi.h>
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>
30#include "../drdynvc_main.h"
32#define FUZZ_LISTENER_NAME "fuzz"
33#define FUZZ_OPEN_HANDLE 1
34#define FUZZ_MAX_RECORDS 256
38 PCHANNEL_INIT_EVENT_EX_FN initEvent;
39 PCHANNEL_OPEN_EVENT_EX_FN openEvent;
45 IWTSVirtualChannelCallback iface;
46 IWTSVirtualChannel* channel;
49static fuzz_vc g_vc = WINPR_C_ARRAY_INIT;
50static int g_initHandle = 0;
52static UINT VCAPITYPE fuzz_init_ex(LPVOID lpUserParam, WINPR_ATTR_UNUSED LPVOID clientContext,
53 WINPR_ATTR_UNUSED LPVOID pInitHandle,
55 WINPR_ATTR_UNUSED INT channelCount,
56 WINPR_ATTR_UNUSED ULONG versionRequested,
57 PCHANNEL_INIT_EVENT_EX_FN pChannelInitEventProcEx)
59 g_vc.userParam = lpUserParam;
60 g_vc.initEvent = pChannelInitEventProcEx;
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)
68 *pOpenHandle = FUZZ_OPEN_HANDLE;
69 g_vc.openEvent = pChannelOpenEventProcEx;
73static UINT VCAPITYPE fuzz_close_ex(WINPR_ATTR_UNUSED LPVOID pInitHandle,
74 WINPR_ATTR_UNUSED DWORD openHandle)
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)
85 g_vc.openEvent(g_vc.userParam, openHandle, CHANNEL_EVENT_WRITE_COMPLETE, pUserData, 0, 0,
88 Stream_Release((
wStream*)pUserData);
92static UINT fuzz_dvc_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
wStream* data)
94 fuzz_dvc_callback* callback = (fuzz_dvc_callback*)pChannelCallback;
95 const size_t length = Stream_GetRemainingLength(data);
98 if ((length == 0) || (length > UINT32_MAX) || !callback->channel)
100 return callback->channel->Write(callback->channel, (ULONG)length, Stream_ConstPointer(data),
104static UINT fuzz_dvc_on_open(WINPR_ATTR_UNUSED IWTSVirtualChannelCallback* pChannelCallback)
106 return CHANNEL_RC_OK;
109static UINT fuzz_dvc_on_close(IWTSVirtualChannelCallback* pChannelCallback)
111 free(pChannelCallback);
112 return CHANNEL_RC_OK;
116fuzz_on_new_channel_connection(WINPR_ATTR_UNUSED IWTSListenerCallback* pListenerCallback,
117 IWTSVirtualChannel* pChannel, WINPR_ATTR_UNUSED BYTE* Data,
118 BOOL* pbAccept, IWTSVirtualChannelCallback** ppCallback)
120 fuzz_dvc_callback* callback = (fuzz_dvc_callback*)calloc(1,
sizeof(fuzz_dvc_callback));
122 return CHANNEL_RC_NO_MEMORY;
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;
130 *ppCallback = &callback->iface;
131 return CHANNEL_RC_OK;
134static IWTSListenerCallback g_listener = { fuzz_on_new_channel_connection,
nullptr };
136static void fuzz_feed(
const uint8_t* data,
size_t size)
138 wStream buffer = WINPR_C_ARRAY_INIT;
139 wStream* s = Stream_StaticConstInit(&buffer, data, size);
141 for (
size_t index = 0; index < FUZZ_MAX_RECORDS; index++)
143 if (Stream_GetRemainingLength(s) < 5)
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);
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);
159int LLVMFuzzerTestOneInput(
const uint8_t* data,
size_t size)
161 if (size > (1u << 20))
164 wLog* root = WLog_GetRoot();
165 (void)WLog_SetLogLevel(root, WLOG_TRACE);
166 (void)WLog_SetLogAppenderType(root, WLOG_APPENDER_CALLBACK);
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);
173 rdpContext* context = freerdp_client_context_new(&entry);
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);
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;
200 const fuzz_vc empty = WINPR_C_ARRAY_INIT;
202 if (!entryEx((PCHANNEL_ENTRY_POINTS_EX)&entryPoints, &g_initHandle) || !g_vc.initEvent)
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);
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) ==
215 fuzz_feed(data, size);
218 g_vc.initEvent(g_vc.userParam, &g_initHandle, CHANNEL_EVENT_DISCONNECTED,
nullptr, 0);
220 g_vc.initEvent(g_vc.userParam, &g_initHandle, CHANNEL_EVENT_TERMINATED,
nullptr, 0);
223 freerdp_client_context_free(context);
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.