summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaph Levien <raph@google.com>2016-01-06 14:31:23 -0800
committerThe Android Automerger <android-build@google.com>2016-02-26 16:56:13 -0800
commit013771f6e806f9dc32ec4318dd4e1ddd79be0878 (patch)
tree9e639f4e9b93dc3249a42c6c2e7f638d9bf9cce5
parente4c07b52019e1f12beac171017b15360cdf67641 (diff)
downloadandroid_frameworks_minikin-013771f6e806f9dc32ec4318dd4e1ddd79be0878.tar.gz
android_frameworks_minikin-013771f6e806f9dc32ec4318dd4e1ddd79be0878.tar.bz2
android_frameworks_minikin-013771f6e806f9dc32ec4318dd4e1ddd79be0878.zip
Reject fonts with invalid ranges in cmap
A corrupt or malicious font may have a negative size in its cmap range, which in turn could lead to memory corruption. This patch detects the case and rejects the font, and also includes an assertion in the sparse bit set implementation if we missed any such case. External issue: https://code.google.com/p/android/issues/detail?id=192618 Bug: 26413177 Change-Id: Icc0c80e4ef389abba0964495b89aa0fae3e9f4b2
-rw-r--r--libs/minikin/CmapCoverage.cpp41
-rw-r--r--libs/minikin/SparseBitSet.cpp2
2 files changed, 27 insertions, 16 deletions
diff --git a/libs/minikin/CmapCoverage.cpp b/libs/minikin/CmapCoverage.cpp
index 6431000..9f3447e 100644
--- a/libs/minikin/CmapCoverage.cpp
+++ b/libs/minikin/CmapCoverage.cpp
@@ -49,7 +49,7 @@ static void addRange(vector<uint32_t> &coverage, uint32_t start, uint32_t end) {
}
}
-// Get the coverage information out of a Format 12 subtable, storing it in the coverage vector
+// Get the coverage information out of a Format 4 subtable, storing it in the coverage vector
static bool getCoverageFormat4(vector<uint32_t>& coverage, const uint8_t* data, size_t size) {
const size_t kSegCountOffset = 6;
const size_t kEndCountOffset = 14;
@@ -63,29 +63,33 @@ static bool getCoverageFormat4(vector<uint32_t>& coverage, const uint8_t* data,
return false;
}
for (size_t i = 0; i < segCount; i++) {
- int end = readU16(data, kEndCountOffset + 2 * i);
- int start = readU16(data, kHeaderSize + 2 * (segCount + i));
- int rangeOffset = readU16(data, kHeaderSize + 2 * (3 * segCount + i));
+ uint32_t end = readU16(data, kEndCountOffset + 2 * i);
+ uint32_t start = readU16(data, kHeaderSize + 2 * (segCount + i));
+ if (end < start) {
+ // invalid segment range: size must be positive
+ return false;
+ }
+ uint32_t rangeOffset = readU16(data, kHeaderSize + 2 * (3 * segCount + i));
if (rangeOffset == 0) {
- int delta = readU16(data, kHeaderSize + 2 * (2 * segCount + i));
+ uint32_t delta = readU16(data, kHeaderSize + 2 * (2 * segCount + i));
if (((end + delta) & 0xffff) > end - start) {
addRange(coverage, start, end + 1);
} else {
- for (int j = start; j < end + 1; j++) {
+ for (uint32_t j = start; j < end + 1; j++) {
if (((j + delta) & 0xffff) != 0) {
addRange(coverage, j, j + 1);
}
}
}
} else {
- for (int j = start; j < end + 1; j++) {
+ for (uint32_t j = start; j < end + 1; j++) {
uint32_t actualRangeOffset = kHeaderSize + 6 * segCount + rangeOffset +
(i + j - start) * 2;
if (actualRangeOffset + 2 > size) {
// invalid rangeOffset is considered a "warning" by OpenType Sanitizer
continue;
}
- int glyphId = readU16(data, actualRangeOffset);
+ uint32_t glyphId = readU16(data, actualRangeOffset);
if (glyphId != 0) {
addRange(coverage, j, j + 1);
}
@@ -115,6 +119,10 @@ static bool getCoverageFormat12(vector<uint32_t>& coverage, const uint8_t* data,
uint32_t groupOffset = kFirstGroupOffset + i * kGroupSize;
uint32_t start = readU32(data, groupOffset + kStartCharCodeOffset);
uint32_t end = readU32(data, groupOffset + kEndCharCodeOffset);
+ if (end < start) {
+ // invalid group range: size must be positive
+ return false;
+ }
addRange(coverage, start, end + 1); // file is inclusive, vector is exclusive
}
return true;
@@ -128,18 +136,19 @@ bool CmapCoverage::getCoverage(SparseBitSet& coverage, const uint8_t* cmap_data,
const size_t kPlatformIdOffset = 0;
const size_t kEncodingIdOffset = 2;
const size_t kOffsetOffset = 4;
- const int kMicrosoftPlatformId = 3;
- const int kUnicodeBmpEncodingId = 1;
- const int kUnicodeUcs4EncodingId = 10;
+ const uint16_t kMicrosoftPlatformId = 3;
+ const uint16_t kUnicodeBmpEncodingId = 1;
+ const uint16_t kUnicodeUcs4EncodingId = 10;
+ const uint32_t kNoTable = UINT32_MAX;
if (kHeaderSize > cmap_size) {
return false;
}
- int numTables = readU16(cmap_data, kNumTablesOffset);
+ uint32_t numTables = readU16(cmap_data, kNumTablesOffset);
if (kHeaderSize + numTables * kTableSize > cmap_size) {
return false;
}
- int bestTable = -1;
- for (int i = 0; i < numTables; i++) {
+ uint32_t bestTable = kNoTable;
+ for (uint32_t i = 0; i < numTables; i++) {
uint16_t platformId = readU16(cmap_data, kHeaderSize + i * kTableSize + kPlatformIdOffset);
uint16_t encodingId = readU16(cmap_data, kHeaderSize + i * kTableSize + kEncodingIdOffset);
if (platformId == kMicrosoftPlatformId && encodingId == kUnicodeUcs4EncodingId) {
@@ -152,11 +161,11 @@ bool CmapCoverage::getCoverage(SparseBitSet& coverage, const uint8_t* cmap_data,
#ifdef VERBOSE_DEBUG
ALOGD("best table = %d\n", bestTable);
#endif
- if (bestTable < 0) {
+ if (bestTable == kNoTable) {
return false;
}
uint32_t offset = readU32(cmap_data, kHeaderSize + bestTable * kTableSize + kOffsetOffset);
- if (offset + 2 > cmap_size) {
+ if (offset > cmap_size - 2) {
return false;
}
uint16_t format = readU16(cmap_data, offset);
diff --git a/libs/minikin/SparseBitSet.cpp b/libs/minikin/SparseBitSet.cpp
index 7acb7ba..2265ff2 100644
--- a/libs/minikin/SparseBitSet.cpp
+++ b/libs/minikin/SparseBitSet.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <cutils/log.h>
#include <stddef.h>
#include <string.h>
#include <minikin/SparseBitSet.h>
@@ -71,6 +72,7 @@ void SparseBitSet::initFromRanges(const uint32_t* ranges, size_t nRanges) {
for (size_t i = 0; i < nRanges; i++) {
uint32_t start = ranges[i * 2];
uint32_t end = ranges[i * 2 + 1];
+ LOG_ALWAYS_FATAL_IF(end < start); // make sure range size is nonnegative
uint32_t startPage = start >> kLogValuesPerPage;
uint32_t endPage = (end - 1) >> kLogValuesPerPage;
if (startPage >= nonzeroPageEnd) {