Import legacy bugfixes found over time

- Fix mishandling empty microcode entries
- Fix mishandling TE image base
- Fix Intel legacy LZMA support
This commit is contained in:
vit9696 2019-11-27 19:46:16 +03:00
parent f2e343d8bf
commit 1b2ea8c276
5 changed files with 54 additions and 66 deletions

View File

@ -125,14 +125,14 @@ typedef ptrdiff_t INTN;
#define EFI_ERROR(X) (X) #define EFI_ERROR(X) (X)
// Compression algorithms // Compression algorithms
#define COMPRESSION_ALGORITHM_UNKNOWN 0 #define COMPRESSION_ALGORITHM_UNKNOWN 0
#define COMPRESSION_ALGORITHM_NONE 1 #define COMPRESSION_ALGORITHM_NONE 1
#define COMPRESSION_ALGORITHM_EFI11 2 #define COMPRESSION_ALGORITHM_EFI11 2
#define COMPRESSION_ALGORITHM_TIANO 3 #define COMPRESSION_ALGORITHM_TIANO 3
#define COMPRESSION_ALGORITHM_UNDECIDED 4 #define COMPRESSION_ALGORITHM_UNDECIDED 4
#define COMPRESSION_ALGORITHM_LZMA 5 #define COMPRESSION_ALGORITHM_LZMA 5
#define COMPRESSION_ALGORITHM_IMLZMA 6 #define COMPRESSION_ALGORITHM_LZMA_INTEL_LEGACY 6
#define COMPRESSION_ALGORITHM_GZIP 7 #define COMPRESSION_ALGORITHM_GZIP 7
// Item create modes // Item create modes
#define CREATE_MODE_APPEND 0 #define CREATE_MODE_APPEND 0

View File

