summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaph Levien <raph@google.com>2016-01-06 14:31:23 -0800
committerRaph Levien <raph@google.com>2016-01-07 21:39:25 +0000
commitca8ac8acdad662230ae37998c6c4091bb39402b6 (patch)
treef2142f959da7f25a1c70efcfea0db2a853d194bf
parent6299a6ba13906c695f7a4f6748f7bc5856a110e5 (diff)
downloadandroid_frameworks_minikin-ca8ac8acdad662230ae37998c6c4091bb39402b6.tar.gz
android_frameworks_minikin-ca8ac8acdad662230ae37998c6c4091bb39402b6.tar.bz2
android_frameworks_minikin-ca8ac8acdad662230ae37998c6c4091bb39402b6.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 8be45d1..4c9643a 100644
--- a/libs/minikin/CmapCoverage.cpp
+++ b/libs/minikin/CmapCoverage.cpp
@@ -50,7 +50,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;
@@ -64,28 +64,32 @@ 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) {
return false;
}
- 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 PRINTF_DEBUG
printf("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) {