aboutsummaryrefslogtreecommitdiff
path: root/fuzz/mjpeg_dec_fuzz.cc
blob: 3be8410abcb3ca2df1043dc522ea60e5a053f0bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// -----------------------------------------------------------------------------
// Fuzz Target for libyuv's mjpeg decoder.
//
// This fuzz target focuses on the decoding from JPEG to YUV format.
// -----------------------------------------------------------------------------
#include "libyuv/basic_types.h"
#include "libyuv/mjpeg_decoder.h"

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>


// -----------------------------------------------------------------------------
// Checks whether 3 values are equal.
//
inline bool IsEqual(int a, int b, int  c) {
  return (a == b && a == c);
}

// -----------------------------------------------------------------------------
// libFuzzer's callback that is invoked upon startup.
//
extern "C" int LLVMFuzzerInitialize(int *unused_argc, char ***unused_argv) {
  (void) unused_argc;  // Avoid "-Wunused-parameter" warnings.
  (void) unused_argv;
  // Printing this message is benefial as we can infer which fuzzer runs
  // just by looking at the logs which are stored in the cloud.
  printf("[*] Fuzz Target for libyuv mjpeg decoder started.\n");

  return 0;
}

// -----------------------------------------------------------------------------
// Decodes a JPEG image into a YUV format.
//
extern "C" bool Decode(libyuv::MJpegDecoder &decoder) {
  // YUV colors are represented with one "luminance" component called Y
  // and two "chrominance" components, called U and V.
  // Planar formats use separate matrices for each of the 3 color components.
  //
  // If we don't have 3 components abort.
  //
  // NOTE: It may be possible to have 4 planes for CMYK and alpha, but it's
  // very rare and not supported.
  int num_planes = decoder.GetNumComponents();

  if (num_planes != 3) {
    return false;
  }

  /* NOTE: Without a jpeg corpus, we can't reach this point */

  int width = decoder.GetWidth();
  int height = decoder.GetHeight();
  int y_width = decoder.GetComponentWidth(0);
  int y_height = decoder.GetComponentHeight(0);
  int u_width = decoder.GetComponentWidth(1);
  int u_height = decoder.GetComponentHeight(1);
  int v_width = decoder.GetComponentWidth(2);
  int v_height = decoder.GetComponentHeight(2);
  uint8_t *y;
  uint8_t *u;
  uint8_t *v;

  // Make sure that width and heigh stay at decent levels (< 16K * 16K).
  // (Y is the largest buffer).
  if (width > (1 << 14) || height > (1 << 14)) {
    // Ok, if this happens it's a DoS, but let's ignore it for now.
    return false;
  }

  // Allocate stides according to the sampling type.
  if (IsEqual(y_width, u_width, v_width) &&
      IsEqual(y_height, u_height, v_height)) {
    // Sampling type: YUV444.
    y = new uint8_t[width * height];
    u = new uint8_t[width * height];
    v = new uint8_t[width * height];

  } else if (IsEqual((y_width + 1) / 2, u_width, v_width) &&
      IsEqual(y_height, u_height, v_height)) {
    // Sampling type: YUV422.
    y = new uint8_t[width * height];
    u = new uint8_t[((width + 1) / 2) * height];
    v = new uint8_t[((width + 1) / 2) * height];

  } else if (IsEqual((y_width + 1) / 2, u_width, v_width) &&
      IsEqual((y_height + 1) / 2, u_height, v_height)) {
    // Sampling type: YUV420.
    y = new uint8_t[width * height];
    u = new uint8_t[((width + 1) / 2) * ((height + 1) / 2)];
    v = new uint8_t[((width + 1) / 2) * ((height + 1) / 2)];

  } else {
    // Invalid sampling type.
    return false;
  }

  uint8_t* planes[] = {y, u, v};

  // Do the actual decoding. (Ignore return values).
  decoder.DecodeToBuffers(planes, width, height);

  delete[] y;
  delete[] u;
  delete[] v;

  return true;  // Success!
}

// -----------------------------------------------------------------------------
// libFuzzer's callback that performs the actual fuzzing.
//
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  // Make sure that we have a minimum length (32 or something small).
  if (size < 32) {
      return 0;
  }

  // Create the decoder object.
  libyuv::MJpegDecoder decoder;

  // Load frame, read its headers and determine uncompress image format.
  if (decoder.LoadFrame(data, size) == LIBYUV_FALSE) {
    // Header parsing error. Discrad frame.
    return 0;
  }

  // Do the actual decoding.
  Decode(decoder);

  // Unload the frame.
  decoder.UnloadFrame();

  return 0;
}