@ -1312,11 +1312,14 @@ USTATUS FfsParser::findNextRawAreaItem(const UModelIndex & index, const UINT32 l
// Check microcode header candidate // Check microcode header candidate
const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)currentPos; const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)currentPos;
if (FALSE == microcodeHeaderValid(ucodeHeader)) { if (FALSE == microcodeHeaderValid(ucodeHeader)) {
continue; continue;
} }
// Check size candidate
if (ucodeHeader->TotalSize == 0)
continue;
// All checks passed, microcode found // All checks passed, microcode found
nextItemType = Types::Microcode; nextItemType = Types::Microcode;
nextItemSize = ucodeHeader->TotalSize; nextItemSize = ucodeHeader->TotalSize;
@ -1399,8 +1402,9 @@ USTATUS FfsParser::findNextRawAreaItem(const UModelIndex & index, const UINT32 l
} }
// No more stores found // No more stores found
if (offset >= dataSize - sizeof(UINT32)) if (offset >= dataSize - sizeof(UINT32)) {
return U_STORES_NOT_FOUND; return U_STORES_NOT_FOUND;
}
return U_SUCCESS; return U_SUCCESS;
} }
@ -2683,7 +2687,7 @@ USTATUS FfsParser::parseCompressedSectionBody(const UModelIndex & index)
// Add info // Add info
model->addInfo(index, UString("\nCompression algorithm: ") + compressionTypeToUString(algorithm)); model->addInfo(index, UString("\nCompression algorithm: ") + compressionTypeToUString(algorithm));
if (algorithm == COMPRESSION_ALGORITHM_LZMA || algorithm == COMPRESSION_ALGORITHM_IMLZMA) { if (algorithm == COMPRESSION_ALGORITHM_LZMA || algorithm == COMPRESSION_ALGORITHM_LZMA_INTEL_LEGACY) {
model->addInfo(index, usprintf("\nLZMA dictionary size: %Xh", dictionarySize)); model->addInfo(index, usprintf("\nLZMA dictionary size: %Xh", dictionarySize));
} }
@ -3146,7 +3150,7 @@ USTATUS FfsParser::parseTeImageSectionBody(const UModelIndex & index)
// Update parsing data // Update parsing data
TE_IMAGE_SECTION_PARSING_DATA pdata; TE_IMAGE_SECTION_PARSING_DATA pdata;
pdata.imageBaseType = EFI_IMAGE_TE_BASE_OTHER; // Will be determined later pdata.imageBaseType = EFI_IMAGE_TE_BASE_OTHER; // Will be determined later
pdata.imageBase = (UINT32)teHeader->ImageBase; pdata.originalImageBase = (UINT32)teHeader->ImageBase;
pdata.adjustedImageBase = (UINT32)(teHeader->ImageBase + teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER)); pdata.adjustedImageBase = (UINT32)(teHeader->ImageBase + teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER));
model->setParsingData(index, UByteArray((const char*)&pdata, sizeof(pdata))); model->setParsingData(index, UByteArray((const char*)&pdata, sizeof(pdata)));
@ -3236,16 +3240,16 @@ USTATUS FfsParser::checkTeImageBase(const UModelIndex & index)
if (model->hasEmptyParsingData(index) == false) { if (model->hasEmptyParsingData(index) == false) {
UByteArray data = model->parsingData(index); UByteArray data = model->parsingData(index);
const TE_IMAGE_SECTION_PARSING_DATA* pdata = (const TE_IMAGE_SECTION_PARSING_DATA*)data.constData(); const TE_IMAGE_SECTION_PARSING_DATA* pdata = (const TE_IMAGE_SECTION_PARSING_DATA*)data.constData();
originalImageBase = readUnaligned(pdata).imageBase; originalImageBase = readUnaligned(pdata).originalImageBase;
adjustedImageBase = readUnaligned(pdata).adjustedImageBase; adjustedImageBase = readUnaligned(pdata).adjustedImageBase;
} }
if (imageBase != 0) { if (originalImageBase != 0 || adjustedImageBase != 0) {
// Check data memory address to be equal to either ImageBase or AdjustedImageBase // Check data memory address to be equal to either OriginalImageBase or AdjustedImageBase
UINT64 address = addressDiff + model->base(index); UINT64 address = addressDiff + model->base(index);
UINT32 base = (UINT32)address + model->header(index).size(); UINT32 base = (UINT32)address + model->header(index).size();
if (imageBase == base) { if (originalImageBase == base) {
imageBaseType = EFI_IMAGE_TE_BASE_ORIGINAL; imageBaseType = EFI_IMAGE_TE_BASE_ORIGINAL;
} }
else if (adjustedImageBase == base) { else if (adjustedImageBase == base) {
@ -3253,7 +3257,7 @@ USTATUS FfsParser::checkTeImageBase(const UModelIndex & index)
} }
else { else {
// Check for one-bit difference // Check for one-bit difference
UINT32 xored = base ^ imageBase; // XOR result can't be zero UINT32 xored = base ^ originalImageBase; // XOR result can't be zero
if ((xored & (xored - 1)) == 0) { // Check that XOR result is a power of 2, i.e. has exactly one bit set if ((xored & (xored - 1)) == 0) { // Check that XOR result is a power of 2, i.e. has exactly one bit set
imageBaseType = EFI_IMAGE_TE_BASE_ORIGINAL; imageBaseType = EFI_IMAGE_TE_BASE_ORIGINAL;
} }
@ -3266,13 +3270,14 @@ USTATUS FfsParser::checkTeImageBase(const UModelIndex & index)
} }
// Show message if imageBaseType is still unknown // Show message if imageBaseType is still unknown
if (imageBaseType == EFI_IMAGE_TE_BASE_OTHER) if (imageBaseType == EFI_IMAGE_TE_BASE_OTHER) {
msg(usprintf("%s: TE image base is neither zero, nor original, nor adjusted, nor top-swapped", __FUNCTION__), index); msg(usprintf("%s: TE image base is neither zero, nor original, nor adjusted, nor top-swapped", __FUNCTION__), index);
}
// Update parsing data // Update parsing data
TE_IMAGE_SECTION_PARSING_DATA pdata; TE_IMAGE_SECTION_PARSING_DATA pdata;
pdata.imageBaseType = imageBaseType; pdata.imageBaseType = imageBaseType;
pdata.imageBase = originalImageBase; pdata.originalImageBase = originalImageBase;
pdata.adjustedImageBase = adjustedImageBase; pdata.adjustedImageBase = adjustedImageBase;
model->setParsingData(index, UByteArray((const char*)&pdata, sizeof(pdata))); model->setParsingData(index, UByteArray((const char*)&pdata, sizeof(pdata)));
} }

View File

@ -54,7 +54,7 @@ typedef struct COMPRESSED_SECTION_PARSING_DATA_ {
} COMPRESSED_SECTION_PARSING_DATA; } COMPRESSED_SECTION_PARSING_DATA;
typedef struct TE_IMAGE_SECTION_PARSING_DATA_ { typedef struct TE_IMAGE_SECTION_PARSING_DATA_ {
UINT32 imageBase; UINT32 originalImageBase;
UINT32 adjustedImageBase; UINT32 adjustedImageBase;
UINT8 imageBaseType; UINT8 imageBaseType;
} TE_IMAGE_SECTION_PARSING_DATA; } TE_IMAGE_SECTION_PARSING_DATA;

View File

