FreeRDP
Loading...
Searching...
No Matches
TestFuzzServer.c
1
25#include <freerdp/peer.h>
26#include <freerdp/freerdp.h>
27
28#include <freerdp/settings.h>
29#include <freerdp/constants.h>
30#include <freerdp/crypto/certificate.h>
31#include <freerdp/crypto/privatekey.h>
32
33#include <freerdp/channels/wtsvc.h>
34#include <freerdp/channels/channels.h>
35
36#include "../multitransport.h"
37
38#include <winpr/assert.h>
39#include <winpr/ssl.h>
40#include <winpr/wlog.h>
41
42#ifdef _WIN32
43#error "WIN32 not supported, remove this file from compile!"
44#endif
45
46#include <sys/socket.h>
47#include <unistd.h>
48#include <fcntl.h>
49#include <errno.h>
50
51#define TEST_SERVER_MAX_ITERATIONS (1 << 20)
52
53#include "TestFuzzServerCerts.h"
54
55static BOOL test_peer_post_connect(freerdp_peer* peer)
56{
57 WINPR_ASSERT(peer);
58 return TRUE;
59}
60
61static BOOL test_peer_activate(freerdp_peer* peer)
62{
63 WINPR_ASSERT(peer);
64 return TRUE;
65}
66
67static int test_peer_virtual_channel_read(freerdp_peer* peer, HANDLE hChannel, BYTE* buffer,
68 UINT32 length)
69{
70 WINPR_UNUSED(peer);
71 WINPR_UNUSED(hChannel);
72 WINPR_UNUSED(buffer);
73 WINPR_UNUSED(length);
74 return 0;
75}
76
77struct test_peer_context
78{
79 rdpContext _p;
80
81 HANDLE vcm;
82};
83typedef struct test_peer_context testPeerContext;
84
85static void test_peer_context_free(freerdp_peer* client, rdpContext* ctx)
86{
87 testPeerContext* context = (testPeerContext*)ctx;
88
89 WINPR_UNUSED(client);
90
91 if (context && context->vcm)
92 {
93 WTSCloseServer(context->vcm);
94 context->vcm = NULL;
95 }
96}
97
98static BOOL test_peer_context_new(freerdp_peer* client, rdpContext* ctx)
99{
100 testPeerContext* context = (testPeerContext*)ctx;
101
102 WINPR_ASSERT(client);
103 WINPR_ASSERT(context);
104
105 context->vcm = WTSOpenServerA((LPSTR)client->context);
106 if (!context->vcm || context->vcm == INVALID_HANDLE_VALUE)
107 goto fail;
108
109 return TRUE;
110fail:
111 test_peer_context_free(client, ctx);
112 return FALSE;
113}
114
115static BOOL test_server_one(const char* fkey, const char* fcert, const uint8_t* Data, size_t Size)
116{
117 int sv[2] = WINPR_C_ARRAY_INIT;
118
119 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) != 0)
120 return FALSE;
121
122 freerdp_peer* client = freerdp_peer_new(sv[0]);
123 if (!client)
124 {
125 close(sv[0]);
126 close(sv[1]);
127 return FALSE;
128 }
129
130 client->ContextSize = sizeof(testPeerContext);
131 client->ContextNew = test_peer_context_new;
132 client->ContextFree = test_peer_context_free;
133 if (!freerdp_peer_context_new(client))
134 goto fail;
135
136 WINPR_ASSERT(client->context);
137 rdpSettings* settings = client->context->settings;
138 WINPR_ASSERT(settings);
139
140 rdpCertificate* cert = freerdp_certificate_new_from_file(fcert);
141 if (!cert)
142 goto fail;
143 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerCertificate, cert, 1))
144 goto fail;
145
146 rdpPrivateKey* key = freerdp_key_new_from_file(fkey);
147 if (!key)
148 goto fail;
149 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerRsaKey, key, 1))
150 goto fail;
151
152 /*
153 * Plain RDP security. Together with the local peer flag below this
154 * results in the plaintext local peer path (no RDP encryption), which
155 * allows the byte stream fuzzer to reach all the way into the post
156 * activation parsing code.
157 */
158 if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, TRUE))
159 goto fail;
160 if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, TRUE))
161 goto fail;
162 if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, FALSE))
163 goto fail;
164 if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE))
165 goto fail;
166 if (!freerdp_settings_set_bool(settings, FreeRDP_ExtSecurity, FALSE))
167 goto fail;
168 if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel, ENCRYPTION_LEVEL_NONE))
169 goto fail;
170
171 /*
172 * Widen the negotiated surface: codecs, autodetect, multitransport and
173 * channel handling (no channel join shortcut) so more of the server
174 * parsing code is reachable once a (valid) client connects.
175 */
176 if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE))
177 goto fail;
178 if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, TRUE))
179 goto fail;
180 if (!freerdp_settings_set_bool(settings, FreeRDP_SupportMultitransport, TRUE))
181 goto fail;
182 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultitransportFlags,
183 INITIATE_REQUEST_PROTOCOL_UDPFECR))
184 goto fail;
185 if (!freerdp_settings_set_bool(settings, FreeRDP_SupportSkipChannelJoin, FALSE))
186 goto fail;
187
188 client->PostConnect = test_peer_post_connect;
189 client->Activate = test_peer_activate;
190 client->VirtualChannelRead = test_peer_virtual_channel_read;
191
192 /*
193 * The socketpair is a local connection. Mark it as such so the server
194 * uses the plaintext local peer path (no RDP encryption, see nego.c),
195 * which allows the byte stream fuzzer to reach all the way into the post
196 * activation parsing code.
197 */
198 client->local = TRUE;
199 if (!client->Initialize(client))
200 goto fail;
201
202 testPeerContext* context = (testPeerContext*)client->context;
203 WINPR_ASSERT(context);
204
205 /* make sure we never block on the client side of the socketpair */
206 if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0)
207 goto fail;
208
209 {
210 size_t written = 0;
211 while (written < Size)
212 {
213 const ssize_t rc = write(sv[1], Data + written, Size - written);
214 if (rc < 0)
215 {
216 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
217 break;
218 goto fail;
219 }
220 written += (size_t)rc;
221 }
222 }
223 if (shutdown(sv[1], SHUT_WR) != 0)
224 goto fail;
225
226 /*
227 * Drive the server state machine synchronously until it fails or
228 * reaches EOF (the client side of the socketpair is closed after
229 * shutdown). Drain server output so its socket buffer can not fill up.
230 */
231 for (size_t i = 0; i < TEST_SERVER_MAX_ITERATIONS; i++)
232 {
233 if (!client->CheckFileDescriptor(client))
234 break;
235
236 if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE)
237 break;
238
239 char buffer[256] = WINPR_C_ARRAY_INIT;
240 ssize_t rc = 0;
241 do
242 {
243 rc = read(sv[1], buffer, sizeof(buffer));
244 } while (rc > 0);
245 }
246
247fail:
248 freerdp_peer_context_free(client);
249 freerdp_peer_free(client);
250 close(sv[1]);
251 return TRUE;
252}
253
254int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size)
255{
256 const char* key = getTestCredentialsFileNameFor("crt");
257 const char* cert = getTestCredentialsFileNameFor("key");
258
259 if (key && cert)
260 {
261 if (WLog_SetLogLevel(WLog_GetRoot(), WLOG_OFF) &&
262 WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi()) &&
263 winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT))
264 {
265 test_server_one(key, cert, Data, Size);
266 }
267 }
268 free(key);
269 free(cert);
270
271 return 0;
272}
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_pointer_len(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id, const void *data, size_t len)
Set a pointer to value data.