diff --git a/modules/commodetto/cfeBMF.c b/modules/commodetto/cfeBMF.c index 7fead08a6..29d92846f 100644 --- a/modules/commodetto/cfeBMF.c +++ b/modules/commodetto/cfeBMF.c @@ -77,22 +77,20 @@ void CFELockCache(CommodettoFontEngine bmf, uint8_t lock) void CFESetFontData(CommodettoFontEngine bmf, const void *fontData, uint32_t fontDataSize) { - const unsigned char *bytes, *start; - uint32_t size; - uint8_t version; - if (fontData == bmf->fontData) return; // unchanged bmf->charCount = 0; // zero in case of failure + if (fontDataSize < 5) + return; - start = fontData; - bytes = start; + const unsigned char *start = fontData; + const unsigned char *bytes = start; + const unsigned char *end = start + fontDataSize; - version = c_read8(bytes + 3); + uint8_t version = c_read8(bytes + 3); if ((0x42 != c_read8(bytes + 0)) || (0x4D != c_read8(bytes + 1)) || (0x46 != c_read8(bytes + 2)) || ((3 != version) && (4 != version))) return; - bmf->isCompressed = 4 == version; bytes += 4; @@ -102,52 +100,58 @@ void CFESetFontData(CommodettoFontEngine bmf, const void *fontData, uint32_t fon return; bytes += 1; - bytes += 4 + c_read32(bytes); + if ((end - bytes) < 4) + return; + uint32_t size = c_read32(bytes); + if (size > (uint32_t)((end - bytes) - 4)) + return; + bytes += 4 + size; // get lineHeight from block 2 - if (2 != c_read8(bytes)) + if (((end - bytes) < 5) || (2 != c_read8(bytes))) return; bytes += 1; size = c_read32(bytes); bytes += 4; + if (((end - bytes) < 10) || (size < 8) || (size > (uint32_t)(end - bytes))) + return; bmf->height = c_read16(bytes); - bytes += 2; - - bmf->ascent = c_read16(bytes); - bytes += 2; - - bytes += 2 + 2; // scaleW and scaleH - if (1 != c_read16(bytes)) // pages + bmf->ascent = c_read16(bytes + 2); + if (1 != c_read16(bytes + 8)) // pages return; - bytes += size - 8; + bytes += size; // skip block 3 - if (3 != c_read8(bytes)) + if (((end - bytes) < 5) || (3 != c_read8(bytes))) return; bytes += 1; - bytes += 4 + c_read32(bytes); + size = c_read32(bytes); + if (size > (uint32_t)((end - bytes) - 4)) + return; + bytes += 4 + size; // use block 4 - if (4 != c_read8(bytes)) + if (((end - bytes) < 1) || (4 != c_read8(bytes))) return; bytes += 1; - bmf->charTable = bytes + 4; - bmf->isContinuous = (0x40 & c_read8(19 + bmf->charTable)) ? 1 : 0; - + if ((end - bytes) < 4) + return; size = c_read32(bytes); - if (size % 20) + if ((size % 20) || (size < 20) || (size > (uint32_t)((end - bytes) - 4))) return; + bmf->charTable = bytes + 4; + bmf->isContinuous = (0x40 & c_read8(19 + bmf->charTable)) ? 1 : 0; bmf->charCount = size / 20; #if MODDEF_CFE_KERN // block 5 - kerning bytes += 4 + size; - if (5 == c_read8(bytes)) { + if (((end - bytes) >= 11) && (5 == c_read8(bytes))) { bytes += 1; bmf->kernCount = c_read32(bytes) / 10; bmf->kernTriples = bytes + 4; diff --git a/modules/commodetto/commodettoParseBMF.c b/modules/commodetto/commodettoParseBMF.c index a3ce15e07..4d3962c09 100644 --- a/modules/commodetto/commodettoParseBMF.c +++ b/modules/commodetto/commodettoParseBMF.c @@ -24,18 +24,18 @@ #include "xsmc.h" #include "mc.xs.h" // for xsID_ values -//@@ can read beyond end of provided buffer on malformed data void xs_parseBMF(xsMachine *the) { - unsigned char *bytes, *start; + unsigned char *bytes, *start, *end; uint32_t size; xsUnsignedValue byteLength; int charCount; xsmcGetBufferReadable(xsArg(0), (void **)&bytes, &byteLength); start = bytes; + end = bytes + byteLength; - if ((0x42 != c_read8(bytes + 0)) || (0x4D != c_read8(bytes + 1)) || (0x46 != c_read8(bytes + 2)) || ((3 != c_read8(bytes + 3)) && (4 != c_read8(bytes + 3)))) + if ((byteLength < 5) || (0x42 != c_read8(bytes + 0)) || (0x4D != c_read8(bytes + 1)) || (0x46 != c_read8(bytes + 2)) || ((3 != c_read8(bytes + 3)) && (4 != c_read8(bytes + 3)))) xsUnknownError("Invalid BMF header"); bytes += 4; @@ -44,15 +44,24 @@ void xs_parseBMF(xsMachine *the) xsUnknownError("can't find info block"); bytes += 1; - bytes += 4 + c_read32(bytes); + if ((end - bytes) < 4) + xsUnknownError("truncated BMF"); + size = c_read32(bytes); + if (size > (uint32_t)((end - bytes) - 4)) + xsUnknownError("truncated BMF"); + bytes += 4 + size; // get lineHeight from block 2 - if (2 != c_read8(bytes)) + if (((end - bytes) < 1) || (2 != c_read8(bytes))) xsUnknownError("can't find common block"); bytes += 1; + if ((end - bytes) < 4) + xsUnknownError("truncated BMF"); size = c_read32(bytes); bytes += 4; + if (((end - bytes) < 10) || (size < 8) || (size > (uint32_t)(end - bytes))) + xsUnknownError("truncated BMF"); xsmcSetInteger(xsResult, c_read16(bytes)); bytes += 2; @@ -69,22 +78,29 @@ void xs_parseBMF(xsMachine *the) bytes += size - 8; // skip block 3 - if (3 != c_read8(bytes)) + if (((end - bytes) < 1) || (3 != c_read8(bytes))) xsUnknownError("can't find pages block"); bytes += 1; - bytes += 4 + c_read32(bytes); + if ((end - bytes) < 4) + xsUnknownError("truncated BMF"); + size = c_read32(bytes); + if (size > (uint32_t)((end - bytes) - 4)) + xsUnknownError("truncated BMF"); + bytes += 4 + size; // use block 4 - if (4 != c_read8(bytes)) + if (((end - bytes) < 1) || (4 != c_read8(bytes))) xsUnknownError("can't find chars block"); bytes += 1; xsmcSetInteger(xsResult, bytes - start); xsmcDefine(xsArg(0), xsID_position, xsResult, xsDontDelete | xsDontSet); + if ((end - bytes) < 4) + xsUnknownError("truncated BMF"); size = c_read32(bytes); - if (size % 20) + if ((size % 20) || (size > (uint32_t)((end - bytes) - 4))) xsUnknownError("bad chars block size"); charCount = size / 20;