• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // -----------------------------------------------------------------------------
2 // Fuzz Target for libyuv's mjpeg decoder.
3 //
4 // This fuzz target focuses on the decoding from JPEG to YUV format.
5 // -----------------------------------------------------------------------------
6 #include "libyuv/basic_types.h"
7 #include "libyuv/mjpeg_decoder.h"
8 
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <malloc.h>
14 
15 
16 // -----------------------------------------------------------------------------
17 // Checks whether 3 values are equal.
18 //
IsEqual(int a,int b,int c)19 inline bool IsEqual(int a, int b, int  c) {
20   return (a == b && a == c);
21 }
22 
23 // -----------------------------------------------------------------------------
24 // libFuzzer's callback that is invoked upon startup.
25 //
LLVMFuzzerInitialize(int * unused_argc,char *** unused_argv)26 extern "C" int LLVMFuzzerInitialize(int *unused_argc, char ***unused_argv) {
27   (void) unused_argc;  // Avoid "-Wunused-parameter" warnings.
28   (void) unused_argv;
29   // Printing this message is benefial as we can infer which fuzzer runs
30   // just by looking at the logs which are stored in the cloud.
31   printf("[*] Fuzz Target for libyuv mjpeg decoder started.\n");
32 
33   return 0;
34 }
35 
36 // -----------------------------------------------------------------------------
37 // Decodes a JPEG image into a YUV format.
38 //
Decode(libyuv::MJpegDecoder & decoder)39 extern "C" bool Decode(libyuv::MJpegDecoder &decoder) {
40   // YUV colors are represented with one "luminance" component called Y
41   // and two "chrominance" components, called U and V.
42   // Planar formats use separate matrices for each of the 3 color components.
43   //
44   // If we don't have 3 components abort.
45   //
46   // NOTE: It may be possible to have 4 planes for CMYK and alpha, but it's
47   // very rare and not supported.
48   int num_planes = decoder.GetNumComponents();
49 
50   if (num_planes != 3) {
51     return false;
52   }
53 
54   /* NOTE: Without a jpeg corpus, we can't reach this point */
55 
56   int width = decoder.GetWidth();
57   int height = decoder.GetHeight();
58   int y_width = decoder.GetComponentWidth(0);
59   int y_height = decoder.GetComponentHeight(0);
60   int u_width = decoder.GetComponentWidth(1);
61   int u_height = decoder.GetComponentHeight(1);
62   int v_width = decoder.GetComponentWidth(2);
63   int v_height = decoder.GetComponentHeight(2);
64   uint8_t *y;
65   uint8_t *u;
66   uint8_t *v;
67 
68   // Make sure that width and heigh stay at decent levels (< 16K * 16K).
69   // (Y is the largest buffer).
70   if (width > (1 << 14) || height > (1 << 14)) {
71     // Ok, if this happens it's a DoS, but let's ignore it for now.
72     return false;
73   }
74 
75   // Allocate stides according to the sampling type.
76   if (IsEqual(y_width, u_width, v_width) &&
77       IsEqual(y_height, u_height, v_height)) {
78     // Sampling type: YUV444.
79     y = new uint8_t[width * height];
80     u = new uint8_t[width * height];
81     v = new uint8_t[width * height];
82 
83   } else if (IsEqual((y_width + 1) / 2, u_width, v_width) &&
84       IsEqual(y_height, u_height, v_height)) {
85     // Sampling type: YUV422.
86     y = new uint8_t[width * height];
87     u = new uint8_t[((width + 1) / 2) * height];
88     v = new uint8_t[((width + 1) / 2) * height];
89 
90   } else if (IsEqual((y_width + 1) / 2, u_width, v_width) &&
91       IsEqual((y_height + 1) / 2, u_height, v_height)) {
92     // Sampling type: YUV420.
93     y = new uint8_t[width * height];
94     u = new uint8_t[((width + 1) / 2) * ((height + 1) / 2)];
95     v = new uint8_t[((width + 1) / 2) * ((height + 1) / 2)];
96 
97   } else {
98     // Invalid sampling type.
99     return false;
100   }
101 
102   uint8_t* planes[] = {y, u, v};
103 
104   // Do the actual decoding. (Ignore return values).
105   decoder.DecodeToBuffers(planes, width, height);
106 
107   delete[] y;
108   delete[] u;
109   delete[] v;
110 
111   return true;  // Success!
112 }
113 
114 // -----------------------------------------------------------------------------
115 // libFuzzer's callback that performs the actual fuzzing.
116 //
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)117 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
118   // Make sure that we have a minimum length (32 or something small).
119   if (size < 32) {
120       return 0;
121   }
122 
123   // Create the decoder object.
124   libyuv::MJpegDecoder decoder;
125 
126   // Load frame, read its headers and determine uncompress image format.
127   if (decoder.LoadFrame(data, size) == LIBYUV_FALSE) {
128     // Header parsing error. Discrad frame.
129     return 0;
130   }
131 
132   // Do the actual decoding.
133   Decode(decoder);
134 
135   // Unload the frame.
136   decoder.UnloadFrame();
137 
138   return 0;
139 }
140