@ -174,12 +174,12 @@ UString itemSubtypeToUString(const UINT8 type, const UINT8 subtype)
UString compressionTypeToUString(const UINT8 algorithm) UString compressionTypeToUString(const UINT8 algorithm)
{ {
switch (algorithm) { switch (algorithm) {
case COMPRESSION_ALGORITHM_NONE: return UString("None"); case COMPRESSION_ALGORITHM_NONE: return UString("None");
case COMPRESSION_ALGORITHM_EFI11: return UString("EFI 1.1"); case COMPRESSION_ALGORITHM_EFI11: return UString("EFI 1.1");
case COMPRESSION_ALGORITHM_TIANO: return UString("Tiano"); case COMPRESSION_ALGORITHM_TIANO: return UString("Tiano");
case COMPRESSION_ALGORITHM_UNDECIDED: return UString("Undecided Tiano/EFI 1.1"); case COMPRESSION_ALGORITHM_UNDECIDED: return UString("Undecided Tiano/EFI 1.1");
case COMPRESSION_ALGORITHM_LZMA: return UString("LZMA"); case COMPRESSION_ALGORITHM_LZMA: return UString("LZMA");
case COMPRESSION_ALGORITHM_IMLZMA: return UString("Intel LZMA"); case COMPRESSION_ALGORITHM_LZMA_INTEL_LEGACY: return UString("Intel legacy LZMA");
} }
return UString("Unknown"); return UString("Unknown");

View File

@ -235,56 +235,39 @@ USTATUS decompress(const UByteArray & compressedData, const UINT8 compressionTyp
data = (const UINT8*)compressedData.constData(); data = (const UINT8*)compressedData.constData();
dataSize = compressedData.size(); dataSize = compressedData.size();
// Get info // Get info as normal LZMA section
if (U_SUCCESS != LzmaGetInfo(data, dataSize, &decompressedSize)) if (U_SUCCESS != LzmaGetInfo(data, dataSize, &decompressedSize)) {
return U_CUSTOMIZED_DECOMPRESSION_FAILED; // Get info as Intel legacy LZMA section
data += sizeof(UINT32);
if (U_SUCCESS != LzmaGetInfo(data, dataSize, &decompressedSize)) {
return U_CUSTOMIZED_DECOMPRESSION_FAILED;
}
else {
algorithm = COMPRESSION_ALGORITHM_LZMA_INTEL_LEGACY;
}
}
else {
algorithm = COMPRESSION_ALGORITHM_LZMA;
}
// Allocate memory // Allocate memory
decompressed = (UINT8*)malloc(decompressedSize); decompressed = (UINT8*)malloc(decompressedSize);
if (!decompressed) { if (!decompressed) {
return U_STANDARD_DECOMPRESSION_FAILED; return U_OUT_OF_MEMORY;
} }
// Decompress section data // Decompress section data
if (U_SUCCESS != LzmaDecompress(data, dataSize, decompressed)) { if (U_SUCCESS != LzmaDecompress(data, dataSize, decompressed)) {
// Intel modified LZMA workaround return U_CUSTOMIZED_DECOMPRESSION_FAILED;
// Decompress section data once again
// VERIFY: might be wrong assumption, 0.2x had a different code here
// See: https://github.com/LongSoft/UEFITool/blob/4bee991c949b458739ffa96b88dbc589192c7689/ffsengine.cpp#L2814-L2823
data += sizeof(UINT32);
// Get info again
if (U_SUCCESS != LzmaGetInfo(data, dataSize, &decompressedSize)) {
free(decompressed);
return U_CUSTOMIZED_DECOMPRESSION_FAILED;
}
// Decompress section data again
if (U_SUCCESS != LzmaDecompress(data, dataSize, decompressed)) {
free(decompressed);
return U_CUSTOMIZED_DECOMPRESSION_FAILED;
}
else {
if (decompressedSize > INT32_MAX) {
free(decompressed);
return U_CUSTOMIZED_DECOMPRESSION_FAILED;
}
algorithm = COMPRESSION_ALGORITHM_IMLZMA;
dictionarySize = readUnaligned((UINT32*)(data + 1)); // LZMA dictionary size is stored in bytes 1-4 of LZMA properties header
decompressedData = UByteArray((const char*)decompressed, (int)decompressedSize);
}
}
else {
if (decompressedSize > INT32_MAX) {
free(decompressed);
return U_CUSTOMIZED_DECOMPRESSION_FAILED;
}
algorithm = COMPRESSION_ALGORITHM_LZMA;
dictionarySize = readUnaligned((UINT32*)(data + 1)); // LZMA dictionary size is stored in bytes 1-4 of LZMA properties header
decompressedData = UByteArray((const char*)decompressed, (int)decompressedSize);
} }
if (decompressedSize > INT32_MAX) {
free(decompressed);
return U_CUSTOMIZED_DECOMPRESSION_FAILED;
}
dictionarySize = readUnaligned((UINT32*)(data + 1)); // LZMA dictionary size is stored in bytes 1-4 of LZMA properties header
decompressedData = UByteArray((const char*)decompressed, (int)decompressedSize);
free(decompressed); free(decompressed);
return U_SUCCESS; return U_SUCCESS;
default: default: