# HG changeset patch # User smatz # Date 1266017984 0 # Node ID e038fae3f7f0a17e1b5eb3d07e6025e397c0ae56 # Parent b568841a8e39657c1c74a4e1ffab4adf05275f97 (svn r19112) -Fix [FS#3611]: don't crash on broken lng file diff --git a/src/strings.cpp b/src/strings.cpp --- a/src/strings.cpp +++ b/src/strings.cpp @@ -1239,15 +1239,16 @@ bool ReadLanguagePack(int lang_index) { - int tot_count, i; + /* Current language pack */ size_t len; - char **langpack_offs; - char *s; + LanguagePack *lang_pack = (LanguagePack *)ReadFileToMem(_dynlang.ent[lang_index].file, &len, 200000); + if (lang_pack == NULL) return false; - LanguagePack *lang_pack = (LanguagePack*)ReadFileToMem(_dynlang.ent[lang_index].file, &len, 200000); + /* End of read data (+ terminating zero added in ReadFileToMem()) */ + const char *end = (char *)lang_pack + len + 1; - if (lang_pack == NULL) return false; - if (len < sizeof(LanguagePack) || + /* We need at least one byte of lang_pack->data */ + if (end <= lang_pack->data || lang_pack->ident != TO_LE32(LANGUAGE_PACK_IDENT) || lang_pack->version != TO_LE32(LANGUAGE_PACK_VERSION)) { free(lang_pack); @@ -1255,30 +1256,43 @@ } #if TTD_ENDIAN == TTD_BIG_ENDIAN - for (i = 0; i != 32; i++) { + for (uint i = 0; i < 32; i++) { lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]); } #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */ - tot_count = 0; - for (i = 0; i != 32; i++) { + uint count = 0; + for (uint i = 0; i < 32; i++) { uint num = lang_pack->offsets[i]; - _langtab_start[i] = tot_count; + _langtab_start[i] = count; _langtab_num[i] = num; - tot_count += num; + count += num; } /* Allocate offsets */ - langpack_offs = MallocT(tot_count); + char **langpack_offs = MallocT(count); /* Fill offsets */ - s = lang_pack->data; - for (i = 0; i != tot_count; i++) { - len = (byte)*s; - *s++ = '\0'; // zero terminate the string before. - if (len >= 0xC0) len = ((len & 0x3F) << 8) + (byte)*s++; + char *s = lang_pack->data; + len = (byte)*s++; + for (uint i = 0; i < count; i++) { + if (s + len >= end) { + free(lang_pack); + free(langpack_offs); + return false; + } + if (len >= 0xC0) { + len = ((len & 0x3F) << 8) + (byte)*s++; + if (s + len >= end) { + free(lang_pack); + free(langpack_offs); + return false; + } + } langpack_offs[i] = s; s += len; + len = (byte)*s; + *s++ = '\0'; // zero terminate the string } free(_langpack);