FreeRDP
Loading...
Searching...
No Matches
TestFuzzChannelRdpgfx.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
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>
28
29#define FUZZ_MAX_RECORDS 64
30
31typedef struct
32{
33 IDRDYNVC_ENTRY_POINTS iface;
34 rdpContext* context;
35 IWTSPlugin* plugin;
36} fuzz_entry_points;
37
38typedef struct
39{
40 IWTSVirtualChannelManager iface;
41 IWTSListener listener;
42 IWTSListenerCallback* listenerCallback;
43} fuzz_channel_manager;
44
45static UINT fuzz_register_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints,
46 WINPR_ATTR_UNUSED const char* name, IWTSPlugin* pPlugin)
47{
48 fuzz_entry_points* ep = (fuzz_entry_points*)pEntryPoints;
49 if (ep->plugin)
50 return CHANNEL_RC_ALREADY_INITIALIZED;
51 ep->plugin = pPlugin;
52 return CHANNEL_RC_OK;
53}
54
55static IWTSPlugin* fuzz_get_plugin(WINPR_ATTR_UNUSED IDRDYNVC_ENTRY_POINTS* pEntryPoints,
56 WINPR_ATTR_UNUSED const char* name)
57{
58 return nullptr;
59}
60
61static const ADDIN_ARGV* fuzz_get_plugin_data(WINPR_ATTR_UNUSED IDRDYNVC_ENTRY_POINTS* pEntryPoints)
62{
63 return nullptr;
64}
65
66static rdpSettings* fuzz_get_rdp_settings(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
67{
68 return ((fuzz_entry_points*)pEntryPoints)->context->settings;
69}
70
71static rdpContext* fuzz_get_rdp_context(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
72{
73 return ((fuzz_entry_points*)pEntryPoints)->context;
74}
75
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)
80{
81 fuzz_channel_manager* mgr = (fuzz_channel_manager*)pChannelMgr;
82 mgr->listenerCallback = pListenerCallback;
83 if (ppListener)
84 *ppListener = &mgr->listener;
85 return CHANNEL_RC_OK;
86}
87
88static UINT fuzz_destroy_listener(IWTSVirtualChannelManager* pChannelMgr,
89 WINPR_ATTR_UNUSED IWTSListener* pListener)
90{
91 ((fuzz_channel_manager*)pChannelMgr)->listenerCallback = nullptr;
92 return CHANNEL_RC_OK;
93}
94
95static UINT32 fuzz_get_channel_id(WINPR_ATTR_UNUSED IWTSVirtualChannel* channel)
96{
97 return 1;
98}
99
100static const char* fuzz_get_channel_name(WINPR_ATTR_UNUSED IWTSVirtualChannel* channel)
101{
102 return RDPGFX_DVC_CHANNEL_NAME;
103}
104
105static IWTSVirtualChannel* fuzz_find_channel_by_id(WINPR_ATTR_UNUSED IWTSVirtualChannelManager* mgr,
106 WINPR_ATTR_UNUSED UINT32 ChannelId)
107{
108 return nullptr;
109}
110
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)
115{
116 return CHANNEL_RC_OK;
117}
118
119static UINT fuzz_channel_close(WINPR_ATTR_UNUSED IWTSVirtualChannel* pChannel)
120{
121 return CHANNEL_RC_OK;
122}
123
124static void fuzz_feed(IWTSVirtualChannelCallback* callback, const uint8_t* data, size_t size)
125{
126 wStream buffer = WINPR_C_ARRAY_INIT;
127 wStream* s = Stream_StaticConstInit(&buffer, data, size);
128
129 if (Stream_GetRemainingLength(s) < 1)
130 return;
131 const BOOL raw = (Stream_Get_UINT8(s) & 0x01) != 0;
132
133 wStream* pdu = Stream_New(nullptr, UINT16_MAX + 2);
134 if (!pdu)
135 return;
136
137 for (size_t index = 0; index < FUZZ_MAX_RECORDS; index++)
138 {
139 if (Stream_GetRemainingLength(s) < 2)
140 break;
141
142 size_t length = Stream_Get_UINT16(s);
143 if (length > Stream_GetRemainingLength(s))
144 length = Stream_GetRemainingLength(s);
145
146 Stream_ResetPosition(pdu);
147 if (!raw)
148 {
149 Stream_Write_UINT8(pdu, ZGFX_SEGMENTED_SINGLE);
150 Stream_Write_UINT8(pdu, ZGFX_PACKET_COMPR_TYPE_RDP8);
151 }
152 Stream_Copy(s, pdu, length);
153 Stream_SealLength(pdu);
154 Stream_ResetPosition(pdu);
155
156 if (callback->OnDataReceived(callback, pdu) != CHANNEL_RC_OK)
157 break;
158 }
159
160 Stream_Free(pdu, TRUE);
161}
162
163int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
164{
165 if (size > (1u << 20))
166 return 0;
167
168 wLog* root = WLog_GetRoot();
169 (void)WLog_SetLogLevel(root, WLOG_TRACE);
170 (void)WLog_SetLogAppenderType(root, WLOG_APPENDER_CALLBACK);
171
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);
176
177 rdpContext* context = freerdp_client_context_new(&entry);
178 if (!context)
179 return 0;
180
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),
184 PDVC_PLUGIN_ENTRY);
185
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;
193
194 if (!pluginEntry || (pluginEntry(&ep.iface) != CHANNEL_RC_OK) || !ep.plugin)
195 goto fail;
196
197 {
198 IWTSPlugin* plugin = ep.plugin;
199
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;
206
207 IWTSVirtualChannel channel = WINPR_C_ARRAY_INIT;
208 channel.Write = fuzz_channel_write;
209 channel.Close = fuzz_channel_close;
210
211 if ((plugin->Initialize(plugin, &mgr.iface) == CHANNEL_RC_OK) && mgr.listenerCallback)
212 {
213 BOOL accept = TRUE;
214 IWTSVirtualChannelCallback* callback = nullptr;
215
216 if ((mgr.listenerCallback->OnNewChannelConnection(mgr.listenerCallback, &channel,
217 nullptr, &accept,
218 &callback) == CHANNEL_RC_OK) &&
219 callback)
220 {
221 if (callback->OnOpen(callback) == CHANNEL_RC_OK)
222 fuzz_feed(callback, data, size);
223 /* frees the channel callback */
224 (void)callback->OnClose(callback);
225 }
226 }
227
228 /* frees the plugin */
229 (void)plugin->Terminated(plugin);
230 }
231
232fail:
233 freerdp_client_context_free(context);
234 return 0;
235}