Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/libfreerdp/codec/test/TestFuzzCodecs.c
Line
Count
Source (jump to first uncovered line)
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
48
static BOOL test_ClearDecompressExample(UINT32 nr, UINT32 width, UINT32 height,
49
                                        const BYTE* pSrcData, const UINT32 SrcSize)
50
17.1k
{
51
17.1k
  BOOL rc = FALSE;
52
17.1k
  int status = 0;
53
17.1k
  BYTE* pDstData = calloc(1ull * width * height, 4);
54
17.1k
  CLEAR_CONTEXT* clear = clear_context_new(FALSE);
55
56
17.1k
  WINPR_UNUSED(nr);
57
17.1k
  if (!clear || !pDstData)
58
0
    goto fail;
59
60
17.1k
  status = clear_decompress(clear, pSrcData, SrcSize, width, height, pDstData,
61
17.1k
                            PIXEL_FORMAT_XRGB32, 0, 0, 0, width, height, NULL);
62
  // printf("clear_decompress example %" PRIu32 " status: %d\n", nr, status);
63
  // fflush(stdout);
64
17.1k
  rc = (status == 0);
65
17.1k
fail:
66
17.1k
  clear_context_free(clear);
67
17.1k
  free(pDstData);
68
17.1k
  return rc;
69
17.1k
}
70
71
static int TestFreeRDPCodecClear(const uint8_t* Data, size_t Size)
72
5.71k
{
73
5.71k
  if (Size > UINT32_MAX)
74
0
    return -1;
75
5.71k
  test_ClearDecompressExample(2, 78, 17, Data, (UINT32)Size);
76
5.71k
  test_ClearDecompressExample(3, 64, 24, Data, (UINT32)Size);
77
5.71k
  test_ClearDecompressExample(4, 7, 15, Data, (UINT32)Size);
78
5.71k
  return 0;
79
5.71k
}
80
81
static int TestFreeRDPCodecXCrush(const uint8_t* Data, size_t Size)
82
5.71k
{
83
5.71k
  if (Size > UINT32_MAX)
84
0
    return -1;
85
86
5.71k
  const BYTE* OutputBuffer = NULL;
87
5.71k
  UINT32 DstSize = 0;
88
5.71k
  XCRUSH_CONTEXT* xcrush = xcrush_context_new(TRUE);
89
5.71k
  if (!xcrush)
90
0
    return 0;
91
5.71k
  xcrush_decompress(xcrush, Data, (UINT32)Size, &OutputBuffer, &DstSize, 0);
92
5.71k
  xcrush_context_free(xcrush);
93
5.71k
  return 0;
94
5.71k
}
95
96
static int test_ZGfxDecompressFoxSingle(const uint8_t* Data, size_t Size)
97
5.71k
{
98
5.71k
  if (Size > UINT32_MAX)
99
0
    return -1;
100
5.71k
  int rc = -1;
101
5.71k
  int status = 0;
102
5.71k
  UINT32 Flags = 0;
103
5.71k
  const BYTE* pSrcData = (const BYTE*)Data;
104
5.71k
  UINT32 SrcSize = (UINT32)Size;
105
5.71k
  UINT32 DstSize = 0;
106
5.71k
  BYTE* pDstData = NULL;
107
5.71k
  ZGFX_CONTEXT* zgfx = zgfx_context_new(TRUE);
108
109
5.71k
  if (!zgfx)
110
0
    return -1;
111
112
5.71k
  status = zgfx_decompress(zgfx, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
113
5.71k
  if (status < 0)
114
5.59k
    goto fail;
115
116
124
  rc = 0;
117
5.71k
fail:
118
5.71k
  free(pDstData);
119
5.71k
  zgfx_context_free(zgfx);
120
5.71k
  return rc;
121
124
}
122
123
static int TestFreeRDPCodecZGfx(const uint8_t* Data, size_t Size)
124
5.71k
{
125
5.71k
  test_ZGfxDecompressFoxSingle(Data, Size);
126
5.71k
  return 0;
127
5.71k
}
128
129
static BOOL test_NCrushDecompressBells(const uint8_t* Data, size_t Size)
130
5.71k
{
131
5.71k
  if (Size > UINT32_MAX)
132
0
    return FALSE;
133
134
5.71k
  BOOL rc = FALSE;
135
5.71k
  int status = 0;
136
5.71k
  UINT32 Flags = PACKET_COMPRESSED | 2;
137
5.71k
  const BYTE* pSrcData = (const BYTE*)Data;
138
5.71k
  UINT32 SrcSize = (UINT32)Size;
139
5.71k
  UINT32 DstSize = 0;
140
5.71k
  const BYTE* pDstData = NULL;
141
5.71k
  NCRUSH_CONTEXT* ncrush = ncrush_context_new(FALSE);
142
143
5.71k
  if (!ncrush)
144
0
    return rc;
145
146
5.71k
  status = ncrush_decompress(ncrush, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
147
5.71k
  if (status < 0)
148
5.67k
    goto fail;
149
150
42
  rc = TRUE;
151
5.71k
fail:
152
5.71k
  ncrush_context_free(ncrush);
153
5.71k
  return rc;
154
42
}
155
156
static int TestFreeRDPCodecNCrush(const uint8_t* Data, size_t Size)
157
5.71k
{
158
5.71k
  test_NCrushDecompressBells(Data, Size);
159
5.71k
  return 0;
160
5.71k
}
161
162
static const size_t IMG_WIDTH = 64;
163
static const size_t IMG_HEIGHT = 64;
164
static const size_t FORMAT_SIZE = 4;
165
static const UINT32 FORMAT = PIXEL_FORMAT_XRGB32;
166
167
static int TestFreeRDPCodecRemoteFX(const uint8_t* Data, size_t Size)
168
5.71k
{
169
5.71k
  int rc = -1;
170
5.71k
  REGION16 region = { 0 };
171
5.71k
  RFX_CONTEXT* context = rfx_context_new(FALSE);
172
5.71k
  BYTE* dest = calloc(IMG_WIDTH * IMG_HEIGHT, FORMAT_SIZE);
173
5.71k
  size_t stride = FORMAT_SIZE * IMG_WIDTH;
174
5.71k
  if (!context)
175
0
    goto fail;
176
5.71k
  if (Size > UINT32_MAX)
177
0
    goto fail;
178
5.71k
  if (stride > UINT32_MAX)
179
0
    goto fail;
180
5.71k
  if (!dest)
181
0
    goto fail;
182
183
5.71k
  region16_init(&region);
184
5.71k
  if (!rfx_process_message(context, Data, (UINT32)Size, 0, 0, dest, FORMAT, (UINT32)stride,
185
5.71k
                           IMG_HEIGHT, &region))
186
4.79k
    goto fail;
187
188
919
  region16_clear(&region);
189
919
  if (!rfx_process_message(context, Data, (UINT32)Size, 0, 0, dest, FORMAT, (UINT32)stride,
190
919
                           IMG_HEIGHT, &region))
191
0
    goto fail;
192
919
  region16_print(&region);
193
194
919
  rc = 0;
195
5.71k
fail:
196
5.71k
  region16_uninit(&region);
197
5.71k
  rfx_context_free(context);
198
5.71k
  free(dest);
199
5.71k
  return rc;
200
919
}
201
202
static int test_MppcDecompressBellsRdp5(const uint8_t* Data, size_t Size)
203
5.71k
{
204
5.71k
  int rc = -1;
205
5.71k
  int status = 0;
206
5.71k
  UINT32 Flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 1;
207
5.71k
  const BYTE* pSrcData = Data;
208
5.71k
  UINT32 SrcSize = (UINT32)Size;
209
5.71k
  UINT32 DstSize = 0;
210
5.71k
  const BYTE* pDstData = NULL;
211
5.71k
  MPPC_CONTEXT* mppc = mppc_context_new(1, FALSE);
212
213
5.71k
  if (!mppc)
214
0
    return -1;
215
216
5.71k
  status = mppc_decompress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
217
218
5.71k
  if (status < 0)
219
2.49k
    goto fail;
220
221
3.21k
  rc = 0;
222
223
5.71k
fail:
224
5.71k
  mppc_context_free(mppc);
225
5.71k
  return rc;
226
3.21k
}
227
228
static int test_MppcDecompressBellsRdp4(const uint8_t* Data, size_t Size)
229
5.71k
{
230
5.71k
  if (Size > UINT32_MAX)
231
0
    return -1;
232
5.71k
  int rc = -1;
233
5.71k
  int status = 0;
234
5.71k
  UINT32 Flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 0;
235
5.71k
  const BYTE* pSrcData = (const BYTE*)Data;
236
5.71k
  UINT32 SrcSize = (UINT32)Size;
237
5.71k
  UINT32 DstSize = 0;
238
5.71k
  const BYTE* pDstData = NULL;
239
5.71k
  MPPC_CONTEXT* mppc = mppc_context_new(0, FALSE);
240
241
5.71k
  if (!mppc)
242
0
    return -1;
243
244
5.71k
  status = mppc_decompress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
245
246
5.71k
  if (status < 0)
247
2.50k
    goto fail;
248
249
3.20k
  rc = 0;
250
5.71k
fail:
251
5.71k
  mppc_context_free(mppc);
252
5.71k
  return rc;
253
3.20k
}
254
255
static int test_MppcDecompressBufferRdp5(const uint8_t* Data, size_t Size)
256
5.71k
{
257
5.71k
  if (Size > UINT32_MAX)
258
0
    return -1;
259
5.71k
  int rc = -1;
260
5.71k
  int status = 0;
261
5.71k
  UINT32 Flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 1;
262
5.71k
  const BYTE* pSrcData = (const BYTE*)Data;
263
5.71k
  UINT32 SrcSize = (UINT32)Size;
264
5.71k
  UINT32 DstSize = 0;
265
5.71k
  const BYTE* pDstData = NULL;
266
5.71k
  MPPC_CONTEXT* mppc = mppc_context_new(1, FALSE);
267
268
5.71k
  if (!mppc)
269
0
    return -1;
270
271
5.71k
  status = mppc_decompress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
272
273
5.71k
  if (status < 0)
274
2.49k
    goto fail;
275
276
3.21k
  rc = 0;
277
5.71k
fail:
278
5.71k
  mppc_context_free(mppc);
279
5.71k
  return rc;
280
3.21k
}
281
282
static int TestFreeRDPCodecMppc(const uint8_t* Data, size_t Size)
283
5.71k
{
284
5.71k
  test_MppcDecompressBellsRdp5(Data, Size);
285
5.71k
  test_MppcDecompressBellsRdp4(Data, Size);
286
5.71k
  test_MppcDecompressBufferRdp5(Data, Size);
287
5.71k
  return 0;
288
5.71k
}
289
290
static BOOL progressive_decode(const uint8_t* Data, size_t Size)
291
5.71k
{
292
5.71k
  BOOL res = FALSE;
293
5.71k
  int rc = 0;
294
5.71k
  BYTE* resultData = NULL;
295
5.71k
  UINT32 ColorFormat = PIXEL_FORMAT_BGRX32;
296
5.71k
  REGION16 invalidRegion = { 0 };
297
5.71k
  UINT32 scanline = 4240;
298
5.71k
  UINT32 width = 1060;
299
5.71k
  UINT32 height = 827;
300
5.71k
  if (Size > UINT32_MAX)
301
0
    return FALSE;
302
303
5.71k
  PROGRESSIVE_CONTEXT* progressiveDec = progressive_context_new(FALSE);
304
305
5.71k
  region16_init(&invalidRegion);
306
5.71k
  if (!progressiveDec)
307
0
    goto fail;
308
309
5.71k
  resultData = calloc(scanline, height);
310
5.71k
  if (!resultData)
311
0
    goto fail;
312
313
5.71k
  rc = progressive_create_surface_context(progressiveDec, 0, width, height);
314
5.71k
  if (rc <= 0)
315
0
    goto fail;
316
317
5.71k
  rc = progressive_decompress(progressiveDec, Data, (UINT32)Size, resultData, ColorFormat,
318
5.71k
                              scanline, 0, 0, &invalidRegion, 0, 0);
319
5.71k
  if (rc < 0)
320
0
    goto fail;
321
322
5.71k
  res = TRUE;
323
5.71k
fail:
324
5.71k
  region16_uninit(&invalidRegion);
325
5.71k
  progressive_context_free(progressiveDec);
326
5.71k
  free(resultData);
327
5.71k
  return res;
328
5.71k
}
329
330
static int TestFreeRDPCodecProgressive(const uint8_t* Data, size_t Size)
331
5.71k
{
332
5.71k
  progressive_decode(Data, Size);
333
5.71k
  return 0;
334
5.71k
}
335
336
static 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
17.1k
{
340
17.1k
  BOOL rc2 = FALSE;
341
17.1k
  BOOL rc = 0;
342
17.1k
  const UINT32 w = 64;
343
17.1k
  const UINT32 h = 64;
344
17.1k
  const UINT32 x = 0;
345
17.1k
  const UINT32 y = 0;
346
17.1k
  const UINT32 format = PIXEL_FORMAT_RGBX32;
347
17.1k
  const size_t step = (w + 13ull) * 4ull;
348
17.1k
  const size_t SrcSize = step * h;
349
17.1k
  BYTE* pSrcData = calloc(1, SrcSize);
350
17.1k
  BYTE* pDstData = calloc(1, SrcSize);
351
17.1k
  BYTE* tmp = calloc(1, SrcSize);
352
353
17.1k
  WINPR_UNUSED(encoder);
354
17.1k
  if (!pSrcData || !pDstData || !tmp)
355
0
    goto fail;
356
357
17.1k
  if (Size > UINT32_MAX)
358
0
    goto fail;
359
360
17.1k
  winpr_RAND(pSrcData, SrcSize);
361
362
17.1k
  if (!bitmap_interleaved_context_reset(decoder))
363
0
    goto fail;
364
365
17.1k
  rc = interleaved_decompress(decoder, Data, (UINT32)Size, w, h, bpp, pDstData, format, step, x,
366
17.1k
                              y, w, h, NULL);
367
368
17.1k
  if (!rc)
369
12.9k
    goto fail;
370
371
4.18k
  rc2 = TRUE;
372
17.1k
fail:
373
17.1k
  free(pSrcData);
374
17.1k
  free(pDstData);
375
17.1k
  free(tmp);
376
17.1k
  return rc2;
377
4.18k
}
378
379
static int TestFreeRDPCodecInterleaved(const uint8_t* Data, size_t Size)
380
5.71k
{
381
5.71k
  int rc = -1;
382
5.71k
  BITMAP_INTERLEAVED_CONTEXT* decoder = bitmap_interleaved_context_new(FALSE);
383
384
5.71k
  if (!decoder)
385
0
    goto fail;
386
387
5.71k
  i_run_encode_decode(24, NULL, decoder, Data, Size);
388
5.71k
  i_run_encode_decode(16, NULL, decoder, Data, Size);
389
5.71k
  i_run_encode_decode(15, NULL, decoder, Data, Size);
390
5.71k
  rc = 0;
391
5.71k
fail:
392
5.71k
  bitmap_interleaved_context_free(decoder);
393
5.71k
  return rc;
394
5.71k
}
395
396
static 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
11.4k
{
400
11.4k
  BOOL rc = FALSE;
401
11.4k
  WINPR_UNUSED(srcBitmap);
402
11.4k
  WINPR_UNUSED(srcFormat);
403
11.4k
  if (Size > UINT32_MAX)
404
0
    return FALSE;
405
11.4k
  UINT32 dstSize = (UINT32)Size;
406
11.4k
  const BYTE* compressedBitmap = Data;
407
11.4k
  BYTE* decompressedBitmap =
408
11.4k
      (BYTE*)calloc(height, 1ull * width * FreeRDPGetBytesPerPixel(dstFormat));
409
11.4k
  rc = TRUE;
410
411
11.4k
  if (!decompressedBitmap)
412
0
    goto fail;
413
414
11.4k
  if (!planar_decompress(planar, compressedBitmap, dstSize, width, height, decompressedBitmap,
415
11.4k
                         dstFormat, 0, 0, 0, width, height, FALSE))
416
10.1k
  {
417
10.1k
    goto fail;
418
10.1k
  }
419
420
1.30k
  rc = TRUE;
421
11.4k
fail:
422
11.4k
  free(decompressedBitmap);
423
11.4k
  return rc;
424
1.30k
}
425
426
static BOOL TestPlanar(const UINT32 format, const uint8_t* Data, size_t Size)
427
5.71k
{
428
5.71k
  BOOL rc = FALSE;
429
5.71k
  const DWORD planarFlags = PLANAR_FORMAT_HEADER_NA | PLANAR_FORMAT_HEADER_RLE;
430
5.71k
  BITMAP_PLANAR_CONTEXT* planar = freerdp_bitmap_planar_context_new(planarFlags, 64, 64);
431
432
5.71k
  if (!planar)
433
0
    goto fail;
434
435
5.71k
  RunTestPlanar(planar, NULL, PIXEL_FORMAT_RGBX32, format, 64, 64, Data, Size);
436
437
5.71k
  RunTestPlanar(planar, NULL, PIXEL_FORMAT_RGB16, format, 32, 32, Data, Size);
438
439
5.71k
  rc = TRUE;
440
5.71k
fail:
441
5.71k
  freerdp_bitmap_planar_context_free(planar);
442
5.71k
  return rc;
443
5.71k
}
444
445
static int TestFreeRDPCodecPlanar(const uint8_t* Data, size_t Size)
446
5.71k
{
447
5.71k
  TestPlanar(0, Data, Size);
448
5.71k
  return 0;
449
5.71k
}
450
451
int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size)
452
5.71k
{
453
5.71k
  if (Size < 4)
454
2
    return 0;
455
456
5.71k
  TestFreeRDPCodecClear(Data, Size);
457
5.71k
  TestFreeRDPCodecXCrush(Data, Size);
458
5.71k
  TestFreeRDPCodecZGfx(Data, Size);
459
5.71k
  TestFreeRDPCodecNCrush(Data, Size);
460
5.71k
  TestFreeRDPCodecRemoteFX(Data, Size);
461
5.71k
  TestFreeRDPCodecMppc(Data, Size);
462
5.71k
  TestFreeRDPCodecProgressive(Data, Size);
463
5.71k
  TestFreeRDPCodecInterleaved(Data, Size);
464
5.71k
  TestFreeRDPCodecPlanar(Data, Size);
465
466
5.71k
  return 0;
467
5.71k
}