1 #![no_main]
2 use libfuzzer_sys::fuzz_target;
3 extern crate qcms;
4 extern crate libc;
5 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
6 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
7 /* This Source Code Form is subject to the terms of the Mozilla Public
8  * License, v. 2.0. If a copy of the MPL was not distributed with this
9  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
10 
11 use qcms::c_bindings::{qcms_profile, icSigRgbData, icSigCmykData, icSigGrayData, qcms_profile_is_bogus};
12 use qcms::c_bindings::{qcms_profile_get_color_space, qcms_profile_get_rendering_intent, qcms_profile_from_memory, qcms_profile_release, qcms_profile_sRGB, qcms_transform_create};
13 use qcms::c_bindings::{qcms_profile_precache_output_transform, qcms_transform_data, qcms_transform_release, qcms_enable_iccv4};
14 
15 use qcms::DataType::*;
16 
transform(src_profile: *const qcms_profile, dst_profile: *mut qcms_profile, size: usize)17  unsafe fn transform(src_profile: *const qcms_profile, dst_profile: *mut qcms_profile, size: usize)
18  {
19    // qcms supports GRAY and RGB profiles as input, and RGB as output.
20 
21    let src_color_space = qcms_profile_get_color_space(&*src_profile);
22    let mut src_type = if (size & 1) != 0 { RGBA8 } else { RGB8 };
23    if src_color_space == icSigGrayData {
24      src_type = if (size & 1) != 0 { GrayA8 } else { Gray8 };
25    } else if src_color_space == icSigCmykData {
26      src_type = CMYK;
27    } else if src_color_space != icSigRgbData {
28      return;
29    }
30 
31    let dst_color_space = qcms_profile_get_color_space(&*dst_profile);
32    if dst_color_space != icSigRgbData {
33      return;
34    }
35    let dst_type = if (size & 2) != 0 { RGBA8 } else { RGB8 };
36 
37    let intent = qcms_profile_get_rendering_intent(&*src_profile);
38    // Firefox calls this on the display profile to increase performance.
39    // Skip with low probability to increase coverage.
40    if (size % 15) != 0 {
41      qcms_profile_precache_output_transform(&mut *dst_profile);
42    }
43 
44    let transform =
45      qcms_transform_create(&*src_profile, src_type, &*dst_profile, dst_type, intent);
46    if transform == std::ptr::null_mut() {
47      return;
48    }
49 
50    const SRC_SIZE: usize = 36;
51    let src:[u8; SRC_SIZE] = [
52      0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x7F, 0x7F, 0xFF, 0x7F, 0x10, 0x20, 0x30,
53      0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xB0, 0xBF, 0xEF, 0x6F,
54      0x3F, 0xC0, 0x9F, 0xE0, 0x90, 0xCF, 0x40, 0xAF, 0x0F, 0x01, 0x60, 0xF0,
55    ];
56    let mut dst: [u8; 36 * 4] = [0; 144]; // 4x in case of GRAY to RGBA
57 
58    qcms_transform_data(&*transform, src.as_ptr() as *const libc::c_void, dst.as_mut_ptr() as *mut libc::c_void, (SRC_SIZE / src_type.bytes_per_pixel()) as usize);
59    qcms_transform_release(transform);
60  }
61 
do_fuzz(data: &[u8])62  unsafe fn do_fuzz(data: &[u8])
63  {
64    let size = data.len();
65    qcms_enable_iccv4();
66 
67    let profile = qcms_profile_from_memory(data.as_ptr() as *const libc::c_void, size);
68    if profile == std::ptr::null_mut() {
69      return;
70    }
71 
72    let srgb_profile = qcms_profile_sRGB();
73    if srgb_profile == std::ptr::null_mut() {
74      qcms_profile_release(profile);
75      return;
76    }
77 
78    transform(profile, srgb_profile, size);
79 
80    // Firefox only checks the display (destination) profile.
81    if !qcms_profile_is_bogus(&mut *profile) {
82 
83      transform(srgb_profile, profile, size);
84      let identity = qcms::Profile::new_XYZD50();
85      transform(&*identity, profile, size);
86    }
87    qcms_profile_release(profile);
88    qcms_profile_release(srgb_profile);
89 
90    return;
91  }
92 
93 
94 
95 fuzz_target!(|data: &[u8]| {
96     unsafe { do_fuzz(data) }
97 });
98