FreeRDP
Loading...
Searching...
No Matches
TestFuzzCodecs.c
1/* https://github.com/ergnoorr/fuzzrdp
2 *
3 * MIT License
4 *
5 * Copyright (c) 2024 ergnoorr
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25#include <freerdp/assistance.h>
26
27#include <winpr/crt.h>
28#include <winpr/print.h>
29#include <winpr/platform.h>
30#include <freerdp/codec/interleaved.h>
31#include <freerdp/codec/planar.h>
32#include <freerdp/codec/bulk.h>
33#include <freerdp/codec/clear.h>
34#include <freerdp/codec/zgfx.h>
35#include <freerdp/log.h>
36#include <winpr/bitstream.h>
37#include <freerdp/codec/rfx.h>
38#include <freerdp/codec/progressive.h>
39
40#include <freerdp/freerdp.h>
41#include <freerdp/gdi/gdi.h>
42
43#include "../progressive.h"
44#include "../mppc.h"
45#include "../xcrush.h"
46#include "../ncrush.h"
47
48static BOOL test_ClearDecompressExample(UINT32 nr, UINT32 width, UINT32 height,
49 const BYTE* pSrcData, const UINT32 SrcSize)
50{
51 BOOL rc = FALSE;
52 int status = 0;
53 BYTE* pDstData = calloc(1ull * width * height, 4);
54 CLEAR_CONTEXT* clear = clear_context_new(FALSE);
55
56 WINPR_UNUSED(nr);
57 if (!clear || !pDstData)
58 goto fail;
59
60 status = clear_decompress(clear, pSrcData, SrcSize, width, height, pDstData,
61 PIXEL_FORMAT_XRGB32, 0, 0, 0, width, height, NULL);
62 // printf("clear_decompress example %" PRIu32 " status: %d\n", nr, status);
63 // fflush(stdout);
64 rc = (status == 0);
65fail:
66 clear_context_free(clear);
67 free(pDstData);
68 return rc;
69}
70
71static int TestFreeRDPCodecClear(const uint8_t* Data, size_t Size)
72{
73 if (Size > UINT32_MAX)
74 return -1;
75 test_ClearDecompressExample(2, 78, 17, Data, (UINT32)Size);
76 test_ClearDecompressExample(3, 64, 24, Data, (UINT32)Size);
77 test_ClearDecompressExample(4, 7, 15, Data, (UINT32)Size);
78 return 0;
79}
80
81static int TestFreeRDPCodecXCrush(const uint8_t* Data, size_t Size)
82{
83 if (Size > UINT32_MAX)
84 return -1;
85
86 const BYTE* OutputBuffer = NULL;
87 UINT32 DstSize = 0;
88 XCRUSH_CONTEXT* xcrush = xcrush_context_new(TRUE);
89 if (!xcrush)
90 return 0;
91 xcrush_decompress(xcrush, Data, (UINT32)Size, &OutputBuffer, &DstSize, 0);
92 xcrush_context_free(xcrush);
93 return 0;
94}
95
96static int test_ZGfxDecompressFoxSingle(const uint8_t* Data, size_t Size)
97{
98 if (Size > UINT32_MAX)
99 return -1;
100 int rc = -1;
101 int status = 0;
102 UINT32 Flags = 0;
103 const BYTE* pSrcData = (const BYTE*)Data;
104 UINT32 SrcSize = (UINT32)Size;
105 UINT32 DstSize = 0;
106 BYTE* pDstData = NULL;
107 ZGFX_CONTEXT* zgfx = zgfx_context_new(TRUE);
108
109 if (!zgfx)
110 return -1;
111
112 status = zgfx_decompress(zgfx, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
113 if (status < 0)
114 goto fail;
115
116 rc = 0;
117fail:
118 free(pDstData);
119 zgfx_context_free(zgfx);
120 return rc;
121}
122
123static int TestFreeRDPCodecZGfx(const uint8_t* Data, size_t Size)
124{
125 test_ZGfxDecompressFoxSingle(Data, Size);
126 return 0;
127}
128
129static BOOL test_NCrushDecompressBells(const uint8_t* Data, size_t Size)
130{
131 if (Size > UINT32_MAX)
132 return FALSE;
133
134 BOOL rc = FALSE;
135 int status = 0;
136 UINT32 Flags = PACKET_COMPRESSED | 2;
137 const BYTE* pSrcData = (const BYTE*)Data;
138 UINT32 SrcSize = (UINT32)Size;
139 UINT32 DstSize = 0;
140 const BYTE* pDstData = NULL;
141 NCRUSH_CONTEXT* ncrush = ncrush_context_new(FALSE);
142
143 if (!ncrush)
144 return rc;
145
146 status = ncrush_decompress(ncrush, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
147 if (status < 0)
148 goto fail;
149
150 rc = TRUE;
151fail:
152 ncrush_context_free(ncrush);
153 return rc;
154}
155
156static int TestFreeRDPCodecNCrush(const uint8_t* Data, size_t Size)
157{
158 test_NCrushDecompressBells(Data, Size);
159 return 0;
160}
161
162static const size_t IMG_WIDTH = 64;
163static const size_t IMG_HEIGHT = 64;
164static const size_t FORMAT_SIZE = 4;
165static const UINT32 FORMAT = PIXEL_FORMAT_XRGB32;
166
167static int TestFreeRDPCodecRemoteFX(const uint8_t* Data, size_t Size)
168{
169 int rc = -1;
170 REGION16 region = { 0 };
171 RFX_CONTEXT* context = rfx_context_new(FALSE);
172 BYTE* dest = calloc(IMG_WIDTH * IMG_HEIGHT, FORMAT_SIZE);
173 size_t stride = FORMAT_SIZE * IMG_WIDTH;
174 if (!context)
175 goto fail;
176 if (Size > UINT32_MAX)
177 goto fail;
178 if (stride > UINT32_MAX)
179 goto fail;
180 if (!dest)
181 goto fail;
182
183 region16_init(&region);
184 if (!rfx_process_message(context, Data, (UINT32)Size, 0, 0, dest, FORMAT, (UINT32)stride,
185 IMG_HEIGHT, &region))
186 goto fail;
187
188 region16_clear(&region);
189 if (!rfx_process_message(context, Data, (UINT32)Size, 0, 0, dest, FORMAT, (UINT32)stride,
190 IMG_HEIGHT, &region))
191 goto fail;
192 region16_print(&region);
193
194 rc = 0;
195fail:
196 region16_uninit(&region);
197 rfx_context_free(context);
198 free(dest);
199 return rc;
200}
201
202static int test_MppcDecompressBellsRdp5(const uint8_t* Data, size_t Size)
203{
204 int rc = -1;
205 int status = 0;
206 UINT32 Flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 1;
207 const BYTE* pSrcData = Data;
208 UINT32 SrcSize = (UINT32)Size;
209 UINT32 DstSize = 0;
210 const BYTE* pDstData = NULL;
211 MPPC_CONTEXT* mppc = mppc_context_new(1, FALSE);
212
213 if (!mppc)
214 return -1;
215
216 status = mppc_decompress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
217
218 if (status < 0)
219 goto fail;
220
221 rc = 0;
222
223fail:
224 mppc_context_free(mppc);
225 return rc;
226}
227
228static int test_MppcDecompressBellsRdp4(const uint8_t* Data, size_t Size)
229{
230 if (Size > UINT32_MAX)
231 return -1;
232 int rc = -1;
233 int status = 0;
234 UINT32 Flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 0;
235 const BYTE* pSrcData = (const BYTE*)Data;
236 UINT32 SrcSize = (UINT32)Size;
237 UINT32 DstSize = 0;
238 const BYTE* pDstData = NULL;
239 MPPC_CONTEXT* mppc = mppc_context_new(0, FALSE);
240
241 if (!mppc)
242 return -1;
243
244 status = mppc_decompress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
245
246 if (status < 0)
247 goto fail;
248
249 rc = 0;
250fail:
251 mppc_context_free(mppc);
252 return rc;
253}
254
255static int test_MppcDecompressBufferRdp5(const uint8_t* Data, size_t Size)
256{
257 if (Size > UINT32_MAX)
258 return -1;
259 int rc = -1;
260 int status = 0;
261 UINT32 Flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 1;
262 const BYTE* pSrcData = (const BYTE*)Data;
263 UINT32 SrcSize = (UINT32)Size;
264 UINT32 DstSize = 0;
265 const BYTE* pDstData = NULL;
266 MPPC_CONTEXT* mppc = mppc_context_new(1, FALSE);
267
268 if (!mppc)
269 return -1;
270
271 status = mppc_decompress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
272
273 if (status < 0)
274 goto fail;
275
276 rc = 0;
277fail:
278 mppc_context_free(mppc);
279 return rc;
280}
281
282static int TestFreeRDPCodecMppc(const uint8_t* Data, size_t Size)
283{
284 test_MppcDecompressBellsRdp5(Data, Size);
285 test_MppcDecompressBellsRdp4(Data, Size);
286 test_MppcDecompressBufferRdp5(Data, Size);
287 return 0;
288}
289
290static BOOL progressive_decode(const uint8_t* Data, size_t Size)
291{
292 BOOL res = FALSE;
293 int rc = 0;
294 BYTE* resultData = NULL;
295 UINT32 ColorFormat = PIXEL_FORMAT_BGRX32;
296 REGION16 invalidRegion = { 0 };
297 UINT32 scanline = 4240;
298 UINT32 width = 1060;
299 UINT32 height = 827;
300 if (Size > UINT32_MAX)
301 return FALSE;
302
303 PROGRESSIVE_CONTEXT* progressiveDec = progressive_context_new(FALSE);
304
305 region16_init(&invalidRegion);
306 if (!progressiveDec)
307 goto fail;
308
309 resultData = calloc(scanline, height);
310 if (!resultData)
311 goto fail;
312
313 rc = progressive_create_surface_context(progressiveDec, 0, width, height);
314 if (rc <= 0)
315 goto fail;
316
317 rc = progressive_decompress(progressiveDec, Data, (UINT32)Size, resultData, ColorFormat,
318 scanline, 0, 0, &invalidRegion, 0, 0);
319 if (rc < 0)
320 goto fail;
321
322 res = TRUE;
323fail:
324 region16_uninit(&invalidRegion);
325 progressive_context_free(progressiveDec);
326 free(resultData);
327 return res;
328}
329
330static int TestFreeRDPCodecProgressive(const uint8_t* Data, size_t Size)
331{
332 progressive_decode(Data, Size);
333 return 0;
334}
335
336static BOOL i_run_encode_decode(UINT16 bpp, BITMAP_INTERLEAVED_CONTEXT* encoder,
337 BITMAP_INTERLEAVED_CONTEXT* decoder, const uint8_t* Data,
338 size_t Size)
339{
340 BOOL rc2 = FALSE;
341 BOOL rc = 0;
342 const UINT32 w = 64;
343 const UINT32 h = 64;
344 const UINT32 x = 0;
345 const UINT32 y = 0;
346 const UINT32 format = PIXEL_FORMAT_RGBX32;
347 const size_t step = (w + 13ull) * 4ull;
348 const size_t SrcSize = step * h;
349 BYTE* pSrcData = calloc(1, SrcSize);
350 BYTE* pDstData = calloc(1, SrcSize);
351 BYTE* tmp = calloc(1, SrcSize);
352
353 WINPR_UNUSED(encoder);
354 if (!pSrcData || !pDstData || !tmp)
355 goto fail;
356
357 if (Size > UINT32_MAX)
358 goto fail;
359
360 winpr_RAND(pSrcData, SrcSize);
361
362 if (!bitmap_interleaved_context_reset(decoder))
363 goto fail;
364
365 rc = interleaved_decompress(decoder, Data, (UINT32)Size, w, h, bpp, pDstData, format, step, x,
366 y, w, h, NULL);
367
368 if (!rc)
369 goto fail;
370
371 rc2 = TRUE;
372fail:
373 free(pSrcData);
374 free(pDstData);
375 free(tmp);
376 return rc2;
377}
378
379static int TestFreeRDPCodecInterleaved(const uint8_t* Data, size_t Size)
380{
381 int rc = -1;
382 BITMAP_INTERLEAVED_CONTEXT* decoder = bitmap_interleaved_context_new(FALSE);
383
384 if (!decoder)
385 goto fail;
386
387 i_run_encode_decode(24, NULL, decoder, Data, Size);
388 i_run_encode_decode(16, NULL, decoder, Data, Size);
389 i_run_encode_decode(15, NULL, decoder, Data, Size);
390 rc = 0;
391fail:
392 bitmap_interleaved_context_free(decoder);
393 return rc;
394}
395
396static BOOL RunTestPlanar(BITMAP_PLANAR_CONTEXT* planar, const BYTE* srcBitmap,
397 const UINT32 srcFormat, const UINT32 dstFormat, const UINT32 width,
398 const UINT32 height, const uint8_t* Data, size_t Size)
399{
400 BOOL rc = FALSE;
401 WINPR_UNUSED(srcBitmap);
402 WINPR_UNUSED(srcFormat);
403 if (Size > UINT32_MAX)
404 return FALSE;
405 UINT32 dstSize = (UINT32)Size;
406 const BYTE* compressedBitmap = Data;
407 BYTE* decompressedBitmap =
408 (BYTE*)calloc(height, 1ull * width * FreeRDPGetBytesPerPixel(dstFormat));
409 rc = TRUE;
410
411 if (!decompressedBitmap)
412 goto fail;
413
414 if (!planar_decompress(planar, compressedBitmap, dstSize, width, height, decompressedBitmap,
415 dstFormat, 0, 0, 0, width, height, FALSE))
416 {
417 goto fail;
418 }
419
420 rc = TRUE;
421fail:
422 free(decompressedBitmap);
423 return rc;
424}
425
426static BOOL TestPlanar(const UINT32 format, const uint8_t* Data, size_t Size)
427{
428 BOOL rc = FALSE;
429 const DWORD planarFlags = PLANAR_FORMAT_HEADER_NA | PLANAR_FORMAT_HEADER_RLE;
430 BITMAP_PLANAR_CONTEXT* planar = freerdp_bitmap_planar_context_new(planarFlags, 64, 64);
431
432 if (!planar)
433 goto fail;
434
435 RunTestPlanar(planar, NULL, PIXEL_FORMAT_RGBX32, format, 64, 64, Data, Size);
436
437 RunTestPlanar(planar, NULL, PIXEL_FORMAT_RGB16, format, 32, 32, Data, Size);
438
439 rc = TRUE;
440fail:
441 freerdp_bitmap_planar_context_free(planar);
442 return rc;
443}
444
445static int TestFreeRDPCodecPlanar(const uint8_t* Data, size_t Size)
446{
447 TestPlanar(0, Data, Size);
448 return 0;
449}
450
451int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size)
452{
453 if (Size < 4)
454 return 0;
455
456 TestFreeRDPCodecClear(Data, Size);
457 TestFreeRDPCodecXCrush(Data, Size);
458 TestFreeRDPCodecZGfx(Data, Size);
459 TestFreeRDPCodecNCrush(Data, Size);
460 TestFreeRDPCodecRemoteFX(Data, Size);
461 TestFreeRDPCodecMppc(Data, Size);
462 TestFreeRDPCodecProgressive(Data, Size);
463 TestFreeRDPCodecInterleaved(Data, Size);
464 TestFreeRDPCodecPlanar(Data, Size);
465
466 return 0;
467}