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 WINPR_ASSERT(buffer || (length == 0));
75 return 0;
76}
77
78struct test_peer_context
79{
80 rdpContext _p;
81
82 HANDLE vcm;
83};
84typedef struct test_peer_context testPeerContext;
85
86static void test_peer_context_free(freerdp_peer* client, rdpContext* ctx)
87{
88 testPeerContext* context = (testPeerContext*)ctx;
89
90 WINPR_UNUSED(client);
91
92 if (context && context->vcm)
93 {
94 WTSCloseServer(context->vcm);
95 context->vcm = nullptr;
96 }
97}
98
99static BOOL test_peer_context_new(freerdp_peer* client, rdpContext* ctx)
100{
101 testPeerContext* context = (testPeerContext*)ctx;
102
103 WINPR_ASSERT(client);
104 WINPR_ASSERT(context);
105
106 context->vcm = WTSOpenServerA((LPSTR)client->context);
107 if (!context->vcm || context->vcm == INVALID_HANDLE_VALUE)
108 goto fail;
109
110 return TRUE;
111fail:
112 test_peer_context_free(client, ctx);
113 return FALSE;
114}
115
116static BOOL test_server_one(const char* fkey, const char* fcert, const uint8_t* Data, size_t Size)
117{
118 int sv[2] = WINPR_C_ARRAY_INIT;
119
120 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) != 0)
121 return FALSE;
122
123 freerdp_peer* client = freerdp_peer_new(sv[0]);
124 if (!client)
125 {
126 close(sv[0]);
127 close(sv[1]);
128 return FALSE;
129 }
130
131 client->ContextSize = sizeof(testPeerContext);
132 client->ContextNew = test_peer_context_new;
133 client->ContextFree = test_peer_context_free;
134 if (!freerdp_peer_context_new(client))
135 goto fail;
136
137 WINPR_ASSERT(client->context);
138 rdpSettings* settings = client->context->settings;
139 WINPR_ASSERT(settings);
140
141 rdpCertificate* cert = freerdp_certificate_new_from_file(fcert);
142 if (!cert)
143 goto fail;
144 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerCertificate, cert, 1))
145 goto fail;
146
147 rdpPrivateKey* key = freerdp_key_new_from_file(fkey);
148 if (!key)
149 goto fail;
150 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerRsaKey, key, 1))
151 goto fail;
152
153 /*
154 * Plain RDP security. Together with the local peer flag below this
155 * results in the plaintext local peer path (no RDP encryption), which
156 * allows the byte stream fuzzer to reach all the way into the post
157 * activation parsing code.
158 */
159 if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, TRUE))
160 goto fail;
161 if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, TRUE))
162 goto fail;
163 if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, FALSE))
164 goto fail;
165 if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE))
166 goto fail;
167 if (!freerdp_settings_set_bool(settings, FreeRDP_ExtSecurity, FALSE))
168 goto fail;
169 if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel, ENCRYPTION_LEVEL_NONE))
170 goto fail;
171
172 /*
173 * Widen the negotiated surface: codecs, autodetect, multitransport and
174 * channel handling (no channel join shortcut) so more of the server
175 * parsing code is reachable once a (valid) client connects.
176 */
177 if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE))
178 goto fail;
179 if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, TRUE))
180 goto fail;
181 if (!freerdp_settings_set_bool(settings, FreeRDP_SupportMultitransport, TRUE))
182 goto fail;
183 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultitransportFlags,
184 INITIATE_REQUEST_PROTOCOL_UDPFECR))
185 goto fail;
186 if (!freerdp_settings_set_bool(settings, FreeRDP_SupportSkipChannelJoin, FALSE))
187 goto fail;
188
189 client->PostConnect = test_peer_post_connect;
190 client->Activate = test_peer_activate;
191 client->VirtualChannelRead = test_peer_virtual_channel_read;
192
193 /*
194 * The socketpair is a local connection. Mark it as such so the server
195 * uses the plaintext local peer path (no RDP encryption, see nego.c),
196 * which allows the byte stream fuzzer to reach all the way into the post
197 * activation parsing code.
198 */
199 client->local = TRUE;
200 if (!client->Initialize(client))
201 goto fail;
202
203 testPeerContext* context = (testPeerContext*)client->context;
204 WINPR_ASSERT(context);
205
206 /* make sure we never block on the client side of the socketpair */
207 if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0)
208 goto fail;
209
210 {
211 size_t written = 0;
212 while (written < Size)
213 {
214 const ssize_t rc = write(sv[1], Data + written, Size - written);
215 if (rc < 0)
216 {
217 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
218 break;
219 goto fail;
220 }
221 written += (size_t)rc;
222 }
223 }
224 if (shutdown(sv[1], SHUT_WR) != 0)
225 goto fail;
226
227 /*
228 * Drive the server state machine synchronously until it fails or
229 * reaches EOF (the client side of the socketpair is closed after
230 * shutdown). Drain server output so its socket buffer can not fill up.
231 */
232 for (size_t i = 0; i < TEST_SERVER_MAX_ITERATIONS; i++)
233 {
234 if (!client->CheckFileDescriptor(client))
235 break;
236
237 if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE)
238 break;
239
240 char buffer[256] = WINPR_C_ARRAY_INIT;
241 ssize_t rc = 0;
242 do
243 {
244 rc = read(sv[1], buffer, sizeof(buffer));
245 } while (rc > 0);
246 }
247
248fail:
249 freerdp_peer_context_free(client);
250 freerdp_peer_free(client);
251 close(sv[1]);
252 return TRUE;
253}
254
255int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size)
256{
257 const char* key = getTestCredentialsFileNameFor("crt");
258 const char* cert = getTestCredentialsFileNameFor("key");
259
260 if (key && cert)
261 {
262 if (WLog_SetLogLevel(WLog_GetRoot(), WLOG_OFF) &&
263 WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi()) &&
264 winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT))
265 {
266 test_server_one(key, cert, Data, Size);
267 }
268 }
269 free(key);
270 free(cert);
271
272 return 0;
273}
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.