19#include <winpr/stream.h>
20#include <winpr/wlog.h>
22#include <freerdp/addin.h>
23#include <freerdp/client.h>
24#include <freerdp/client/channels.h>
25#include <freerdp/channels/rdpgfx.h>
26#include <freerdp/codec/zgfx.h>
27#include <freerdp/dvc.h>
29#define FUZZ_MAX_RECORDS 64
33 IDRDYNVC_ENTRY_POINTS iface;
40 IWTSVirtualChannelManager iface;
41 IWTSListener listener;
42 IWTSListenerCallback* listenerCallback;
43} fuzz_channel_manager;
45static UINT fuzz_register_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints,
46 WINPR_ATTR_UNUSED
const char* name, IWTSPlugin* pPlugin)
48 fuzz_entry_points* ep = (fuzz_entry_points*)pEntryPoints;
50 return CHANNEL_RC_ALREADY_INITIALIZED;
55static IWTSPlugin* fuzz_get_plugin(WINPR_ATTR_UNUSED IDRDYNVC_ENTRY_POINTS* pEntryPoints,
56 WINPR_ATTR_UNUSED
const char* name)
61static const ADDIN_ARGV* fuzz_get_plugin_data(WINPR_ATTR_UNUSED IDRDYNVC_ENTRY_POINTS* pEntryPoints)
66static rdpSettings* fuzz_get_rdp_settings(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
68 return ((fuzz_entry_points*)pEntryPoints)->context->settings;
71static rdpContext* fuzz_get_rdp_context(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
73 return ((fuzz_entry_points*)pEntryPoints)->context;
76static UINT fuzz_create_listener(IWTSVirtualChannelManager* pChannelMgr,
77 WINPR_ATTR_UNUSED
const char* pszChannelName,
78 WINPR_ATTR_UNUSED ULONG ulFlags,
79 IWTSListenerCallback* pListenerCallback, IWTSListener** ppListener)
81 fuzz_channel_manager* mgr = (fuzz_channel_manager*)pChannelMgr;
82 mgr->listenerCallback = pListenerCallback;
84 *ppListener = &mgr->listener;
88static UINT fuzz_destroy_listener(IWTSVirtualChannelManager* pChannelMgr,
89 WINPR_ATTR_UNUSED IWTSListener* pListener)
91 ((fuzz_channel_manager*)pChannelMgr)->listenerCallback =
nullptr;
95static UINT32 fuzz_get_channel_id(WINPR_ATTR_UNUSED IWTSVirtualChannel* channel)
100static const char* fuzz_get_channel_name(WINPR_ATTR_UNUSED IWTSVirtualChannel* channel)
102 return RDPGFX_DVC_CHANNEL_NAME;
105static IWTSVirtualChannel* fuzz_find_channel_by_id(WINPR_ATTR_UNUSED IWTSVirtualChannelManager* mgr,
106 WINPR_ATTR_UNUSED UINT32 ChannelId)
111static UINT fuzz_channel_write(WINPR_ATTR_UNUSED IWTSVirtualChannel* pChannel,
112 WINPR_ATTR_UNUSED ULONG cbSize,
113 WINPR_ATTR_UNUSED
const BYTE* pBuffer,
114 WINPR_ATTR_UNUSED
void* pReserved)
116 return CHANNEL_RC_OK;
119static UINT fuzz_channel_close(WINPR_ATTR_UNUSED IWTSVirtualChannel* pChannel)
121 return CHANNEL_RC_OK;
124static void fuzz_feed(IWTSVirtualChannelCallback* callback,
const uint8_t* data,
size_t size)
126 wStream buffer = WINPR_C_ARRAY_INIT;
127 wStream* s = Stream_StaticConstInit(&buffer, data, size);
129 if (Stream_GetRemainingLength(s) < 1)
131 const BOOL raw = (Stream_Get_UINT8(s) & 0x01) != 0;
133 wStream* pdu = Stream_New(
nullptr, UINT16_MAX + 2);
137 for (
size_t index = 0; index < FUZZ_MAX_RECORDS; index++)
139 if (Stream_GetRemainingLength(s) < 2)
142 size_t length = Stream_Get_UINT16(s);
143 if (length > Stream_GetRemainingLength(s))
144 length = Stream_GetRemainingLength(s);
146 Stream_ResetPosition(pdu);
149 Stream_Write_UINT8(pdu, ZGFX_SEGMENTED_SINGLE);
150 Stream_Write_UINT8(pdu, ZGFX_PACKET_COMPR_TYPE_RDP8);
152 Stream_Copy(s, pdu, length);
153 Stream_SealLength(pdu);
154 Stream_ResetPosition(pdu);
156 if (callback->OnDataReceived(callback, pdu) != CHANNEL_RC_OK)
160 Stream_Free(pdu, TRUE);
163int LLVMFuzzerTestOneInput(
const uint8_t* data,
size_t size)
165 if (size > (1u << 20))
168 wLog* root = WLog_GetRoot();
169 (void)WLog_SetLogLevel(root, WLOG_TRACE);
170 (void)WLog_SetLogAppenderType(root, WLOG_APPENDER_CALLBACK);
172 RDP_CLIENT_ENTRY_POINTS entry = WINPR_C_ARRAY_INIT;
173 entry.Version = RDP_CLIENT_INTERFACE_VERSION;
174 entry.Size =
sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
175 entry.ContextSize =
sizeof(rdpContext);
177 rdpContext* context = freerdp_client_context_new(&entry);
181 PDVC_PLUGIN_ENTRY pluginEntry = WINPR_FUNC_PTR_CAST(
182 freerdp_channels_load_static_addin_entry(RDPGFX_CHANNEL_NAME,
nullptr,
nullptr,
183 FREERDP_ADDIN_CHANNEL_DYNAMIC),
186 fuzz_entry_points ep = WINPR_C_ARRAY_INIT;
187 ep.iface.RegisterPlugin = fuzz_register_plugin;
188 ep.iface.GetPlugin = fuzz_get_plugin;
189 ep.iface.GetPluginData = fuzz_get_plugin_data;
190 ep.iface.GetRdpSettings = fuzz_get_rdp_settings;
191 ep.iface.GetRdpContext = fuzz_get_rdp_context;
192 ep.context = context;
194 if (!pluginEntry || (pluginEntry(&ep.iface) != CHANNEL_RC_OK) || !ep.plugin)
198 IWTSPlugin* plugin = ep.plugin;
200 fuzz_channel_manager mgr = WINPR_C_ARRAY_INIT;
201 mgr.iface.CreateListener = fuzz_create_listener;
202 mgr.iface.DestroyListener = fuzz_destroy_listener;
203 mgr.iface.GetChannelId = fuzz_get_channel_id;
204 mgr.iface.GetChannelName = fuzz_get_channel_name;
205 mgr.iface.FindChannelById = fuzz_find_channel_by_id;
207 IWTSVirtualChannel channel = WINPR_C_ARRAY_INIT;
208 channel.Write = fuzz_channel_write;
209 channel.Close = fuzz_channel_close;
211 if ((plugin->Initialize(plugin, &mgr.iface) == CHANNEL_RC_OK) && mgr.listenerCallback)
214 IWTSVirtualChannelCallback* callback =
nullptr;
216 if ((mgr.listenerCallback->OnNewChannelConnection(mgr.listenerCallback, &channel,
218 &callback) == CHANNEL_RC_OK) &&
221 if (callback->OnOpen(callback) == CHANNEL_RC_OK)
222 fuzz_feed(callback, data, size);
224 (void)callback->OnClose(callback);
229 (void)plugin->Terminated(plugin);
233 freerdp_client_context_free(context);