Implement custom LZMA dictionary size for NE

This commit is contained in:
vit9696 2019-01-03 22:53:31 +03:00
parent f074dfc5ca
commit be2cdc7dfe
8 changed files with 124 additions and 104 deletions

View File

@ -64,7 +64,8 @@ LzmaCompress (
CONST UINT8 *Source, CONST UINT8 *Source,
UINT32 SourceSize, UINT32 SourceSize,
UINT8 *Destination, UINT8 *Destination,
UINT32 *DestinationSize UINT32 *DestinationSize,
UINT32 DictionarySize
) )
{ {
SRes LzmaResult; SRes LzmaResult;
@ -79,8 +80,7 @@ LzmaCompress (
} }
LzmaEncProps_Init(&props); LzmaEncProps_Init(&props);
// TODO: need to detect this instead of hardcoding props.dictSize = DictionarySize;
props.dictSize = LZMA_DICTIONARY_SIZE;
props.level = 9; props.level = 9;
props.fb = 273; props.fb = 273;

View File

@ -21,7 +21,7 @@
extern "C" { extern "C" {
#endif #endif
#define LZMA_DICTIONARY_SIZE 0x800000 #define DEFAULT_LZMA_DICTIONARY_SIZE 0x800000
#define _LZMA_SIZE_OPT #define _LZMA_SIZE_OPT
USTATUS USTATUS
@ -30,7 +30,8 @@ extern "C" {
const UINT8 *Source, const UINT8 *Source,
UINT32 SourceSize, UINT32 SourceSize,
UINT8 *Destination, UINT8 *Destination,
UINT32 *DestinationSize UINT32 *DestinationSize,
UINT32 DictionarySize
); );
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -45,31 +45,32 @@ typedef size_t USTATUS;
#define U_CUSTOMIZED_COMPRESSION_FAILED 23 #define U_CUSTOMIZED_COMPRESSION_FAILED 23
#define U_STANDARD_DECOMPRESSION_FAILED 24 #define U_STANDARD_DECOMPRESSION_FAILED 24
#define U_CUSTOMIZED_DECOMPRESSION_FAILED 25 #define U_CUSTOMIZED_DECOMPRESSION_FAILED 25
#define U_UNKNOWN_COMPRESSION_TYPE 26 #define U_GZIP_DECOMPRESSION_FAILED 26
#define U_DEPEX_PARSE_FAILED 27 #define U_UNKNOWN_COMPRESSION_TYPE 27
#define U_UNKNOWN_EXTRACT_MODE 28 #define U_DEPEX_PARSE_FAILED 28
#define U_UNKNOWN_REPLACE_MODE 29 #define U_UNKNOWN_EXTRACT_MODE 29
#define U_UNKNOWN_IMAGE_TYPE 30 #define U_UNKNOWN_REPLACE_MODE 30
#define U_UNKNOWN_PE_OPTIONAL_HEADER_TYPE 31 #define U_UNKNOWN_IMAGE_TYPE 31
#define U_UNKNOWN_RELOCATION_TYPE 32 #define U_UNKNOWN_PE_OPTIONAL_HEADER_TYPE 32
#define U_DIR_ALREADY_EXIST 33 #define U_UNKNOWN_RELOCATION_TYPE 33
#define U_DIR_CREATE 34 #define U_DIR_ALREADY_EXIST 34
#define U_DIR_CHANGE 35 #define U_DIR_CREATE 35
#define U_TRUNCATED_IMAGE 36 #define U_DIR_CHANGE 36
#define U_INVALID_CAPSULE 37 #define U_TRUNCATED_IMAGE 37
#define U_STORES_NOT_FOUND 38 #define U_INVALID_CAPSULE 38
#define U_INVALID_IMAGE 39 #define U_STORES_NOT_FOUND 39
#define U_INVALID_RAW_AREA 40 #define U_INVALID_IMAGE 40
#define U_INVALID_FIT 41 #define U_INVALID_RAW_AREA 41
#define U_INVALID_MICROCODE 42 #define U_INVALID_FIT 42
#define U_INVALID_ACM 43 #define U_INVALID_MICROCODE 43
#define U_INVALID_BG_KEY_MANIFEST 44 #define U_INVALID_ACM 44
#define U_INVALID_BG_BOOT_POLICY 45 #define U_INVALID_BG_KEY_MANIFEST 45
#define U_INVALID_TXT_CONF 46 #define U_INVALID_BG_BOOT_POLICY 46
#define U_ELEMENTS_NOT_FOUND 47 #define U_INVALID_TXT_CONF 47
#define U_ELEMENTS_NOT_FOUND 48
#define U_NOT_IMPLEMENTED 0xFF #define U_NOT_IMPLEMENTED 0xFF
// UDK porting definitions // EDK2 porting definitions
typedef uint8_t BOOLEAN; typedef uint8_t BOOLEAN;
typedef int8_t INT8; typedef int8_t INT8;
typedef uint8_t UINT8; typedef uint8_t UINT8;

View File

@ -1285,10 +1285,9 @@ USTATUS FfsParser::parseVolumeBody(const UModelIndex & index)
while (fileOffset < volumeBodySize) { while (fileOffset < volumeBodySize) {
UINT32 fileSize = getFileSize(volumeBody, fileOffset, ffsVersion); UINT32 fileSize = getFileSize(volumeBody, fileOffset, ffsVersion);
// Check file size
if (fileSize < sizeof(EFI_FFS_FILE_HEADER) || fileSize > volumeBodySize - fileOffset) {
// Check that we are at the empty space // Check that we are at the empty space
UByteArray header = volumeBody.mid(fileOffset, sizeof(EFI_FFS_FILE_HEADER)); UByteArray header = volumeBody.mid(fileOffset, std::min(sizeof(EFI_FFS_FILE_HEADER), (size_t)volumeBodySize - fileOffset));
if (header.count(emptyByte) == header.size()) { //Empty space if (header.count(emptyByte) == header.size()) { //Empty space
// Check volume usedSpace entry to be valid // Check volume usedSpace entry to be valid
if (usedSpace > 0 && usedSpace == fileOffset + volumeHeaderSize) { if (usedSpace > 0 && usedSpace == fileOffset + volumeHeaderSize) {
@ -1342,24 +1341,19 @@ USTATUS FfsParser::parseVolumeBody(const UModelIndex & index)
} }
break; // Exit from parsing loop break; // Exit from parsing loop
} }
else { //File space
// We aren't at the end of empty space
// Check that the remaining space can still have a file in it
if (volumeBodySize - fileOffset < sizeof(EFI_FFS_FILE_HEADER) || // Remaining space is smaller than the smallest possible file
volumeBodySize - fileOffset < fileSize) { // Remaining space is smaller than non-empty file size
// Parse non-UEFI data // Parse non-UEFI data
parseVolumeNonUefiData(volumeBody.mid(fileOffset), volumeHeaderSize + fileOffset, index); parseVolumeNonUefiData(volumeBody.mid(fileOffset), volumeHeaderSize + fileOffset, index);
break; // Exit from parsing loop break; // Exit from parsing loop
} }
}
// Get file header
UByteArray file = volumeBody.mid(fileOffset, fileSize);
UByteArray header = file.left(sizeof(EFI_FFS_FILE_HEADER));
const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)header.constData();
if (ffsVersion == 3 && (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)) {
header = file.left(sizeof(EFI_FFS_FILE_HEADER2));
}
// Parse current file's header // Parse current file's header
UModelIndex fileIndex; UModelIndex fileIndex;
USTATUS result = parseFileHeader(file, volumeHeaderSize + fileOffset, index, fileIndex); USTATUS result = parseFileHeader(volumeBody.mid(fileOffset, fileSize), volumeHeaderSize + fileOffset, index, fileIndex);
if (result) { if (result) {
msg(usprintf("%s: file header parsing failed with error ", __FUNCTION__) + errorCodeToUString(result), index); msg(usprintf("%s: file header parsing failed with error ", __FUNCTION__) + errorCodeToUString(result), index);
} }
@ -2462,9 +2456,10 @@ USTATUS FfsParser::parseCompressedSectionBody(const UModelIndex & index)
// Decompress section // Decompress section
UINT8 algorithm = COMPRESSION_ALGORITHM_NONE; UINT8 algorithm = COMPRESSION_ALGORITHM_NONE;
UINT32 dictionarySize = 0;
UByteArray decompressed; UByteArray decompressed;
UByteArray efiDecompressed; UByteArray efiDecompressed;
USTATUS result = decompress(model->body(index), compressionType, algorithm, decompressed, efiDecompressed); USTATUS result = decompress(model->body(index), compressionType, algorithm, dictionarySize, decompressed, efiDecompressed);
if (result) { if (result) {
msg(UString("parseCompressedSectionBody: decompression failed with error ") + errorCodeToUString(result), index); msg(UString("parseCompressedSectionBody: decompression failed with error ") + errorCodeToUString(result), index);
return U_SUCCESS; return U_SUCCESS;
@ -2497,10 +2492,14 @@ 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) {
model->addInfo(index, usprintf("\nLZMA dictionary size: %Xh", dictionarySize));
}
// Update parsing data // Update parsing data
COMPRESSED_SECTION_PARSING_DATA pdata; COMPRESSED_SECTION_PARSING_DATA pdata;
pdata.algorithm = algorithm; pdata.algorithm = algorithm;
pdata.dictionarySize = dictionarySize;
pdata.compressionType = compressionType; pdata.compressionType = compressionType;
pdata.uncompressedSize = uncompressedSize; pdata.uncompressedSize = uncompressedSize;
model->setParsingData(index, UByteArray((const char*)&pdata, sizeof(pdata))); model->setParsingData(index, UByteArray((const char*)&pdata, sizeof(pdata)));
@ -2532,10 +2531,11 @@ USTATUS FfsParser::parseGuidedSectionBody(const UModelIndex & index)
UString info; UString info;
bool parseCurrentSection = true; bool parseCurrentSection = true;
UINT8 algorithm = COMPRESSION_ALGORITHM_NONE; UINT8 algorithm = COMPRESSION_ALGORITHM_NONE;
UINT32 dictionarySize = 0;
UByteArray baGuid = UByteArray((const char*)&guid, sizeof(EFI_GUID)); UByteArray baGuid = UByteArray((const char*)&guid, sizeof(EFI_GUID));
// Tiano compressed section // Tiano compressed section
if (baGuid == EFI_GUIDED_SECTION_TIANO) { if (baGuid == EFI_GUIDED_SECTION_TIANO) {
USTATUS result = decompress(model->body(index), EFI_STANDARD_COMPRESSION, algorithm, processed, efiDecompressed); USTATUS result = decompress(model->body(index), EFI_STANDARD_COMPRESSION, algorithm, dictionarySize, processed, efiDecompressed);
if (result) { if (result) {
msg(usprintf("%s: decompression failed with error ", __FUNCTION__) + errorCodeToUString(result), index); msg(usprintf("%s: decompression failed with error ", __FUNCTION__) + errorCodeToUString(result), index);
return U_SUCCESS; return U_SUCCESS;
@ -2563,7 +2563,7 @@ USTATUS FfsParser::parseGuidedSectionBody(const UModelIndex & index)
} }
// LZMA compressed section // LZMA compressed section
else if (baGuid == EFI_GUIDED_SECTION_LZMA || baGuid == EFI_GUIDED_SECTION_LZMAF86) { else if (baGuid == EFI_GUIDED_SECTION_LZMA || baGuid == EFI_GUIDED_SECTION_LZMAF86) {
USTATUS result = decompress(model->body(index), EFI_CUSTOMIZED_COMPRESSION, algorithm, processed, efiDecompressed); USTATUS result = decompress(model->body(index), EFI_CUSTOMIZED_COMPRESSION, algorithm, dictionarySize, processed, efiDecompressed);
if (result) { if (result) {
msg(usprintf("%s: decompression failed with error ", __FUNCTION__) + errorCodeToUString(result), index); msg(usprintf("%s: decompression failed with error ", __FUNCTION__) + errorCodeToUString(result), index);
return U_SUCCESS; return U_SUCCESS;
@ -2572,6 +2572,7 @@ USTATUS FfsParser::parseGuidedSectionBody(const UModelIndex & index)
if (algorithm == COMPRESSION_ALGORITHM_LZMA) { if (algorithm == COMPRESSION_ALGORITHM_LZMA) {
info += UString("\nCompression algorithm: LZMA"); info += UString("\nCompression algorithm: LZMA");
info += usprintf("\nDecompressed size: %Xh (%u)", processed.size(), processed.size()); info += usprintf("\nDecompressed size: %Xh (%u)", processed.size(), processed.size());
info += usprintf("\nLZMA dictionary size: %Xh", dictionarySize);
} }
else { else {
info += UString("\nCompression algorithm: unknown"); info += UString("\nCompression algorithm: unknown");
@ -2597,6 +2598,11 @@ USTATUS FfsParser::parseGuidedSectionBody(const UModelIndex & index)
if (algorithm != COMPRESSION_ALGORITHM_NONE) if (algorithm != COMPRESSION_ALGORITHM_NONE)
model->setCompressed(index, true); model->setCompressed(index, true);
// Set parsing data
GUIDED_SECTION_PARSING_DATA pdata;
pdata.dictionarySize = dictionarySize;
model->setParsingData(index, UByteArray((const char*)&pdata, sizeof(pdata)));
if (!parseCurrentSection) { if (!parseCurrentSection) {
msg(usprintf("%s: GUID defined section can not be processed", __FUNCTION__), index); msg(usprintf("%s: GUID defined section can not be processed", __FUNCTION__), index);
return U_SUCCESS; return U_SUCCESS;

View File

@ -37,14 +37,20 @@ typedef struct FILE_PARSING_DATA_ {
EFI_GUID guid; EFI_GUID guid;
} FILE_PARSING_DATA; } FILE_PARSING_DATA;
typedef struct GUID_PARSING_DATA_ { typedef struct GUIDED_SECTION_PARSING_DATA_ {
EFI_GUID guid; EFI_GUID guid;
} GUIDED_SECTION_PARSING_DATA, FREEFORM_GUIDED_SECTION_PARSING_DATA; UINT32 dictionarySize;
} GUIDED_SECTION_PARSING_DATA;
typedef struct FREEFORM_GUIDED_SECTION_PARSING_DATA_ {
EFI_GUID guid;
} FREEFORM_GUIDED_SECTION_PARSING_DATA;
typedef struct COMPRESSED_SECTION_PARSING_DATA_ { typedef struct COMPRESSED_SECTION_PARSING_DATA_ {
UINT32 uncompressedSize; UINT32 uncompressedSize;
UINT8 compressionType; UINT8 compressionType;
UINT8 algorithm; UINT8 algorithm;
UINT32 dictionarySize;
} COMPRESSED_SECTION_PARSING_DATA; } COMPRESSED_SECTION_PARSING_DATA;
typedef struct TE_IMAGE_SECTION_PARSING_DATA_ { typedef struct TE_IMAGE_SECTION_PARSING_DATA_ {

View File

@ -296,11 +296,13 @@ void TreeModel::setFixed(const UModelIndex &index, const bool fixed)
return; return;
if (fixed) { if (fixed) {
// Special handling for uncompressed to compressed boundary
if (item->compressed() && item->parent()->compressed() == FALSE) { if (item->compressed() && item->parent()->compressed() == FALSE) {
item->setFixed(item->parent()->fixed()); item->setFixed(item->parent()->fixed());
return; return;
} }
// Propagate fixed flag until root
if (item->parent()->type() != Types::Root) if (item->parent()->type() != Types::Root)
item->parent()->setFixed(fixed); item->parent()->setFixed(fixed);
} }

View File

@ -136,7 +136,7 @@ UString errorCodeToUString(USTATUS errorCode)
} }
// Compression routines // Compression routines
USTATUS decompress(const UByteArray & compressedData, const UINT8 compressionType, UINT8 & algorithm, UByteArray & decompressedData, UByteArray & efiDecompressedData) USTATUS decompress(const UByteArray & compressedData, const UINT8 compressionType, UINT8 & algorithm, UINT32 & dictionarySize, UByteArray & decompressedData, UByteArray & efiDecompressedData)
{ {
const UINT8* data; const UINT8* data;
UINT32 dataSize; UINT32 dataSize;
@ -147,6 +147,9 @@ USTATUS decompress(const UByteArray & compressedData, const UINT8 compressionTyp
UINT32 scratchSize = 0; UINT32 scratchSize = 0;
const EFI_TIANO_HEADER* header; const EFI_TIANO_HEADER* header;
// For all but LZMA dictionary size is 0
dictionarySize = 0;
switch (compressionType) switch (compressionType)
{ {
case EFI_NOT_COMPRESSED: case EFI_NOT_COMPRESSED:
@ -189,13 +192,9 @@ USTATUS decompress(const UByteArray & compressedData, const UINT8 compressionTyp
USTATUS EfiResult = EfiDecompress(data, dataSize, efiDecompressed, decompressedSize, scratch, scratchSize); USTATUS EfiResult = EfiDecompress(data, dataSize, efiDecompressed, decompressedSize, scratch, scratchSize);
if (decompressedSize > INT32_MAX) { if (decompressedSize > INT32_MAX) {
free(decompressed); result = U_STANDARD_DECOMPRESSION_FAILED;
free(efiDecompressed);
free(scratch);
return U_STANDARD_DECOMPRESSION_FAILED;
} }
else if (EfiResult == U_SUCCESS && TianoResult == U_SUCCESS) { // Both decompressions are OK
if (EfiResult == U_SUCCESS && TianoResult == U_SUCCESS) { // Both decompressions are OK
algorithm = COMPRESSION_ALGORITHM_UNDECIDED; algorithm = COMPRESSION_ALGORITHM_UNDECIDED;
decompressedData = UByteArray((const char*)decompressed, (int)decompressedSize); decompressedData = UByteArray((const char*)decompressed, (int)decompressedSize);
efiDecompressedData = UByteArray((const char*)efiDecompressed, (int)decompressedSize); efiDecompressedData = UByteArray((const char*)efiDecompressed, (int)decompressedSize);
@ -239,6 +238,9 @@ USTATUS decompress(const UByteArray & compressedData, const UINT8 compressionTyp
if (U_SUCCESS != LzmaDecompress(data, dataSize, decompressed)) { if (U_SUCCESS != LzmaDecompress(data, dataSize, decompressed)) {
// Intel modified LZMA workaround // Intel modified LZMA workaround
// Decompress section data once again // 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); data += sizeof(UINT32);
// Get info again // Get info again
@ -258,6 +260,7 @@ USTATUS decompress(const UByteArray & compressedData, const UINT8 compressionTyp
return U_CUSTOMIZED_DECOMPRESSION_FAILED; return U_CUSTOMIZED_DECOMPRESSION_FAILED;
} }
algorithm = COMPRESSION_ALGORITHM_IMLZMA; 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); decompressedData = UByteArray((const char*)decompressed, (int)decompressedSize);
} }
} }
@ -267,6 +270,7 @@ USTATUS decompress(const UByteArray & compressedData, const UINT8 compressionTyp
return U_CUSTOMIZED_DECOMPRESSION_FAILED; return U_CUSTOMIZED_DECOMPRESSION_FAILED;
} }
algorithm = COMPRESSION_ALGORITHM_LZMA; 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); decompressedData = UByteArray((const char*)decompressed, (int)decompressedSize);
} }
@ -414,7 +418,7 @@ USTATUS gzipDecompress(const UByteArray & input, UByteArray & output)
// 15 for the maximum history buffer, 16 for gzip only input. // 15 for the maximum history buffer, 16 for gzip only input.
int ret = inflateInit2(&stream, 15U | 16U); int ret = inflateInit2(&stream, 15U | 16U);
if (ret != Z_OK) if (ret != Z_OK)
return U_CUSTOMIZED_DECOMPRESSION_FAILED; return U_GZIP_DECOMPRESSION_FAILED;
while (ret == Z_OK) { while (ret == Z_OK) {
Bytef out[4096]; Bytef out[4096];
@ -427,5 +431,5 @@ USTATUS gzipDecompress(const UByteArray & input, UByteArray & output)
} }
inflateEnd(&stream); inflateEnd(&stream);
return ret == Z_STREAM_END ? U_SUCCESS : U_CUSTOMIZED_DECOMPRESSION_FAILED; return ret == Z_STREAM_END ? U_SUCCESS : U_GZIP_DECOMPRESSION_FAILED;
} }

View File

@ -29,8 +29,8 @@ UString uniqueItemName(const UModelIndex & index);
// Converts error code to UString // Converts error code to UString
UString errorCodeToUString(USTATUS errorCode); UString errorCodeToUString(USTATUS errorCode);
// EFI/Tiano decompression routine // EFI/Tiano/LZMA decompression routine
USTATUS decompress(const UByteArray & compressed, const UINT8 compressionType, UINT8 & algorithm, UByteArray & decompressed, UByteArray & efiDecompressed); USTATUS decompress(const UByteArray & compressed, const UINT8 compressionType, UINT8 & algorithm, UINT32 & dictionarySize, UByteArray & decompressed, UByteArray & efiDecompressed);
// GZIP decompression routine // GZIP decompression routine
USTATUS gzipDecompress(const UByteArray & compressed, UByteArray & decompressed); USTATUS gzipDecompress(const UByteArray & compressed, UByteArray & decompressed);