// ----------------------------------------------------------------------------- // 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 #include #include #include #include // ----------------------------------------------------------------------------- // 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; }