diff --git a/projects/qcms/Dockerfile b/projects/qcms/Dockerfile new file mode 100644 index 000000000..723f5bfb8 --- /dev/null +++ b/projects/qcms/Dockerfile @@ -0,0 +1,22 @@ +# Copyright 2018 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +################################################################################ + +FROM gcr.io/oss-fuzz-base/base-builder +MAINTAINER pdknsk@gmail.com +RUN apt-get update && apt-get install -y mercurial +RUN hg clone https://hg.mozilla.org/mozilla-central/ firefox +COPY build.sh fuzz.cc fuzz.dict $SRC/ +WORKDIR firefox/gfx/qcms diff --git a/projects/qcms/build.sh b/projects/qcms/build.sh new file mode 100644 index 000000000..33bad932a --- /dev/null +++ b/projects/qcms/build.sh @@ -0,0 +1,35 @@ +#!/bin/bash -eu +# Copyright 2018 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +################################################################################ + +# moz.build +$CC $CFLAGS \ + -DNDEBUG -msse2 -Wno-missing-field-initializers \ + -c \ + chain.c \ + iccread.c \ + matrix.c \ + transform.c \ + transform-sse1.c \ + transform-sse2.c \ + transform_util.c + +$CXX $CXXFLAGS -std=c++11 \ + -I. *.o \ + -lFuzzingEngine \ + $SRC/fuzz.cc -o $OUT/fuzz + +cp $SRC/fuzz.dict $OUT diff --git a/projects/qcms/fuzz.cc b/projects/qcms/fuzz.cc new file mode 100644 index 000000000..76ed7fc66 --- /dev/null +++ b/projects/qcms/fuzz.cc @@ -0,0 +1,71 @@ +#include + +#include "qcms.h" + +static void transform(qcms_profile* src_profile, qcms_profile* dst_profile, + int alpha) { + // qcms supports GRAY and RGB profiles as input, and RGB as output. + + uint32_t src_color_space = qcms_profile_get_color_space(src_profile); + qcms_data_type src_type = alpha & 1 ? QCMS_DATA_RGBA_8 : QCMS_DATA_RGB_8; + if (src_color_space == icSigGrayData) + src_type = alpha & 1 ? QCMS_DATA_GRAYA_8 : QCMS_DATA_GRAY_8; + else if (src_color_space != icSigRgbData) + return; + + uint32_t dst_color_space = qcms_profile_get_color_space(dst_profile); + if (dst_color_space != icSigRgbData) + return; + qcms_data_type dst_type = alpha & 2 ? QCMS_DATA_RGBA_8 : QCMS_DATA_RGB_8; + + qcms_intent intent = qcms_profile_get_rendering_intent(src_profile); + qcms_profile_precache_output_transform(dst_profile); + + qcms_transform* transform = qcms_transform_create( + src_profile, src_type, dst_profile, dst_type, intent); + if (!transform) + return; + + static uint8_t src[] = { + 0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x7F, 0x7F, 0xFF, 0x7F, 0x10, 0x20, 0x30, + }; + static uint8_t dst[sizeof(src) * 4]; // 4x in case of GRAY to RGBA + + int src_bytes_per_pixel = 4; // QCMS_DATA_RGBA_8 + if (src_type == QCMS_DATA_RGB_8) + src_bytes_per_pixel = 3; + else if (src_type == QCMS_DATA_GRAYA_8) + src_bytes_per_pixel = 2; + else if (src_type == QCMS_DATA_GRAY_8) + src_bytes_per_pixel = 1; + + qcms_transform_data(transform, src, dst, sizeof(src) / src_bytes_per_pixel); + qcms_transform_release(transform); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + qcms_enable_iccv4(); + + qcms_profile* profile = qcms_profile_from_memory(data, size); + if (!profile) + return 0; + + // Firefox respects this check, but ignoring it gives slightly higher + // coverage. It only checks part of the profile for reasonable values, + // to not render output caused by likely broken profiles. + if (qcms_profile_is_bogus(profile)) {}; + + qcms_profile* srgb_profile = qcms_profile_sRGB(); + if (!srgb_profile) { + qcms_profile_release(profile); + return 0; + } + + transform(profile, srgb_profile, size & 3); + transform(srgb_profile, profile, size & 3); + + qcms_profile_release(profile); + qcms_profile_release(srgb_profile); + + return 0; +} diff --git a/projects/qcms/fuzz.dict b/projects/qcms/fuzz.dict new file mode 100644 index 000000000..b5dda7a39 --- /dev/null +++ b/projects/qcms/fuzz.dict @@ -0,0 +1,28 @@ +# tags used by qcms + +# v2 +0x41324230="A2B0" +0x42324130="B2A0" +0x47524159="GRAY" +0x4C616220="Lab " +0x52474220="RGB " +0x58595a20="XYZ " +0x62545243="bTRC" +0x6258595a="bXYZ" +0x63686164="chad" +0x63757276="curv" +0x67545243="gTRC" +0x6758595a="gXYZ" +0x6D667431="mft1" +0x6D667432="mft2" +0x6b545243="kTRC" +0x6d6e7472="mntr" +0x72545243="rTRC" +0x7258595a="rXYZ" +0x73636e72="scnr" +0x73663332="sf32" + +# v4 +0x6D414220="mAB " +0x6D424120="mBA " +0x70617261="para" diff --git a/projects/qcms/project.yaml b/projects/qcms/project.yaml new file mode 100644 index 000000000..8c5318e27 --- /dev/null +++ b/projects/qcms/project.yaml @@ -0,0 +1,6 @@ +homepage: "https://hg.mozilla.org/mozilla-central/file/tip/gfx/qcms/" +primary_contact: "agaynor@mozilla.com" +sanitizers: +- address +- undefined +- memory