From a15a8ab86b934cf436f8fac4a8a11ddf8b59d792 Mon Sep 17 00:00:00 2001 From: Rod Sheeter Date: Fri, 6 May 2016 13:14:42 -0700 Subject: [PATCH] Fixes for bugs uncovered by libFuzzer analysis. A write past buffer, a potential DOS by way of giant alloc, and an out of range access. --- src/woff2_dec.cc | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/woff2_dec.cc b/src/woff2_dec.cc index 1e63caa..7a00f8a 100644 --- a/src/woff2_dec.cc +++ b/src/woff2_dec.cc @@ -70,6 +70,10 @@ const size_t kCompositeGlyphBegin = 10; // Largest glyph ever observed was 72k bytes const size_t kDefaultGlyphBuf = 5120; +// Over 14k test fonts the max compression ratio seen to date was ~20. +// >100 suggests you wrote a bad uncompressed size. +const float kMaxPlausibleCompressionRatio = 100.0; + // metadata for a TTC font entry struct TtcFont { uint32_t flavor; @@ -478,7 +482,7 @@ bool ReconstructGlyf(const uint8_t* data, Table* glyf_table, } } - size_t size_needed = 2 + composite_size + instruction_size; + size_t size_needed = 12 + composite_size + instruction_size; if (PREDICT_FALSE(glyph_buf_size < size_needed)) { glyph_buf.reset(new uint8_t[size_needed]); glyph_buf_size = size_needed; @@ -672,6 +676,11 @@ bool ReconstructTransformedHmtx(const uint8_t* transformed_buf, assert(x_mins.size() == num_glyphs); + // num_glyphs 0 is OK if there is no 'glyf' but cannot then xform 'hmtx'. + if (PREDICT_FALSE(num_hmetrics > num_glyphs)) { + return FONT_COMPRESSION_FAILURE(); + } + for (uint16_t i = 0; i < num_hmetrics; i++) { uint16_t advance_width; if (PREDICT_FALSE(!hmtx_buff_in.ReadU16(&advance_width))) { @@ -1270,6 +1279,14 @@ bool ConvertWOFF2ToTTF(const uint8_t* data, size_t length, return FONT_COMPRESSION_FAILURE(); } + const float compression_ratio = (float) hdr.uncompressed_size / length; + if (compression_ratio > kMaxPlausibleCompressionRatio) { +#ifdef FONT_COMPRESSION_BIN + fprintf(stderr, "Implausible compression ratio %.01f\n", compression_ratio); +#endif + return FONT_COMPRESSION_FAILURE(); + } + const uint8_t* src_buf = data + hdr.compressed_offset; std::vector uncompressed_buf(hdr.uncompressed_size); if (PREDICT_FALSE(!Woff2Uncompress(&uncompressed_buf[0],