aboutsummaryrefslogtreecommitdiffhomepage
path: root/projects
diff options
context:
space:
mode:
authorGravatar ecalp-tps <72207867+ecalp-tps@users.noreply.github.com>2020-11-26 18:38:10 +0100
committerGravatar GitHub <noreply@github.com>2020-11-26 09:38:10 -0800
commit945e74805a3809d2c09fc2ca4119a4bc16e20368 (patch)
treeca59d456b8207fbb73769f871c75f4f46474c4e3 /projects
parent27c07b51923154e9acf0906feeda114a4c813b9b (diff)
[Cairo] Initial integration (#4703)
* Initial commit with build script and Dockerfile * Corpus and dictionary added * Some comments * Trigger build check * Remove MSan * Move glib extraction to Dockerfile * Move fuzzers into this repo. Fetch cairo from the upstream repo. * Add missing license headers * Fix dictionary and seed corpus * Replace malloc with calloc. Remove unused variable. Replace DEFINE with const. Minor fix
Diffstat (limited to 'projects')
-rw-r--r--projects/cairo/Dockerfile30
-rwxr-xr-xprojects/cairo/build.sh92
-rw-r--r--projects/cairo/project.yaml6
-rw-r--r--projects/cairo/targets/fuzzer_temp_file.h81
-rw-r--r--projects/cairo/targets/pdf_surface_fuzzer.c51
-rw-r--r--projects/cairo/targets/raster_fuzzer.c71
-rw-r--r--projects/cairo/targets/surface_write_png_fuzzer.c46
-rw-r--r--projects/cairo/targets/text_glyphs_fuzzer.c59
8 files changed, 436 insertions, 0 deletions
diff --git a/projects/cairo/Dockerfile b/projects/cairo/Dockerfile
new file mode 100644
index 00000000..7463bbd4
--- /dev/null
+++ b/projects/cairo/Dockerfile
@@ -0,0 +1,30 @@
+# 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
+RUN apt-get update && apt-get install -y python3-pip gtk-doc-tools libffi-dev
+RUN pip3 install -U meson==0.55.3 ninja
+
+RUN git clone --depth 1 git://git.sv.nongnu.org/freetype/freetype2.git
+ADD https://ftp.gnome.org/pub/gnome/sources/glib/2.64/glib-2.64.2.tar.xz $SRC
+RUN tar xvJf $SRC/glib-2.64.2.tar.xz
+RUN git clone --depth 1 https://gitlab.freedesktop.org/cairo/cairo.git && \
+ zip -q $SRC/cairo_seed_corpus.zip $SRC/cairo/test/reference/*
+
+ADD https://raw.githubusercontent.com/google/fuzzing/master/dictionaries/png.dict $SRC/cairo.dict
+
+WORKDIR $SRC/cairo
+COPY targets $SRC/fuzz
+COPY build.sh $SRC/
diff --git a/projects/cairo/build.sh b/projects/cairo/build.sh
new file mode 100755
index 00000000..655103e2
--- /dev/null
+++ b/projects/cairo/build.sh
@@ -0,0 +1,92 @@
+#!/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.
+#
+################################################################################
+PREFIX=$WORK/prefix
+mkdir -p $PREFIX
+
+export PKG_CONFIG="`which pkg-config` --static"
+export PKG_CONFIG_PATH=$PREFIX/lib/pkgconfig
+export PATH=$PREFIX/bin:$PATH
+
+BUILD=$WORK/build
+
+rm -rf $WORK/*
+rm -rf $BUILD
+mkdir -p $BUILD
+
+# Build glib
+pushd $SRC/glib-2.64.2
+meson \
+ --prefix=$PREFIX \
+ --libdir=lib \
+ --default-library=static \
+ -Db_lundef=false \
+ -Doss_fuzz=enabled \
+ -Dlibmount=disabled \
+ -Dinternal_pcre=true \
+ _builddir
+ninja -C _builddir
+ninja -C _builddir install
+popd
+
+pushd $SRC/freetype2
+./autogen.sh
+./configure --prefix="$PREFIX" --disable-shared PKG_CONFIG_PATH="$PKG_CONFIG_PATH"
+make -j$(nproc)
+make install
+
+# Build cairo
+pushd $SRC/cairo
+meson \
+ --prefix=$PREFIX \
+ --libdir=lib \
+ --default-library=static \
+ _builddir
+ninja -C _builddir
+ninja -C _builddir install
+popd
+
+mv $SRC/{*.zip,*.dict} $OUT
+
+if [ ! -f "${OUT}/cairo_seed_corpus.zip" ]; then
+ echo "missing seed corpus"
+ exit 1
+fi
+
+if [ ! -f "${OUT}/cairo.dict" ]; then
+ echo "missing dictionary"
+ exit 1
+fi
+
+PREDEPS_LDFLAGS="-Wl,-Bdynamic -ldl -lm -lc -pthread -lrt -lpthread"
+DEPS="gmodule-2.0 glib-2.0 gio-2.0 gobject-2.0 freetype2 cairo cairo-gobject"
+BUILD_CFLAGS="$CFLAGS `pkg-config --static --cflags $DEPS`"
+BUILD_LDFLAGS="-Wl,-static `pkg-config --static --libs $DEPS`"
+
+fuzzers=$(find $SRC/fuzz/ -name "*_fuzzer.c")
+for f in $fuzzers; do
+ fuzzer_name=$(basename $f .c)
+ $CC $CFLAGS $BUILD_CFLAGS \
+ -c $f -o $WORK/${fuzzer_name}.o
+ $CXX $CXXFLAGS \
+ $WORK/${fuzzer_name}.o -o $OUT/${fuzzer_name} \
+ $PREDEPS_LDFLAGS \
+ $BUILD_LDFLAGS \
+ $LIB_FUZZING_ENGINE \
+ -Wl,-Bdynamic
+ ln -sf $SRC/cairo_seed_corpus.zip $OUT/${fuzzer_name}_seed_corpus.zip
+ ln -sf $SRC/cairo.dict $OUT/${fuzzer_name}.dict
+done
diff --git a/projects/cairo/project.yaml b/projects/cairo/project.yaml
new file mode 100644
index 00000000..37b8def4
--- /dev/null
+++ b/projects/cairo/project.yaml
@@ -0,0 +1,6 @@
+homepage: https://gitlab.freedesktop.org/cairo/cairo
+language: c
+primary_contact: security-tps@google.com
+sanitizers:
+ - address
+ - undefined
diff --git a/projects/cairo/targets/fuzzer_temp_file.h b/projects/cairo/targets/fuzzer_temp_file.h
new file mode 100644
index 00000000..158b4978
--- /dev/null
+++ b/projects/cairo/targets/fuzzer_temp_file.h
@@ -0,0 +1,81 @@
+// 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.
+
+// Adapter utility from fuzzer input to a temporary file, for fuzzing APIs that
+// require a file instead of an input buffer.
+
+#ifndef FUZZER_TEMP_FILE_H_
+#define FUZZER_TEMP_FILE_H_
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+// Pure-C interface for creating and cleaning up temporary files.
+
+static char* fuzzer_get_tmpfile(const uint8_t* data, size_t size) {
+ char* filename_buffer = strdup("/tmp/generate_temporary_file.XXXXXX");
+ if (!filename_buffer) {
+ perror("Failed to allocate file name buffer.");
+ abort();
+ }
+ const int file_descriptor = mkstemp(filename_buffer);
+ if (file_descriptor < 0) {
+ perror("Failed to make temporary file.");
+ abort();
+ }
+ FILE* file = fdopen(file_descriptor, "wb");
+ if (!file) {
+ perror("Failed to open file descriptor.");
+ close(file_descriptor);
+ abort();
+ }
+ const size_t bytes_written = fwrite(data, sizeof(uint8_t), size, file);
+ if (bytes_written < size) {
+ close(file_descriptor);
+ fprintf(stderr, "Failed to write all bytes to file (%zu out of %zu)",
+ bytes_written, size);
+ abort();
+ }
+ fclose(file);
+ return filename_buffer;
+}
+
+static void fuzzer_release_tmpfile(char* filename) {
+ if (unlink(filename) != 0) {
+ perror("WARNING: Failed to delete temporary file.");
+ }
+ free(filename);
+}
+
+// C++ RAII object for creating temporary files.
+
+#ifdef __cplusplus
+class FuzzerTemporaryFile {
+ public:
+ FuzzerTemporaryFile(const uint8_t* data, size_t size)
+ : filename_(fuzzer_get_tmpfile(data, size)) {}
+
+ ~FuzzerTemporaryFile() { fuzzer_release_tmpfile(filename_); }
+
+ const char* filename() const { return filename_; }
+
+ private:
+ char* filename_;
+};
+#endif
+
+#endif // FUZZER_TEMP_FILE_H_
diff --git a/projects/cairo/targets/pdf_surface_fuzzer.c b/projects/cairo/targets/pdf_surface_fuzzer.c
new file mode 100644
index 00000000..7869f637
--- /dev/null
+++ b/projects/cairo/targets/pdf_surface_fuzzer.c
@@ -0,0 +1,51 @@
+// Copyright 2020 Google LLC
+//
+// 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.
+
+#include <cairo.h>
+#include <cairo-pdf.h>
+#include "fuzzer_temp_file.h"
+
+const double width_in_inches = 3;
+const double height_in_inches = 3;
+const double width_in_points = width_in_inches * 72.0;
+const double height_in_points = height_in_inches * 72.0;
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ cairo_t *cr;
+ cairo_surface_t *surface;
+ cairo_status_t status;
+
+ char *tmpfile = fuzzer_get_tmpfile(data, size);
+ surface = cairo_pdf_surface_create(tmpfile, width_in_points, height_in_points);
+ status = cairo_surface_status(surface);
+ if (status != CAIRO_STATUS_SUCCESS) {
+ fuzzer_release_tmpfile(tmpfile);
+ return 0;
+ }
+
+ char *buf = (char *) calloc(size + 1, sizeof(char));
+ memcpy(buf, data, size);
+ buf[size] = '\0';
+
+ cairo_pdf_surface_set_metadata(surface, CAIRO_PDF_METADATA_TITLE, buf);
+ cr = cairo_create(surface);
+ cairo_tag_begin(cr, buf, NULL);
+ cairo_tag_end(cr, buf);
+
+ cairo_destroy(cr);
+ cairo_surface_destroy(surface);
+ free(buf);
+ fuzzer_release_tmpfile(tmpfile);
+ return 0;
+}
diff --git a/projects/cairo/targets/raster_fuzzer.c b/projects/cairo/targets/raster_fuzzer.c
new file mode 100644
index 00000000..e7f9bc19
--- /dev/null
+++ b/projects/cairo/targets/raster_fuzzer.c
@@ -0,0 +1,71 @@
+// Copyright 2020 Google LLC
+//
+// 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.
+
+#include <cairo.h>
+#include <cairo-pdf.h>
+#include "fuzzer_temp_file.h"
+
+static cairo_surface_t *
+acquire (cairo_pattern_t *pattern, void *closure,
+ cairo_surface_t *target,
+ const cairo_rectangle_int_t *extents)
+{
+ return cairo_image_surface_create_from_png(closure);
+}
+
+static void
+release (cairo_pattern_t *pattern, void *closure, cairo_surface_t *surface)
+{
+ cairo_surface_destroy(surface);
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ cairo_t *cr;
+ cairo_surface_t *surface;
+ cairo_pattern_t *pattern;
+ cairo_content_t content;
+ cairo_status_t status;
+ int w, h;
+
+ char *tmpfile = fuzzer_get_tmpfile(data, size);
+ surface = cairo_image_surface_create_from_png(tmpfile);
+ status = cairo_surface_status (surface);
+ if (status != CAIRO_STATUS_SUCCESS) {
+ fuzzer_release_tmpfile(tmpfile);
+ return 0;
+ }
+
+ cr = cairo_create(surface);
+ content = cairo_surface_get_content(surface);
+ w = cairo_image_surface_get_width(surface);
+ h = cairo_image_surface_get_height(surface);
+
+ char *buf = (char *) calloc(size + 1, sizeof(char));
+ memcpy(buf, data, size);
+ buf[size] = '\0';
+
+ pattern = cairo_pattern_create_raster_source(buf, content, w, h);
+ cairo_raster_source_pattern_set_acquire (pattern, acquire, release);
+ cairo_set_source(cr, pattern);
+ cairo_pdf_surface_set_page_label(surface, buf);
+ cairo_pdf_surface_set_metadata(surface, CAIRO_PDF_METADATA_KEYWORDS, buf);
+ cairo_paint(cr);
+
+ cairo_destroy(cr);
+ cairo_pattern_destroy(pattern);
+ cairo_surface_destroy(surface);
+ free(buf);
+ fuzzer_release_tmpfile(tmpfile);
+ return 0;
+}
diff --git a/projects/cairo/targets/surface_write_png_fuzzer.c b/projects/cairo/targets/surface_write_png_fuzzer.c
new file mode 100644
index 00000000..9819fa28
--- /dev/null
+++ b/projects/cairo/targets/surface_write_png_fuzzer.c
@@ -0,0 +1,46 @@
+// Copyright 2020 Google LLC
+//
+// 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.
+
+#include <cairo.h>
+#include "fuzzer_temp_file.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ cairo_surface_t *image;
+ cairo_surface_t *surface;
+ cairo_status_t status;
+ cairo_format_t format;
+
+ char *tmpfile = fuzzer_get_tmpfile(data, size);
+ image = cairo_image_surface_create_from_png(tmpfile);
+ status = cairo_surface_status (image);
+ if (status != CAIRO_STATUS_SUCCESS) {
+ fuzzer_release_tmpfile(tmpfile);
+ return 0;
+ }
+
+ format = cairo_image_surface_get_format(image);
+ surface = cairo_image_surface_create_for_data((unsigned char*)data, format, 1, 1, size);
+ status = cairo_surface_status (surface);
+ if (status != CAIRO_STATUS_SUCCESS) {
+ cairo_surface_destroy(image);
+ fuzzer_release_tmpfile(tmpfile);
+ return 0;
+ }
+ cairo_surface_write_to_png(surface, tmpfile);
+
+ cairo_surface_destroy(surface);
+ cairo_surface_destroy(image);
+ fuzzer_release_tmpfile(tmpfile);
+ return 0;
+}
diff --git a/projects/cairo/targets/text_glyphs_fuzzer.c b/projects/cairo/targets/text_glyphs_fuzzer.c
new file mode 100644
index 00000000..41c180df
--- /dev/null
+++ b/projects/cairo/targets/text_glyphs_fuzzer.c
@@ -0,0 +1,59 @@
+// Copyright 2020 Google LLC
+//
+// 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.
+
+#include <cairo.h>
+#include "fuzzer_temp_file.h"
+
+const int glyph_range = 9;
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ if (size < glyph_range) {
+ return 0;
+ }
+ cairo_t *cr;
+ cairo_surface_t *surface;
+ cairo_status_t status;
+ cairo_text_extents_t extents;
+ cairo_text_cluster_t cluster;
+
+ char *tmpfile = fuzzer_get_tmpfile(data, size);
+ surface = cairo_image_surface_create_from_png(tmpfile);
+ status = cairo_surface_status(surface);
+ if (status != CAIRO_STATUS_SUCCESS) {
+ fuzzer_release_tmpfile(tmpfile);
+ return 0;
+ }
+
+ char *buf = (char *) calloc(size + 1, sizeof(char));
+ memcpy(buf, data, size);
+ buf[size] = '\0';
+
+ cr = cairo_create(surface);
+ cairo_text_extents(cr, buf, &extents);
+ cluster.num_bytes = size;
+ cluster.num_glyphs = 1;
+ for (int i = 0; i < glyph_range; i++) {
+ // Taken from test/text-glyph-range.c
+ cairo_glyph_t glyph = {
+ (long int)data[i], 10 * i, 25
+ };
+ cairo_show_text_glyphs(cr, buf, size, &glyph, 1, &cluster, 1, 0);
+ }
+
+ cairo_destroy(cr);
+ cairo_surface_destroy(surface);
+ free(buf);
+ fuzzer_release_tmpfile(tmpfile);
+ return 0;
+}