Bug 730190 - Update OTS to r81. r=jfkthame
authorYury <async.processingjs@yahoo.com>
Fri, 24 Feb 2012 14:31:11 +0100
changeset 87651 34e81dfe34a2a6dfce760a7e6b22d4fe685ddef5
parent 87650 7925703fbce671938e15996bc6abc4fd622dc899
child 87652 ade1f5c930d6a1fba120ff9236246f7e37832705
push idunknown
push userunknown
push dateunknown
reviewersjfkthame
bugs730190
milestone13.0a1
Bug 730190 - Update OTS to r81. r=jfkthame
gfx/ots/README.mozilla
gfx/ots/include/opentype-sanitiser.h
gfx/ots/src/cff.cc
gfx/ots/src/ots.cc
--- a/gfx/ots/README.mozilla
+++ b/gfx/ots/README.mozilla
@@ -1,8 +1,8 @@
 This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/.
 
-Current revision: r77
+Current revision: r81
 
 Applied local patches:
     ots-fix-vc10.patch - workaround for VS10 STL wrappers (bug 602558)
 
     ots-fix-sparc64.patch - fix alignment error on sparc64 (bug 643137)
--- a/gfx/ots/include/opentype-sanitiser.h
+++ b/gfx/ots/include/opentype-sanitiser.h
@@ -72,18 +72,19 @@ class OTSStream {
         std::min(length, static_cast<size_t>(4) - chksum_buffer_offset_);
       std::memcpy(chksum_buffer_ + chksum_buffer_offset_, data, l);
       chksum_buffer_offset_ += l;
       offset += l;
       length -= l;
     }
 
     if (chksum_buffer_offset_ == 4) {
-      // TODO(yusukes): This cast breaks the strict-aliasing rule.
-      chksum_ += ntohl(*reinterpret_cast<const uint32_t*>(chksum_buffer_));
+      uint32_t chksum;
+      std::memcpy(&chksum, chksum_buffer_, 4);
+      chksum_ += ntohl(chksum);
       chksum_buffer_offset_ = 0;
     }
 
     while (length >= 4) {
       uint32_t tmp;
       std::memcpy(&tmp, reinterpret_cast<const uint8_t *>(data) + offset,
         sizeof(uint32_t));
       chksum_ += ntohl(tmp);
--- a/gfx/ots/src/cff.cc
+++ b/gfx/ots/src/cff.cc
@@ -755,24 +755,23 @@ bool ParseDictData(const uint8_t *data, 
             return OTS_FAILURE();
           }
           const uint32_t private_offset = operands.back().first;
           operands.pop_back();
           if (operands.back().second != DICT_OPERAND_INTEGER) {
             return OTS_FAILURE();
           }
           const uint32_t private_length = operands.back().first;
-          if (private_offset >= table_length) {
+          if (private_offset > table_length) {
             return OTS_FAILURE();
           }
           if (private_length >= table_length) {
             return OTS_FAILURE();
           }
           if (private_length + private_offset > table_length) {
-            // does not overflow since table_length < 1GB
             return OTS_FAILURE();
           }
           // parse "15. Private DICT Data"
           if (!ParsePrivateDictData(data, table_length,
                                     private_offset, private_length,
                                     type, out_cff)) {
             return OTS_FAILURE();
           }
--- a/gfx/ots/src/ots.cc
+++ b/gfx/ots/src/ots.cc
@@ -5,16 +5,17 @@
 #include "ots.h"
 
 #include <sys/types.h>
 #include <zlib.h>
 
 #include <algorithm>
 #include <cstdlib>
 #include <cstring>
+#include <limits>
 #include <map>
 #include <vector>
 
 // The OpenType Font File
 // http://www.microsoft.com/typography/otspec/cmap.htm
 
 namespace {
 
@@ -23,19 +24,22 @@ bool g_debug_output = true;
 struct OpenTypeTable {
   uint32_t tag;
   uint32_t chksum;
   uint32_t offset;
   uint32_t length;
   uint32_t uncompressed_length;
 };
 
-// Round a value up to the nearest multiple of 4. Note that this can overflow
-// and return zero.
+// Round a value up to the nearest multiple of 4. Don't round the value in the
+// case that rounding up overflows.
 template<typename T> T Round4(T value) {
+  if (std::numeric_limits<T>::max() - value < 3) {
+    return value;
+  }
   return (value + 3) & ~3;
 }
 
 bool CheckTag(uint32_t tag_value) {
   for (unsigned i = 0; i < 4; ++i) {
     const uint32_t check = tag_value & 0xff;
     if (check < 32 || check > 126) {
       return false;  // non-ASCII character found.
@@ -275,48 +279,135 @@ bool ProcessWOFF(ots::OpenTypeFile *head
   header->entry_selector = 0;
   header->range_shift = 0;
 
   uint32_t reported_length;
   if (!file.ReadU32(&reported_length) || length != reported_length) {
     return OTS_FAILURE();
   }
 
-  if (!file.ReadU16(&header->num_tables)) {
+  if (!file.ReadU16(&header->num_tables) || !header->num_tables) {
     return OTS_FAILURE();
   }
 
   uint16_t reserved_value;
   if (!file.ReadU16(&reserved_value) || reserved_value) {
     return OTS_FAILURE();
   }
 
+  uint32_t reported_total_sfnt_size;
+  if (!file.ReadU32(&reported_total_sfnt_size)) {
+    return OTS_FAILURE();
+  }
+
   // We don't care about these fields of the header:
-  //   uint32_t uncompressed_size;
   //   uint16_t major_version, minor_version
-  //   uint32_t meta_offset, meta_length, meta_length_orig
-  //   uint32_t priv_offset, priv_length
-  if (!file.Skip(6 * 4 + 2 * 2)) {
+  if (!file.Skip(2 * 2)) {
+    return OTS_FAILURE();
+  }
+
+  // Checks metadata block size.
+  uint32_t meta_offset;
+  uint32_t meta_length;
+  uint32_t meta_length_orig;
+  if (!file.ReadU32(&meta_offset) ||
+      !file.ReadU32(&meta_length) ||
+      !file.ReadU32(&meta_length_orig)) {
     return OTS_FAILURE();
   }
+  if (meta_offset) {
+    if (meta_offset >= length || length - meta_offset < meta_length) {
+      return OTS_FAILURE();
+    }
+  }
+
+  // Checks private data block size.
+  uint32_t priv_offset;
+  uint32_t priv_length;
+  if (!file.ReadU32(&priv_offset) ||
+      !file.ReadU32(&priv_length)) {
+    return OTS_FAILURE();
+  }
+  if (priv_offset) {
+    if (priv_offset >= length || length - priv_offset < priv_length) {
+      return OTS_FAILURE();
+    }
+  }
 
   // Next up is the list of tables.
   std::vector<OpenTypeTable> tables;
 
+  uint32_t first_index = 0;
+  uint32_t last_index = 0;
+  // Size of sfnt header plus size of table records.
+  uint64_t total_sfnt_size = 12 + 16 * header->num_tables;
   for (unsigned i = 0; i < header->num_tables; ++i) {
     OpenTypeTable table;
     if (!file.ReadTag(&table.tag) ||
         !file.ReadU32(&table.offset) ||
         !file.ReadU32(&table.length) ||
         !file.ReadU32(&table.uncompressed_length) ||
         !file.ReadU32(&table.chksum)) {
       return OTS_FAILURE();
     }
 
+    total_sfnt_size += Round4(table.uncompressed_length);
+    if (total_sfnt_size > std::numeric_limits<uint32_t>::max()) {
+      return OTS_FAILURE();
+    }
     tables.push_back(table);
+    if (i == 0 || tables[first_index].offset > table.offset)
+      first_index = i;
+    if (i == 0 || tables[last_index].offset < table.offset)
+      last_index = i;
+  }
+
+  if (reported_total_sfnt_size != total_sfnt_size) {
+    return OTS_FAILURE();
+  }
+
+  // Table data must follow immediately after the header.
+  if (tables[first_index].offset != Round4(file.offset())) {
+    return OTS_FAILURE();
+  }
+
+  if (tables[last_index].offset >= length ||
+      length - tables[last_index].offset < tables[last_index].length) {
+    return OTS_FAILURE();
+  }
+  // Blocks must follow immediately after the previous block.
+  // (Except for padding with a maximum of three null bytes)
+  uint64_t block_end = Round4(
+      static_cast<uint64_t>(tables[last_index].offset) +
+      static_cast<uint64_t>(tables[last_index].length));
+  if (block_end > std::numeric_limits<uint32_t>::max()) {
+    return OTS_FAILURE();
+  }
+  if (meta_offset) {
+    if (block_end != meta_offset) {
+      return OTS_FAILURE();
+    }
+    block_end = Round4(static_cast<uint64_t>(meta_offset) +
+                       static_cast<uint64_t>(meta_length));
+    if (block_end > std::numeric_limits<uint32_t>::max()) {
+      return OTS_FAILURE();
+    }
+  }
+  if (priv_offset) {
+    if (block_end != priv_offset) {
+      return OTS_FAILURE();
+    }
+    block_end = Round4(static_cast<uint64_t>(priv_offset) +
+                       static_cast<uint64_t>(priv_length));
+    if (block_end > std::numeric_limits<uint32_t>::max()) {
+      return OTS_FAILURE();
+    }
+  }
+  if (block_end != Round4(length)) {
+    return OTS_FAILURE();
   }
 
   return ProcessGeneric(header, output, data, length, tables, file);
 }
 
 bool ProcessGeneric(ots::OpenTypeFile *header, ots::OTSStream *output,
                     const uint8_t *data, size_t length,
                     const std::vector<OpenTypeTable>& tables,
@@ -373,21 +464,21 @@ bool ProcessGeneric(ots::OpenTypeFile *h
       if (uncompressed_sum + tables[i].uncompressed_length < uncompressed_sum) {
         return OTS_FAILURE();
       }
 
       uncompressed_sum += tables[i].uncompressed_length;
     }
     // since we required that the file be < 1GB in length, and that the table
     // length is < 1GB, the following addtion doesn't overflow
-    const uint32_t end_byte = Round4(tables[i].offset + tables[i].length);
+    const uint32_t end_byte = tables[i].offset + tables[i].length;
     // Some fonts which are automatically generated by a font generator
     // called TTX seems not to add 0-padding to the final table. It might be
     // ok to accept these fonts so we round up the length of the font file.
-    if (!end_byte || end_byte > Round4(length)) {
+    if (!end_byte || end_byte > length) {
       return OTS_FAILURE();
     }
   }
 
   // All decompressed tables uncompressed must be <= 30MB.
   if (uncompressed_sum > 30 * 1024 * 1024) {
     return OTS_FAILURE();
   }