From c9939e23ec7c758166ed020f5e410a67e846dc0c Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Tue, 31 Jan 2023 20:15:12 -0800 Subject: [PATCH] Fix possible unaligned access to UCS2 strings --- UEFITool/ffsfinder.cpp | 18 +++++--------- UEFITool/uefitool.cpp | 3 --- common/bstrlib/bstrwrap.h | 10 -------- common/ffsparser.cpp | 14 +++-------- common/nvramparser.cpp | 49 +++++++++++++++------------------------ common/ustring.cpp | 18 ++++++++++++++ common/ustring.h | 1 + 7 files changed, 47 insertions(+), 66 deletions(-) diff --git a/UEFITool/ffsfinder.cpp b/UEFITool/ffsfinder.cpp index ec3617b..94c236a 100644 --- a/UEFITool/ffsfinder.cpp +++ b/UEFITool/ffsfinder.cpp @@ -61,14 +61,12 @@ USTATUS FfsFinder::findHexPattern(const UModelIndex & index, const UByteArray & QRegularExpressionMatch regexpmatch; INT32 offset = 0; - while ((offset = (INT32)hexBody.indexOf(regexp, (qsizetype)offset, ®expmatch)) != -1) - { + while ((offset = (INT32)hexBody.indexOf(regexp, (qsizetype)offset, ®expmatch)) != -1) { #else - QRegExp regexp = QRegExp(UString(hexPattern), Qt::CaseInsensitive); - - INT32 offset = regexp.indexIn(hexBody); - - while (offset >= 0) { + QRegExp regexp = QRegExp(UString(hexPattern), Qt::CaseInsensitive); + + INT32 offset = regexp.indexIn(hexBody); + while (offset >= 0) { #endif if (offset % 2 == 0) { @@ -223,11 +221,7 @@ USTATUS FfsFinder::findHexPattern(const UModelIndex & index, const UByteArray & UString data; if (unicode) -#if QT_VERSION_MAJOR >= 6 - data = UString::fromUtf16((const char16_t*)body.constData(), (int)(body.length() / 2)); -#else - data = UString::fromUtf16((const ushort*)body.constData(), (int)(body.length() / 2)); -#endif + data = uFromUcs2(body.constData(), body.length() / 2); else data = UString::fromLatin1((const char*)body.constData(), body.length()); diff --git a/UEFITool/uefitool.cpp b/UEFITool/uefitool.cpp index 80524f1..a625bf9 100644 --- a/UEFITool/uefitool.cpp +++ b/UEFITool/uefitool.cpp @@ -807,7 +807,6 @@ void UEFITool::showParserMessages() #if QT_VERSION_MAJOR < 6 std::pair msg; - foreach (msg, messages) #else for (const auto &msg : messages) @@ -832,7 +831,6 @@ void UEFITool::showFinderMessages() #if QT_VERSION_MAJOR < 6 std::pair msg; - foreach (msg, messages) #else for (const auto &msg : messages) @@ -858,7 +856,6 @@ void UEFITool::showBuilderMessages() #if QT_VERSION_MAJOR < 6 std::pair msg; - foreach (msg, messages) #else for (const auto &msg : messages) diff --git a/common/bstrlib/bstrwrap.h b/common/bstrlib/bstrwrap.h index 7b99088..b8f628d 100644 --- a/common/bstrlib/bstrwrap.h +++ b/common/bstrlib/bstrwrap.h @@ -373,16 +373,6 @@ struct CBString : public tagbstring { CBString mid(int pos, int len) const { return midstr(pos, len); } CBString chopped(int len) const { return midstr(slen - len, len); } void chop(int len) { trunc(((slen > len) ? slen - len : 0)); } - static CBString fromUtf16(const unsigned short* str) { - // Naive implementation assuming that only ASCII LE part of UCS2 is used, str may not be aligned. - CBString msg; - const char *str8 = reinterpret_cast(str); - while (str8[0]) { - msg += str8[0]; - str8 += 2; - } - return msg; - } CBString leftJustified(int length) { if (length > slen) { return *this + CBString(' ', length - slen); } return *this; } }; extern const CBString operator + (const char *a, const CBString& b); diff --git a/common/ffsparser.cpp b/common/ffsparser.cpp index 9ec3ee0..610a345 100644 --- a/common/ffsparser.cpp +++ b/common/ffsparser.cpp @@ -1122,7 +1122,7 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc // Check attributes // Determine value of empty byte - UINT8 emptyByte = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? '\xFF' : '\x00'; + UINT8 emptyByte = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? 0xFF : 0x00; // Check for AppleCRC32 and UsedSpace in ZeroVector bool hasAppleCrc32 = false; @@ -2941,11 +2941,7 @@ USTATUS FfsParser::parseVersionSectionBody(const UModelIndex & index) return U_INVALID_PARAMETER; // Add info -#if QT_VERSION_MAJOR >= 6 - model->addInfo(index, UString("\nVersion string: ") + UString::fromUtf16((const char16_t*)model->body(index).constData())); -#else - model->addInfo(index, UString("\nVersion string: ") + UString::fromUtf16((const CHAR16*)model->body(index).constData())); -#endif + model->addInfo(index, UString("\nVersion string: ") + uFromUcs2(model->body(index).constData())); return U_SUCCESS; } @@ -3082,11 +3078,7 @@ USTATUS FfsParser::parseUiSectionBody(const UModelIndex & index) if (!index.isValid()) return U_INVALID_PARAMETER; -#if QT_VERSION_MAJOR >= 6 - UString text = UString::fromUtf16((const char16_t*)model->body(index).constData()); -#else - UString text = UString::fromUtf16((const CHAR16*)model->body(index).constData()); -#endif + UString text = uFromUcs2(model->body(index).constData()); // Add info model->addInfo(index, UString("\nText: ") + text); diff --git a/common/nvramparser.cpp b/common/nvramparser.cpp index f6d388a..404e2a2 100755 --- a/common/nvramparser.cpp +++ b/common/nvramparser.cpp @@ -258,12 +258,7 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) nameSize = (UINT32)(text.length() + 1); } else { // Name is stored as UCS2 string of CHAR16s -#if QT_VERSION_MAJOR >= 6 - text = UString::fromUtf16((char16_t*)namePtr); -#else - text = UString::fromUtf16((CHAR16*)namePtr); -#endif - + text = uFromUcs2(namePtr); nameSize = (UINT32)((text.length() + 1) * 2); } @@ -539,7 +534,9 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & UINT32 offset = storeOffset; for (; offset < dataSize - sizeof(UINT32); offset++) { const UINT32* currentPos = (const UINT32*)(volume.constData() + offset); - if (*currentPos == NVRAM_VSS_STORE_SIGNATURE || *currentPos == NVRAM_APPLE_SVS_STORE_SIGNATURE || *currentPos == NVRAM_APPLE_NSS_STORE_SIGNATURE) { // $VSS, $SVS or $NSS signatures found, perform checks + if (readUnaligned(currentPos) == NVRAM_VSS_STORE_SIGNATURE + || readUnaligned(currentPos) == NVRAM_APPLE_SVS_STORE_SIGNATURE + || readUnaligned(currentPos) == NVRAM_APPLE_NSS_STORE_SIGNATURE) { // $VSS, $SVS or $NSS signatures found, perform checks const VSS_VARIABLE_STORE_HEADER* vssHeader = (const VSS_VARIABLE_STORE_HEADER*)currentPos; if (vssHeader->Format != NVRAM_VSS_VARIABLE_STORE_FORMATTED) { msg(usprintf("%s: VSS store candidate at offset %Xh skipped, has invalid format %02Xh", __FUNCTION__, localOffset + offset, vssHeader->Format), index); @@ -552,7 +549,8 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & // All checks passed, store found break; } - else if (*currentPos == NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *currentPos == NVRAM_VSS2_STORE_GUID_PART1) { // VSS2 store signatures found, perform checks + else if (readUnaligned(currentPos) == NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID_PART1 + || readUnaligned(currentPos) == NVRAM_VSS2_STORE_GUID_PART1) { // VSS2 store signatures found, perform checks UByteArray guid = UByteArray(volume.constData() + offset, sizeof(EFI_GUID)); if (guid != NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID && guid != NVRAM_VSS2_STORE_GUID) // Check the whole signature continue; @@ -569,7 +567,7 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & // All checks passed, store found break; } - else if (*currentPos == NVRAM_FDC_VOLUME_SIGNATURE) { // FDC signature found + else if (readUnaligned(currentPos) == NVRAM_FDC_VOLUME_SIGNATURE) { // FDC signature found const FDC_VOLUME_HEADER* fdcHeader = (const FDC_VOLUME_HEADER*)currentPos; if (fdcHeader->Size == 0 || fdcHeader->Size == 0xFFFFFFFF) { msg(usprintf("%s: FDC store candidate at offset %Xh skipped, has invalid size %Xh", __FUNCTION__, localOffset + offset, fdcHeader->Size), index); @@ -578,7 +576,8 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & // All checks passed, store found break; } - else if (*currentPos == NVRAM_APPLE_FSYS_STORE_SIGNATURE || *currentPos == NVRAM_APPLE_GAID_STORE_SIGNATURE) { // Fsys or Gaid signature found + else if (readUnaligned(currentPos) == NVRAM_APPLE_FSYS_STORE_SIGNATURE + || readUnaligned(currentPos) == NVRAM_APPLE_GAID_STORE_SIGNATURE) { // Fsys or Gaid signature found const APPLE_FSYS_STORE_HEADER* fsysHeader = (const APPLE_FSYS_STORE_HEADER*)currentPos; if (fsysHeader->Size == 0 || fsysHeader->Size == 0xFFFF) { msg(usprintf("%s: Fsys store candidate at offset %Xh skipped, has invalid size %Xh", __FUNCTION__, localOffset + offset, fsysHeader->Size), index); @@ -587,7 +586,7 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & // All checks passed, store found break; } - else if (*currentPos == NVRAM_EVSA_STORE_SIGNATURE) { //EVSA signature found + else if (readUnaligned(currentPos) == NVRAM_EVSA_STORE_SIGNATURE) { //EVSA signature found if (offset < sizeof(UINT32)) continue; @@ -604,7 +603,8 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & offset -= sizeof(UINT32); break; } - else if (*currentPos == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 || *currentPos == EDKII_WORKING_BLOCK_SIGNATURE_GUID_DATA1) { // Possible FTW block signature found + else if (readUnaligned(currentPos) == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 + || readUnaligned(currentPos) == EDKII_WORKING_BLOCK_SIGNATURE_GUID_DATA1) { // Possible FTW block signature found UByteArray guid = UByteArray(volume.constData() + offset, sizeof(EFI_GUID)); if (guid != NVRAM_MAIN_STORE_VOLUME_GUID && guid != EDKII_WORKING_BLOCK_SIGNATURE_GUID && guid != VSS2_WORKING_BLOCK_SIGNATURE_GUID) // Check the whole signature continue; @@ -630,7 +630,7 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & // All checks passed, store found break; } - else if (*currentPos == NVRAM_PHOENIX_FLASH_MAP_SIGNATURE_PART1) {// Phoenix SCT flash map + else if (readUnaligned(currentPos) == NVRAM_PHOENIX_FLASH_MAP_SIGNATURE_PART1) {// Phoenix SCT flash map UByteArray signature = UByteArray(volume.constData() + offset, NVRAM_PHOENIX_FLASH_MAP_SIGNATURE_LENGTH); if (signature != NVRAM_PHOENIX_FLASH_MAP_SIGNATURE) // Check the whole signature continue; @@ -638,7 +638,7 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & // All checks passed, store found break; } - else if (*currentPos == NVRAM_PHOENIX_CMDB_HEADER_SIGNATURE) { // Phoenix SCT CMDB store + else if (readUnaligned(currentPos) == NVRAM_PHOENIX_CMDB_HEADER_SIGNATURE) { // Phoenix SCT CMDB store const PHOENIX_CMDB_HEADER* cmdbHeader = (const PHOENIX_CMDB_HEADER*)currentPos; // Check size @@ -648,7 +648,7 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & // All checks passed, store found break; } - else if (*currentPos == INTEL_MICROCODE_HEADER_VERSION_1) {// Intel microcode + else if (readUnaligned(currentPos) == INTEL_MICROCODE_HEADER_VERSION_1) {// Intel microcode const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)currentPos; // TotalSize is greater then DataSize and is multiple of 1024 @@ -659,7 +659,7 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & // All checks passed, store found break; } - else if (*currentPos == OEM_ACTIVATION_PUBKEY_MAGIC) { // SLIC pubkey + else if (readUnaligned(currentPos) == OEM_ACTIVATION_PUBKEY_MAGIC) { // SLIC pubkey if (offset < 4 * sizeof(UINT32)) continue; @@ -672,7 +672,7 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & offset -= 4 * sizeof(UINT32); break; } - else if (*currentPos == OEM_ACTIVATION_MARKER_WINDOWS_FLAG_PART1) { // SLIC marker + else if (readUnaligned(currentPos) == OEM_ACTIVATION_MARKER_WINDOWS_FLAG_PART1) { // SLIC marker if (offset < 26 || offset >= dataSize - sizeof(UINT64) || *(const UINT64*)currentPos != OEM_ACTIVATION_MARKER_WINDOWS_FLAG) // Check full windows flag and structure size @@ -1504,12 +1504,7 @@ USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignmen else { // Add GUID and text for valid variables name = guidToUString(readUnaligned(variableGuid)); info += UString("Variable GUID: ") + guidToUString(readUnaligned(variableGuid), false) + "\n"; - -#if QT_VERSION_MAJOR >= 6 - text = UString::fromUtf16((char16_t *)variableName); -#else - text = UString::fromUtf16(variableName); -#endif + text = uFromUcs2((const char*)variableName); } // Add info @@ -1741,13 +1736,7 @@ USTATUS NvramParser::parseEvsaStoreBody(const UModelIndex & index) const EVSA_NAME_ENTRY* nameHeader = (const EVSA_NAME_ENTRY*)entryHeader; header = data.mid(offset, sizeof(EVSA_NAME_ENTRY)); body = data.mid(offset + sizeof(EVSA_NAME_ENTRY), nameHeader->Header.Size - sizeof(EVSA_NAME_ENTRY)); - -#if QT_VERSION_MAJOR >= 6 - name = UString::fromUtf16((const char16_t *)body.constData()); -#else - name = UString::fromUtf16((const CHAR16*)body.constData()); -#endif - + name = uFromUcs2(body.constData()); info = UString("Name: ") + name + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %02Xh\nChecksum: %02Xh", variableSize, variableSize, diff --git a/common/ustring.cpp b/common/ustring.cpp index 9166fcf..1786a60 100644 --- a/common/ustring.cpp +++ b/common/ustring.cpp @@ -11,6 +11,8 @@ */ #include "ustring.h" +#include +#include #include #if defined(QT_CORE_LIB) @@ -104,3 +106,19 @@ UString urepeated(char c, int len) return UString(c, len); } #endif + +UString uFromUcs2(const char* str, size_t max_len) +{ + // Naive implementation assuming that only ASCII LE part of UCS2 is used, str may not be aligned. + UString msg; + const char *str8 = str; + size_t rest = (max_len == 0) ? SIZE_MAX : max_len; + if (max_len == 0) { + while (str8[0] && rest) { + msg += str8[0]; + str8 += 2; + rest--; + } + } + return msg; +} \ No newline at end of file diff --git a/common/ustring.h b/common/ustring.h index cdbcdf1..4100b13 100644 --- a/common/ustring.h +++ b/common/ustring.h @@ -29,5 +29,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. UString usprintf(const char* fmt, ...) ATTRIBUTE_FORMAT_(printf, 1, 2); UString urepeated(char c, int len); +UString uFromUcs2(const char* str, size_t max_len = 0); #endif // USTRING_H