diff --git a/Makefile b/Makefile index fbb945c..c652c42 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,9 @@ COMMONOBJ = $(BROTLIOBJ)/common/*.o OBJS = $(patsubst %, $(SRCDIR)/%, $(OUROBJ)) EXECUTABLES=woff2_compress woff2_decompress woff2_info EXE_OBJS=$(patsubst %, $(SRCDIR)/%.o, $(EXECUTABLES)) -ARCHIVES=convert_woff2ttf_fuzzer convert_woff2ttf_fuzzer_new_entry +ARCHIVES=convert_woff2ttf_fuzzer convert_woff2ttf_fuzzer_new_entry \ + convert_ttf2woff2_fuzzer woff2_memory_out_fuzzer \ + woff2_glyph_fuzzer woff2_font_fuzzer ARCHIVE_OBJS=$(patsubst %, $(SRCDIR)/%.o, $(ARCHIVES)) ifeq (,$(wildcard $(BROTLI)/*)) diff --git a/src/convert_ttf2woff2_fuzzer.cc b/src/convert_ttf2woff2_fuzzer.cc new file mode 100644 index 0000000..b7b5c36 --- /dev/null +++ b/src/convert_ttf2woff2_fuzzer.cc @@ -0,0 +1,46 @@ +#include +#include +#include +#include + +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + if (size < 1) { + return 0; + } + + woff2::WOFF2Params params; + uint8_t first_byte = data[0]; + params.allow_transforms = first_byte & 1; + params.brotli_quality = (first_byte >> 1) % 12; // 0-11 + + size_t metadata_size = 0; + if (size > 2) { + metadata_size = data[1] % (size - 1); + } + + if (metadata_size > 0) { + params.extended_metadata.assign(reinterpret_cast(data + 2), metadata_size); + } + + size_t offset = 2 + metadata_size; + if (offset > size) { + return 0; + } + + const uint8_t* font_data = data + offset; + size_t font_size = size - offset; + + if (font_size == 0) { + return 0; + } + + size_t result_length = woff2::MaxWOFF2CompressedSize(font_data, font_size, params.extended_metadata); + if (result_length > 30 * 1024 * 1024) { + return 0; + } + std::vector result(result_length); + woff2::ConvertTTFToWOFF2(font_data, font_size, result.data(), &result_length, params); + return 0; +} diff --git a/src/woff2_font_fuzzer.cc b/src/woff2_font_fuzzer.cc new file mode 100644 index 0000000..c3a86e4 --- /dev/null +++ b/src/woff2_font_fuzzer.cc @@ -0,0 +1,45 @@ +#include +#include +#include + +#include "font.h" +#include "normalize.h" +#include "transform.h" +#include "woff2_common.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + if (size < 10 || size > 1000000) { + return 0; + } + woff2::FontCollection font_collection; + if (!woff2::ReadFontCollection(data, size, &font_collection)) { + return 0; + } + + woff2::NormalizeFontCollection(&font_collection); + + for (auto& font : font_collection.fonts) { + woff2::TransformGlyfAndLocaTables(&font); + woff2::TransformHmtxTable(&font); + } + + size_t out_size = woff2::FontCollectionFileSize(font_collection); + // Robust size calculation for TTC header + if (font_collection.flavor == woff2::kTtcFontFlavor) { + size_t header_size = 12 + 4 * font_collection.fonts.size(); + if (font_collection.header_version == 0x00020000) { + header_size += 12; + } + out_size = std::max(out_size, header_size); + } + + if (out_size == 0 || out_size > 30 * 1024 * 1024) { + return 0; + } + + // Add some padding to be safe against library bugs + std::vector out(out_size + 1024); + woff2::WriteFontCollection(font_collection, out.data(), out.size()); + + return 0; +} diff --git a/src/woff2_glyph_fuzzer.cc b/src/woff2_glyph_fuzzer.cc new file mode 100644 index 0000000..cc730d3 --- /dev/null +++ b/src/woff2_glyph_fuzzer.cc @@ -0,0 +1,21 @@ +#include +#include +#include + +#include "glyph.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + if (size < 2 || size > 10000) { + return 0; + } + woff2::Glyph glyph; + if (!woff2::ReadGlyph(data, size, &glyph)) { + return 0; + } + + size_t dst_size = size * 2 + 1024; // Provide enough space + std::vector dst(dst_size); + woff2::StoreGlyph(glyph, dst.data(), &dst_size); + + return 0; +} diff --git a/src/woff2_memory_out_fuzzer.cc b/src/woff2_memory_out_fuzzer.cc new file mode 100644 index 0000000..cbe327f --- /dev/null +++ b/src/woff2_memory_out_fuzzer.cc @@ -0,0 +1,18 @@ +#include +#include +#include + +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + size_t final_size = woff2::ComputeWOFF2FinalSize(data, size); + if (final_size == 0 || final_size > 30 * 1024 * 1024) { + return 0; + } + + std::vector result(final_size); + woff2::WOFF2MemoryOut out(result.data(), result.size()); + woff2::ConvertWOFF2ToTTF(data, size, &out); + return 0; +}