mirror of
https://github.com/LongSoft/UEFITool.git
synced 2024-11-22 16:08:23 +08:00
UT A16
- added various size checks to prevent crashes found by fuzzing with AFL - rewritten parsing of GUID-defined sections
This commit is contained in:
parent
5fd8edf0be
commit
8c05b4da6a
@ -17,7 +17,7 @@
|
|||||||
UEFITool::UEFITool(QWidget *parent) :
|
UEFITool::UEFITool(QWidget *parent) :
|
||||||
QMainWindow(parent),
|
QMainWindow(parent),
|
||||||
ui(new Ui::UEFITool),
|
ui(new Ui::UEFITool),
|
||||||
version(tr("0.30.0_alpha15"))
|
version(tr("0.30.0_alpha16"))
|
||||||
{
|
{
|
||||||
clipboard = QApplication::clipboard();
|
clipboard = QApplication::clipboard();
|
||||||
|
|
||||||
@ -199,8 +199,7 @@ bool UEFITool::enableExtractBodyUncompressed(const QModelIndex ¤t)
|
|||||||
pdata.section.compressed.algorithm != COMPRESSION_ALGORITHM_UNKNOWN) { //Compressed section
|
pdata.section.compressed.algorithm != COMPRESSION_ALGORITHM_UNKNOWN) { //Compressed section
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (model->subtype(current) == EFI_SECTION_GUID_DEFINED &&
|
else if (model->subtype(current) == EFI_SECTION_GUID_DEFINED) {
|
||||||
(pdata.section.guidDefined.attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED)) {
|
|
||||||
QByteArray guid = QByteArray((const char*)&pdata.section.guidDefined.guid, sizeof(EFI_GUID));
|
QByteArray guid = QByteArray((const char*)&pdata.section.guidDefined.guid, sizeof(EFI_GUID));
|
||||||
if (guid == EFI_GUIDED_SECTION_TIANO || guid == EFI_GUIDED_SECTION_LZMA) {
|
if (guid == EFI_GUIDED_SECTION_TIANO || guid == EFI_GUIDED_SECTION_LZMA) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -78,6 +78,7 @@ typedef UINT8 STATUS;
|
|||||||
#define ERR_DIR_ALREADY_EXIST 32
|
#define ERR_DIR_ALREADY_EXIST 32
|
||||||
#define ERR_DIR_CREATE 33
|
#define ERR_DIR_CREATE 33
|
||||||
#define ERR_TRUNCATED_IMAGE 34
|
#define ERR_TRUNCATED_IMAGE 34
|
||||||
|
#define ERR_INVALID_CAPSULE 35
|
||||||
#define ERR_NOT_IMPLEMENTED 0xFF
|
#define ERR_NOT_IMPLEMENTED 0xFF
|
||||||
|
|
||||||
// UDK porting definitions
|
// UDK porting definitions
|
||||||
|
@ -31,6 +31,9 @@ typedef struct _FLASH_DESCRIPTOR_HEADER {
|
|||||||
// Descriptor region size
|
// Descriptor region size
|
||||||
#define FLASH_DESCRIPTOR_SIZE 0x1000
|
#define FLASH_DESCRIPTOR_SIZE 0x1000
|
||||||
|
|
||||||
|
// Maximum base value in descriptor map
|
||||||
|
#define FLASH_DESCRIPTOR_MAX_BASE 0xE0
|
||||||
|
|
||||||
// Descriptor map
|
// Descriptor map
|
||||||
// Base fields are storing bits [11:4] of actual base addresses, all other bits are 0
|
// Base fields are storing bits [11:4] of actual base addresses, all other bits are 0
|
||||||
typedef struct _FLASH_DESCRIPTOR_MAP {
|
typedef struct _FLASH_DESCRIPTOR_MAP {
|
||||||
|
71
common/ffs.h
71
common/ffs.h
@ -68,11 +68,8 @@ const QByteArray TOSHIBA_CAPSULE_GUID
|
|||||||
// AMI Aptio extended capsule header
|
// AMI Aptio extended capsule header
|
||||||
typedef struct _APTIO_CAPSULE_HEADER {
|
typedef struct _APTIO_CAPSULE_HEADER {
|
||||||
EFI_CAPSULE_HEADER CapsuleHeader;
|
EFI_CAPSULE_HEADER CapsuleHeader;
|
||||||
UINT16 RomImageOffset; // offset in bytes from the beginning of the capsule header to the start of
|
UINT16 RomImageOffset; // offset in bytes from the beginning of the capsule header to the start of the capsule volume
|
||||||
// the capsule volume
|
UINT16 RomLayoutOffset; // offset to the table of the module descriptors in the capsule's volume that are included in the signature calculation
|
||||||
//!TODO: Enable certificate and ROM layout reading
|
|
||||||
//UINT16 RomLayoutOffset; // offset to the table of the module descriptors in the capsule's volume
|
|
||||||
// that are included in the signature calculation
|
|
||||||
//FW_CERTIFICATE FWCert;
|
//FW_CERTIFICATE FWCert;
|
||||||
//ROM_AREA RomAreaMap[1];
|
//ROM_AREA RomAreaMap[1];
|
||||||
} APTIO_CAPSULE_HEADER;
|
} APTIO_CAPSULE_HEADER;
|
||||||
@ -454,6 +451,35 @@ const QByteArray EFI_GUIDED_SECTION_LZMA // EE4E5898-3914-4259-9D6E-DC7BD79403CF
|
|||||||
const QByteArray EFI_FIRMWARE_CONTENTS_SIGNED_GUID //0F9D89E8-9259-4F76-A5AF-0C89E34023DF
|
const QByteArray EFI_FIRMWARE_CONTENTS_SIGNED_GUID //0F9D89E8-9259-4F76-A5AF-0C89E34023DF
|
||||||
("\xE8\x89\x9D\x0F\x59\x92\x76\x4F\xA5\xAF\x0C\x89\xE3\x40\x23\xDF", 16);
|
("\xE8\x89\x9D\x0F\x59\x92\x76\x4F\xA5\xAF\x0C\x89\xE3\x40\x23\xDF", 16);
|
||||||
|
|
||||||
|
//#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002
|
||||||
|
#define WIN_CERT_TYPE_EFI_GUID 0x0EF1
|
||||||
|
|
||||||
|
typedef struct _WIN_CERTIFICATE {
|
||||||
|
UINT32 Length;
|
||||||
|
UINT16 Revision;
|
||||||
|
UINT16 CertificateType;
|
||||||
|
//UINT8 CertData[];
|
||||||
|
} WIN_CERTIFICATE;
|
||||||
|
|
||||||
|
typedef struct _WIN_CERTIFICATE_UEFI_GUID {
|
||||||
|
WIN_CERTIFICATE Header; // Standard WIN_CERTIFICATE
|
||||||
|
EFI_GUID CertType; // Determines format of CertData
|
||||||
|
// UINT8 CertData[]; // Certificate data follows
|
||||||
|
} WIN_CERTIFICATE_UEFI_GUID;
|
||||||
|
|
||||||
|
// WIN_CERTIFICATE_UEFI_GUID.CertType
|
||||||
|
const QByteArray EFI_CERT_TYPE_RSA2048_SHA256_GUID
|
||||||
|
("\x14\x74\x71\xA7\x16\xC6\x77\x49\x94\x20\x84\x47\x12\xA7\x35\xBF");
|
||||||
|
//const QByteArray EFI_CERT_TYPE_PKCS7_GUID
|
||||||
|
//("\x9D\xD2\xAF\x4A\xDF\x68\xEE\x49\x8A\xA9\x34\x7D\x37\x56\x65\xA7");
|
||||||
|
|
||||||
|
// WIN_CERTIFICATE_UEFI_GUID.CertData
|
||||||
|
typedef struct _EFI_CERT_BLOCK_RSA_2048_SHA256 {
|
||||||
|
UINT32 HashType;
|
||||||
|
UINT8 PublicKey[256];
|
||||||
|
UINT8 Signature[256];
|
||||||
|
} EFI_CERT_BLOCK_RSA_2048_SHA256;
|
||||||
|
|
||||||
// Version section
|
// Version section
|
||||||
typedef struct _EFI_VERSION_SECTION {
|
typedef struct _EFI_VERSION_SECTION {
|
||||||
UINT8 Size[3];
|
UINT8 Size[3];
|
||||||
@ -549,43 +575,10 @@ typedef EFI_COMMON_SECTION_HEADER2 EFI_USER_INTERFACE_SECTION2;
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// If present, this must be the first opcode,
|
/// If present, this must be the first opcode,
|
||||||
/// EFI_DEP_SOR is only used by DXE driver.
|
/// EFI_DEP_SOR is only used by DXE drivers
|
||||||
///
|
///
|
||||||
#define EFI_DEP_SOR 0x09
|
#define EFI_DEP_SOR 0x09
|
||||||
|
|
||||||
//*****************************************************************************
|
|
||||||
// UEFI Crypto-signed Stuff
|
|
||||||
//*****************************************************************************
|
|
||||||
|
|
||||||
#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002
|
|
||||||
#define WIN_CERT_TYPE_EFI_GUID 0x0EF1
|
|
||||||
|
|
||||||
typedef struct _WIN_CERTIFICATE {
|
|
||||||
UINT32 Length;
|
|
||||||
UINT16 Revision;
|
|
||||||
UINT16 CertificateType;
|
|
||||||
//UINT8 CertData[];
|
|
||||||
} WIN_CERTIFICATE;
|
|
||||||
|
|
||||||
typedef struct _WIN_CERTIFICATE_UEFI_GUID {
|
|
||||||
WIN_CERTIFICATE Header; // Standard WIN_CERTIFICATE
|
|
||||||
EFI_GUID CertType; // Determines format of CertData
|
|
||||||
// UINT8 CertData[]; // Certificate data follows
|
|
||||||
} WIN_CERTIFICATE_UEFI_GUID;
|
|
||||||
|
|
||||||
// WIN_CERTIFICATE_UEFI_GUID.CertType
|
|
||||||
const QByteArray EFI_CERT_TYPE_RSA2048_SHA256_GUID
|
|
||||||
("\x14\x74\x71\xA7\x16\xC6\x77\x49\x94\x20\x84\x47\x12\xA7\x35\xBF");
|
|
||||||
const QByteArray EFI_CERT_TYPE_PKCS7_GUID
|
|
||||||
("\x9D\xD2\xAF\x4A\xDF\x68\xEE\x49\x8A\xA9\x34\x7D\x37\x56\x65\xA7");
|
|
||||||
|
|
||||||
// WIN_CERTIFICATE_UEFI_GUID.CertData
|
|
||||||
typedef struct _EFI_CERT_BLOCK_RSA_2048_SHA256 {
|
|
||||||
UINT32 HashType;
|
|
||||||
UINT8 PublicKey[256];
|
|
||||||
UINT8 Signature[256];
|
|
||||||
} EFI_CERT_BLOCK_RSA_2048_SHA256;
|
|
||||||
|
|
||||||
// Restore previous packing rules
|
// Restore previous packing rules
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
@ -64,19 +64,32 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
|||||||
// Reset capsule offset fixeup value
|
// Reset capsule offset fixeup value
|
||||||
capsuleOffsetFixup = 0;
|
capsuleOffsetFixup = 0;
|
||||||
|
|
||||||
// Check buffer size to be more then or equal to size of EFI_CAPSULE_HEADER
|
// Check buffer size to be more than or equal to size of EFI_CAPSULE_HEADER
|
||||||
if ((UINT32)buffer.size() <= sizeof(EFI_CAPSULE_HEADER)) {
|
if ((UINT32)buffer.size() <= sizeof(EFI_CAPSULE_HEADER)) {
|
||||||
msg(tr("parseImageFile: image file is smaller then minimum size of %1h (%2) bytes").hexarg(sizeof(EFI_CAPSULE_HEADER)).arg(sizeof(EFI_CAPSULE_HEADER)));
|
msg(tr("parseImageFile: image file is smaller than minimum size of %1h (%2) bytes").hexarg(sizeof(EFI_CAPSULE_HEADER)).arg(sizeof(EFI_CAPSULE_HEADER)));
|
||||||
return ERR_INVALID_PARAMETER;
|
return ERR_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check buffer for being normal EFI capsule header
|
|
||||||
UINT32 capsuleHeaderSize = 0;
|
|
||||||
QModelIndex index;
|
QModelIndex index;
|
||||||
|
UINT32 capsuleHeaderSize = 0;
|
||||||
|
// Check buffer for being normal EFI capsule header
|
||||||
if (buffer.startsWith(EFI_CAPSULE_GUID)
|
if (buffer.startsWith(EFI_CAPSULE_GUID)
|
||||||
|| buffer.startsWith(INTEL_CAPSULE_GUID)) {
|
|| buffer.startsWith(INTEL_CAPSULE_GUID)) {
|
||||||
// Get info
|
// Get info
|
||||||
const EFI_CAPSULE_HEADER* capsuleHeader = (const EFI_CAPSULE_HEADER*)buffer.constData();
|
const EFI_CAPSULE_HEADER* capsuleHeader = (const EFI_CAPSULE_HEADER*)buffer.constData();
|
||||||
|
|
||||||
|
// Check sanity of HeaderSize and CapsuleImageSize values
|
||||||
|
if (capsuleHeader->HeaderSize == 0 || capsuleHeader->HeaderSize > (UINT32)buffer.size() || capsuleHeader->HeaderSize > capsuleHeader->CapsuleImageSize) {
|
||||||
|
msg(tr("parseImageFile: UEFI capsule header size of %1h (%2) bytes is invalid")
|
||||||
|
.hexarg(capsuleHeader->HeaderSize).arg(capsuleHeader->HeaderSize));
|
||||||
|
return ERR_INVALID_CAPSULE;
|
||||||
|
}
|
||||||
|
if (capsuleHeader->CapsuleImageSize == 0 || capsuleHeader->CapsuleImageSize > (UINT32)buffer.size()) {
|
||||||
|
msg(tr("parseImageFile: UEFI capsule image size of %1h (%2) bytes is invalid")
|
||||||
|
.hexarg(capsuleHeader->CapsuleImageSize).arg(capsuleHeader->CapsuleImageSize));
|
||||||
|
return ERR_INVALID_CAPSULE;
|
||||||
|
}
|
||||||
|
|
||||||
capsuleHeaderSize = capsuleHeader->HeaderSize;
|
capsuleHeaderSize = capsuleHeader->HeaderSize;
|
||||||
QByteArray header = buffer.left(capsuleHeaderSize);
|
QByteArray header = buffer.left(capsuleHeaderSize);
|
||||||
QByteArray body = buffer.mid(capsuleHeaderSize);
|
QByteArray body = buffer.mid(capsuleHeaderSize);
|
||||||
@ -84,8 +97,8 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
|||||||
QString info = tr("Offset: 0h\nCapsule GUID: %1\nFull size: %2h (%3)\nHeader size: %4h (%5)\nImage size: %6h (%7)\nFlags: %8h")
|
QString info = tr("Offset: 0h\nCapsule GUID: %1\nFull size: %2h (%3)\nHeader size: %4h (%5)\nImage size: %6h (%7)\nFlags: %8h")
|
||||||
.arg(guidToQString(capsuleHeader->CapsuleGuid))
|
.arg(guidToQString(capsuleHeader->CapsuleGuid))
|
||||||
.hexarg(buffer.size()).arg(buffer.size())
|
.hexarg(buffer.size()).arg(buffer.size())
|
||||||
.hexarg(capsuleHeader->HeaderSize).arg(capsuleHeader->HeaderSize)
|
.hexarg(capsuleHeaderSize).arg(capsuleHeaderSize)
|
||||||
.hexarg(capsuleHeader->CapsuleImageSize - capsuleHeader->HeaderSize).arg(capsuleHeader->CapsuleImageSize - capsuleHeader->HeaderSize)
|
.hexarg(capsuleHeader->CapsuleImageSize - capsuleHeaderSize).arg(capsuleHeader->CapsuleImageSize - capsuleHeaderSize)
|
||||||
.hexarg2(capsuleHeader->Flags, 8);
|
.hexarg2(capsuleHeader->Flags, 8);
|
||||||
|
|
||||||
// Construct parsing data
|
// Construct parsing data
|
||||||
@ -93,7 +106,7 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
|||||||
pdata.fixed = TRUE;
|
pdata.fixed = TRUE;
|
||||||
|
|
||||||
// Set capsule offset fixup for correct volume allignment warnings
|
// Set capsule offset fixup for correct volume allignment warnings
|
||||||
capsuleOffsetFixup = capsuleHeader->HeaderSize;
|
capsuleOffsetFixup = capsuleHeaderSize;
|
||||||
|
|
||||||
// Add tree item
|
// Add tree item
|
||||||
index = model->addItem(Types::Capsule, Subtypes::UefiCapsule, name, QString(), info, header, body, parsingDataToQByteArray(pdata), root);
|
index = model->addItem(Types::Capsule, Subtypes::UefiCapsule, name, QString(), info, header, body, parsingDataToQByteArray(pdata), root);
|
||||||
@ -102,6 +115,19 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
|||||||
else if (buffer.startsWith(TOSHIBA_CAPSULE_GUID)) {
|
else if (buffer.startsWith(TOSHIBA_CAPSULE_GUID)) {
|
||||||
// Get info
|
// Get info
|
||||||
const TOSHIBA_CAPSULE_HEADER* capsuleHeader = (const TOSHIBA_CAPSULE_HEADER*)buffer.constData();
|
const TOSHIBA_CAPSULE_HEADER* capsuleHeader = (const TOSHIBA_CAPSULE_HEADER*)buffer.constData();
|
||||||
|
|
||||||
|
// Check sanity of HeaderSize and FullSize values
|
||||||
|
if (capsuleHeader->HeaderSize == 0 || capsuleHeader->HeaderSize > (UINT32)buffer.size() || capsuleHeader->HeaderSize > capsuleHeader->FullSize) {
|
||||||
|
msg(tr("parseImageFile: Toshiba capsule header size of %1h (%2) bytes is invalid")
|
||||||
|
.hexarg(capsuleHeader->HeaderSize).arg(capsuleHeader->HeaderSize));
|
||||||
|
return ERR_INVALID_CAPSULE;
|
||||||
|
}
|
||||||
|
if (capsuleHeader->FullSize == 0 || capsuleHeader->FullSize > (UINT32)buffer.size()) {
|
||||||
|
msg(tr("parseImageFile: Toshiba capsule full size of %1h (%2) bytes is invalid")
|
||||||
|
.hexarg(capsuleHeader->FullSize).arg(capsuleHeader->FullSize));
|
||||||
|
return ERR_INVALID_CAPSULE;
|
||||||
|
}
|
||||||
|
|
||||||
capsuleHeaderSize = capsuleHeader->HeaderSize;
|
capsuleHeaderSize = capsuleHeader->HeaderSize;
|
||||||
QByteArray header = buffer.left(capsuleHeaderSize);
|
QByteArray header = buffer.left(capsuleHeaderSize);
|
||||||
QByteArray body = buffer.right(buffer.size() - capsuleHeaderSize);
|
QByteArray body = buffer.right(buffer.size() - capsuleHeaderSize);
|
||||||
@ -109,8 +135,8 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
|||||||
QString info = tr("Offset: 0h\nCapsule GUID: %1\nFull size: %2h (%3)\nHeader size: %4h (%5)\nImage size: %6h (%7)\nFlags: %8h")
|
QString info = tr("Offset: 0h\nCapsule GUID: %1\nFull size: %2h (%3)\nHeader size: %4h (%5)\nImage size: %6h (%7)\nFlags: %8h")
|
||||||
.arg(guidToQString(capsuleHeader->CapsuleGuid))
|
.arg(guidToQString(capsuleHeader->CapsuleGuid))
|
||||||
.hexarg(buffer.size()).arg(buffer.size())
|
.hexarg(buffer.size()).arg(buffer.size())
|
||||||
.hexarg(capsuleHeader->HeaderSize).arg(capsuleHeader->HeaderSize)
|
.hexarg(capsuleHeaderSize).arg(capsuleHeaderSize)
|
||||||
.hexarg(capsuleHeader->FullSize - capsuleHeader->HeaderSize).arg(capsuleHeader->FullSize - capsuleHeader->HeaderSize)
|
.hexarg(capsuleHeader->FullSize - capsuleHeaderSize).arg(capsuleHeader->FullSize - capsuleHeaderSize)
|
||||||
.hexarg2(capsuleHeader->Flags, 8);
|
.hexarg2(capsuleHeader->Flags, 8);
|
||||||
|
|
||||||
// Construct parsing data
|
// Construct parsing data
|
||||||
@ -118,7 +144,7 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
|||||||
pdata.fixed = TRUE;
|
pdata.fixed = TRUE;
|
||||||
|
|
||||||
// Set capsule offset fixup for correct volume allignment warnings
|
// Set capsule offset fixup for correct volume allignment warnings
|
||||||
capsuleOffsetFixup = capsuleHeader->HeaderSize;
|
capsuleOffsetFixup = capsuleHeaderSize;
|
||||||
|
|
||||||
// Add tree item
|
// Add tree item
|
||||||
index = model->addItem(Types::Capsule, Subtypes::ToshibaCapsule, name, QString(), info, header, body, parsingDataToQByteArray(pdata), root);
|
index = model->addItem(Types::Capsule, Subtypes::ToshibaCapsule, name, QString(), info, header, body, parsingDataToQByteArray(pdata), root);
|
||||||
@ -126,8 +152,25 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
|||||||
// Check buffer for being extended Aptio signed capsule header
|
// Check buffer for being extended Aptio signed capsule header
|
||||||
else if (buffer.startsWith(APTIO_SIGNED_CAPSULE_GUID) || buffer.startsWith(APTIO_UNSIGNED_CAPSULE_GUID)) {
|
else if (buffer.startsWith(APTIO_SIGNED_CAPSULE_GUID) || buffer.startsWith(APTIO_UNSIGNED_CAPSULE_GUID)) {
|
||||||
bool signedCapsule = buffer.startsWith(APTIO_SIGNED_CAPSULE_GUID);
|
bool signedCapsule = buffer.startsWith(APTIO_SIGNED_CAPSULE_GUID);
|
||||||
|
|
||||||
|
if ((UINT32)buffer.size() <= sizeof(APTIO_CAPSULE_HEADER)) {
|
||||||
|
msg(tr("parseImageFile: AMI capsule image file is smaller than minimum size of %1h (%2) bytes").hexarg(sizeof(APTIO_CAPSULE_HEADER)).arg(sizeof(APTIO_CAPSULE_HEADER)));
|
||||||
|
return ERR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
// Get info
|
// Get info
|
||||||
const APTIO_CAPSULE_HEADER* capsuleHeader = (const APTIO_CAPSULE_HEADER*)buffer.constData();
|
const APTIO_CAPSULE_HEADER* capsuleHeader = (const APTIO_CAPSULE_HEADER*)buffer.constData();
|
||||||
|
|
||||||
|
// Check sanity of RomImageOffset and CapsuleImageSize values
|
||||||
|
if (capsuleHeader->RomImageOffset == 0 || capsuleHeader->RomImageOffset > (UINT32)buffer.size() || capsuleHeader->RomImageOffset > capsuleHeader->CapsuleHeader.CapsuleImageSize) {
|
||||||
|
msg(tr("parseImageFile: AMI capsule image offset of %1h (%2) bytes is invalid").hexarg(capsuleHeader->RomImageOffset).arg(capsuleHeader->RomImageOffset));
|
||||||
|
return ERR_INVALID_CAPSULE;
|
||||||
|
}
|
||||||
|
if (capsuleHeader->CapsuleHeader.CapsuleImageSize == 0 || capsuleHeader->CapsuleHeader.CapsuleImageSize > (UINT32)buffer.size()) {
|
||||||
|
msg(tr("parseImageFile: AMI capsule image size of %1h (%2) bytes is invalid").hexarg(capsuleHeader->CapsuleHeader.CapsuleImageSize).arg(capsuleHeader->CapsuleHeader.CapsuleImageSize));
|
||||||
|
return ERR_INVALID_CAPSULE;
|
||||||
|
}
|
||||||
|
|
||||||
capsuleHeaderSize = capsuleHeader->RomImageOffset;
|
capsuleHeaderSize = capsuleHeader->RomImageOffset;
|
||||||
QByteArray header = buffer.left(capsuleHeaderSize);
|
QByteArray header = buffer.left(capsuleHeaderSize);
|
||||||
QByteArray body = buffer.mid(capsuleHeaderSize);
|
QByteArray body = buffer.mid(capsuleHeaderSize);
|
||||||
@ -220,13 +263,31 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
|
|||||||
|
|
||||||
// Check for buffer size to be greater or equal to descriptor region size
|
// Check for buffer size to be greater or equal to descriptor region size
|
||||||
if (intelImage.size() < FLASH_DESCRIPTOR_SIZE) {
|
if (intelImage.size() < FLASH_DESCRIPTOR_SIZE) {
|
||||||
msg(tr("parseIntelImage: input file is smaller then minimum descriptor size of %1h (%2) bytes").hexarg(FLASH_DESCRIPTOR_SIZE).arg(FLASH_DESCRIPTOR_SIZE));
|
msg(tr("parseIntelImage: input file is smaller than minimum descriptor size of %1h (%2) bytes").hexarg(FLASH_DESCRIPTOR_SIZE).arg(FLASH_DESCRIPTOR_SIZE));
|
||||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse descriptor map
|
// Parse descriptor map
|
||||||
const FLASH_DESCRIPTOR_MAP* descriptorMap = (const FLASH_DESCRIPTOR_MAP*)(descriptor + sizeof(FLASH_DESCRIPTOR_HEADER));
|
const FLASH_DESCRIPTOR_MAP* descriptorMap = (const FLASH_DESCRIPTOR_MAP*)(descriptor + sizeof(FLASH_DESCRIPTOR_HEADER));
|
||||||
const FLASH_DESCRIPTOR_UPPER_MAP* upperMap = (const FLASH_DESCRIPTOR_UPPER_MAP*)(descriptor + FLASH_DESCRIPTOR_UPPER_MAP_BASE);
|
const FLASH_DESCRIPTOR_UPPER_MAP* upperMap = (const FLASH_DESCRIPTOR_UPPER_MAP*)(descriptor + FLASH_DESCRIPTOR_UPPER_MAP_BASE);
|
||||||
|
|
||||||
|
// Check sanity of base values
|
||||||
|
if (descriptorMap->MasterBase > FLASH_DESCRIPTOR_MAX_BASE
|
||||||
|
|| descriptorMap->MasterBase == descriptorMap->RegionBase
|
||||||
|
|| descriptorMap->MasterBase == descriptorMap->ComponentBase) {
|
||||||
|
msg(tr("parseIntelImage: invalid descriptor master base %1h").hexarg2(descriptorMap->MasterBase, 2));
|
||||||
|
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||||
|
}
|
||||||
|
if (descriptorMap->RegionBase > FLASH_DESCRIPTOR_MAX_BASE
|
||||||
|
|| descriptorMap->RegionBase == descriptorMap->ComponentBase) {
|
||||||
|
msg(tr("parseIntelImage: invalid descriptor region base %1h").hexarg2(descriptorMap->RegionBase, 2));
|
||||||
|
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||||
|
}
|
||||||
|
if (descriptorMap->ComponentBase > FLASH_DESCRIPTOR_MAX_BASE) {
|
||||||
|
msg(tr("parseIntelImage: invalid descriptor component base %1h").hexarg2(descriptorMap->ComponentBase, 2));
|
||||||
|
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||||
|
}
|
||||||
|
|
||||||
const FLASH_DESCRIPTOR_REGION_SECTION* regionSection = (const FLASH_DESCRIPTOR_REGION_SECTION*)calculateAddress8(descriptor, descriptorMap->RegionBase);
|
const FLASH_DESCRIPTOR_REGION_SECTION* regionSection = (const FLASH_DESCRIPTOR_REGION_SECTION*)calculateAddress8(descriptor, descriptorMap->RegionBase);
|
||||||
const FLASH_DESCRIPTOR_COMPONENT_SECTION* componentSection = (const FLASH_DESCRIPTOR_COMPONENT_SECTION*)calculateAddress8(descriptor, descriptorMap->ComponentBase);
|
const FLASH_DESCRIPTOR_COMPONENT_SECTION* componentSection = (const FLASH_DESCRIPTOR_COMPONENT_SECTION*)calculateAddress8(descriptor, descriptorMap->ComponentBase);
|
||||||
|
|
||||||
@ -601,6 +662,8 @@ STATUS FfsParser::parseGbeRegion(const QByteArray & gbe, const UINT32 parentOffs
|
|||||||
// Check sanity
|
// Check sanity
|
||||||
if (gbe.isEmpty())
|
if (gbe.isEmpty())
|
||||||
return ERR_EMPTY_REGION;
|
return ERR_EMPTY_REGION;
|
||||||
|
if ((UINT32)gbe.size() < GBE_VERSION_OFFSET + sizeof(GBE_VERSION))
|
||||||
|
return ERR_INVALID_REGION;
|
||||||
|
|
||||||
// Get parent's parsing data
|
// Get parent's parsing data
|
||||||
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
||||||
@ -666,6 +729,10 @@ STATUS FfsParser::parseMeRegion(const QByteArray & me, const UINT32 parentOffset
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check sanity
|
||||||
|
if ((UINT32)me.size() < (UINT32)versionOffset + sizeof(ME_VERSION))
|
||||||
|
return ERR_INVALID_REGION;
|
||||||
|
|
||||||
// Add version information
|
// Add version information
|
||||||
if (versionFound) {
|
if (versionFound) {
|
||||||
const ME_VERSION* version = (const ME_VERSION*)(me.constData() + versionOffset);
|
const ME_VERSION* version = (const ME_VERSION*)(me.constData() + versionOffset);
|
||||||
@ -853,10 +920,17 @@ STATUS FfsParser::parseRawArea(const QByteArray & data, const QModelIndex & inde
|
|||||||
UINT32 volumeSize = 0;
|
UINT32 volumeSize = 0;
|
||||||
UINT32 bmVolumeSize = 0;
|
UINT32 bmVolumeSize = 0;
|
||||||
result = getVolumeSize(data, volumeOffset, volumeSize, bmVolumeSize);
|
result = getVolumeSize(data, volumeOffset, volumeSize, bmVolumeSize);
|
||||||
if (result)
|
if (result) {
|
||||||
|
msg(tr("parseRawArea: getVolumeSize failed with error \"%1\"").arg(errorCodeToQString(result)), index);
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Check that volume is fully present in input
|
// Check that volume is fully present in input
|
||||||
|
if (volumeSize > (UINT32)data.size() || volumeOffset + volumeSize > (UINT32)data.size()) {
|
||||||
|
msg(tr("parseRawArea: one of volumes inside overlaps the end of data"), index);
|
||||||
|
return ERR_INVALID_VOLUME;
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray volume = data.mid(volumeOffset, volumeSize);
|
QByteArray volume = data.mid(volumeOffset, volumeSize);
|
||||||
if (volumeSize > (UINT32)volume.size()) {
|
if (volumeSize > (UINT32)volume.size()) {
|
||||||
// Mark the rest as padding and finish the parsing
|
// Mark the rest as padding and finish the parsing
|
||||||
@ -948,9 +1022,27 @@ STATUS FfsParser::parseVolumeHeader(const QByteArray & volume, const UINT32 pare
|
|||||||
// Get parent's parsing data
|
// Get parent's parsing data
|
||||||
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
||||||
|
|
||||||
|
// Check that there is space for the volume header
|
||||||
|
if ((UINT32)volume.size() < sizeof(EFI_FIRMWARE_VOLUME_HEADER)) {
|
||||||
|
msg(tr("parseVolumeHeader: input volume size %1h (%2) is smaller than volume header size 40h (64)").hexarg(volume.size()).arg(volume.size()));
|
||||||
|
return ERR_INVALID_VOLUME;
|
||||||
|
}
|
||||||
|
|
||||||
// Populate volume header
|
// Populate volume header
|
||||||
const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(volume.constData());
|
const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(volume.constData());
|
||||||
|
|
||||||
|
// Check sanity of HeaderLength value
|
||||||
|
if ((UINT32)ALIGN8(volumeHeader->HeaderLength) > (UINT32)volume.size()) {
|
||||||
|
msg(tr("parseVolumeHeader: volume header overlaps the end of data"));
|
||||||
|
return ERR_INVALID_VOLUME;
|
||||||
|
}
|
||||||
|
// Check sanity of ExtHeaderOffset value
|
||||||
|
if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset
|
||||||
|
&& (UINT32)ALIGN8(volumeHeader->ExtHeaderOffset + sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER)) > (UINT32)volume.size()) {
|
||||||
|
msg(tr("parseVolumeHeader: extended volume header overlaps the end of data"));
|
||||||
|
return ERR_INVALID_VOLUME;
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate volume header size
|
// Calculate volume header size
|
||||||
UINT32 headerSize;
|
UINT32 headerSize;
|
||||||
EFI_GUID extendedHeaderGuid = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }};
|
EFI_GUID extendedHeaderGuid = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }};
|
||||||
@ -1137,7 +1229,7 @@ STATUS FfsParser::findNextVolume(const QModelIndex index, const QByteArray & bio
|
|||||||
// Check volume header to be sane
|
// Check volume header to be sane
|
||||||
for (; nextIndex > 0; nextIndex = bios.indexOf(EFI_FV_SIGNATURE, volumeOffset + nextIndex + 1)) {
|
for (; nextIndex > 0; nextIndex = bios.indexOf(EFI_FV_SIGNATURE, volumeOffset + nextIndex + 1)) {
|
||||||
const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(bios.constData() + nextIndex - EFI_FV_SIGNATURE_OFFSET);
|
const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(bios.constData() + nextIndex - EFI_FV_SIGNATURE_OFFSET);
|
||||||
if (volumeHeader->FvLength >= 0xFFFFFFFFUL) {
|
if (volumeHeader->FvLength < sizeof(EFI_FIRMWARE_VOLUME_HEADER) + 2 * sizeof(EFI_FV_BLOCK_MAP_ENTRY) || volumeHeader->FvLength >= 0xFFFFFFFFUL) {
|
||||||
msg(tr("findNextVolume: volume candidate skipped, has invalid FvLength %1h").hexarg2(volumeHeader->FvLength, 16), index);
|
msg(tr("findNextVolume: volume candidate skipped, has invalid FvLength %1h").hexarg2(volumeHeader->FvLength, 16), index);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1162,6 +1254,10 @@ STATUS FfsParser::findNextVolume(const QModelIndex index, const QByteArray & bio
|
|||||||
|
|
||||||
STATUS FfsParser::getVolumeSize(const QByteArray & bios, UINT32 volumeOffset, UINT32 & volumeSize, UINT32 & bmVolumeSize)
|
STATUS FfsParser::getVolumeSize(const QByteArray & bios, UINT32 volumeOffset, UINT32 & volumeSize, UINT32 & bmVolumeSize)
|
||||||
{
|
{
|
||||||
|
// Check that there is space for the volume header and at least two block map entries.
|
||||||
|
if ((UINT32)bios.size() < volumeOffset + sizeof(EFI_FIRMWARE_VOLUME_HEADER) + 2 * sizeof(EFI_FV_BLOCK_MAP_ENTRY))
|
||||||
|
return ERR_INVALID_VOLUME;
|
||||||
|
|
||||||
// Populate volume header
|
// Populate volume header
|
||||||
const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(bios.constData() + volumeOffset);
|
const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(bios.constData() + volumeOffset);
|
||||||
|
|
||||||
@ -1182,6 +1278,10 @@ STATUS FfsParser::getVolumeSize(const QByteArray & bios, UINT32 volumeOffset, UI
|
|||||||
|
|
||||||
volumeSize = volumeHeader->FvLength;
|
volumeSize = volumeHeader->FvLength;
|
||||||
bmVolumeSize = calcVolumeSize;
|
bmVolumeSize = calcVolumeSize;
|
||||||
|
|
||||||
|
if (volumeSize == 0)
|
||||||
|
return ERR_INVALID_VOLUME;
|
||||||
|
|
||||||
return ERR_SUCCESS;
|
return ERR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1202,9 +1302,18 @@ STATUS FfsParser::parseVolumeNonUefiData(const QByteArray & data, const UINT32 p
|
|||||||
QByteArray padding = data;
|
QByteArray padding = data;
|
||||||
QByteArray vtf;
|
QByteArray vtf;
|
||||||
INT32 vtfIndex = data.lastIndexOf(EFI_FFS_VOLUME_TOP_FILE_GUID);
|
INT32 vtfIndex = data.lastIndexOf(EFI_FFS_VOLUME_TOP_FILE_GUID);
|
||||||
if (vtfIndex > 0) { // VTF found inside non-UEFI data
|
if (vtfIndex >= 0) { // VTF candidate found inside non-UEFI data
|
||||||
padding = data.left(vtfIndex);
|
padding = data.left(vtfIndex);
|
||||||
vtf = data.mid(vtfIndex);
|
vtf = data.mid(vtfIndex);
|
||||||
|
const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)vtf.constData();
|
||||||
|
if (vtf.size() < sizeof(EFI_FFS_FILE_HEADER) // VTF candidate is too small to be a real VTF in FFSv1/v2 volume
|
||||||
|
|| (pdata.ffsVersion == 3
|
||||||
|
&& (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)
|
||||||
|
&& vtf.size() < sizeof(EFI_FFS_FILE_HEADER2))) { // VTF candidate is too small to be a real VTF in FFSv3 volume
|
||||||
|
vtfIndex = -1;
|
||||||
|
padding = data;
|
||||||
|
vtf.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add non-UEFI data first
|
// Add non-UEFI data first
|
||||||
@ -1216,7 +1325,7 @@ STATUS FfsParser::parseVolumeNonUefiData(const QByteArray & data, const UINT32 p
|
|||||||
QModelIndex paddingIndex = model->addItem(Types::Padding, Subtypes::DataPadding, tr("Non-UEFI data"), "", info, QByteArray(), padding, parsingDataToQByteArray(pdata), index);
|
QModelIndex paddingIndex = model->addItem(Types::Padding, Subtypes::DataPadding, tr("Non-UEFI data"), "", info, QByteArray(), padding, parsingDataToQByteArray(pdata), index);
|
||||||
msg(tr("parseVolumeNonUefiData: non-UEFI data found in volume's free space"), paddingIndex);
|
msg(tr("parseVolumeNonUefiData: non-UEFI data found in volume's free space"), paddingIndex);
|
||||||
|
|
||||||
if (vtfIndex > 0) {
|
if (vtfIndex >= 0) {
|
||||||
// Get VTF file header
|
// Get VTF file header
|
||||||
QByteArray header = vtf.left(sizeof(EFI_FFS_FILE_HEADER));
|
QByteArray header = vtf.left(sizeof(EFI_FFS_FILE_HEADER));
|
||||||
const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)header.constData();
|
const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)header.constData();
|
||||||
@ -1356,13 +1465,13 @@ STATUS FfsParser::parseVolumeBody(const QModelIndex & index)
|
|||||||
if (model->type(current) != Types::File || model->subtype(current) == EFI_FV_FILETYPE_PAD)
|
if (model->type(current) != Types::File || model->subtype(current) == EFI_FV_FILETYPE_PAD)
|
||||||
continue;
|
continue;
|
||||||
QByteArray currentGuid = model->header(current).left(sizeof(EFI_GUID));
|
QByteArray currentGuid = model->header(current).left(sizeof(EFI_GUID));
|
||||||
// Check files after current for having the same GUID
|
// Check files after current for having an equal GUID
|
||||||
for (int j = i + 1; j < model->rowCount(index); j++) {
|
for (int j = i + 1; j < model->rowCount(index); j++) {
|
||||||
QModelIndex another = index.child(j, 0);
|
QModelIndex another = index.child(j, 0);
|
||||||
// Skip non-file entries
|
// Skip non-file entries
|
||||||
if (model->type(another) != Types::File)
|
if (model->type(another) != Types::File)
|
||||||
continue;
|
continue;
|
||||||
// Check GUIDs for being same
|
// Check GUIDs for being equal
|
||||||
QByteArray anotherGuid = model->header(another).left(sizeof(EFI_GUID));
|
QByteArray anotherGuid = model->header(another).left(sizeof(EFI_GUID));
|
||||||
if (currentGuid == anotherGuid) {
|
if (currentGuid == anotherGuid) {
|
||||||
msg(tr("parseVolumeBody: file with duplicate GUID %1").arg(guidToQString(*(const EFI_GUID*)anotherGuid.constData())), another);
|
msg(tr("parseVolumeBody: file with duplicate GUID %1").arg(guidToQString(*(const EFI_GUID*)anotherGuid.constData())), another);
|
||||||
@ -1392,10 +1501,14 @@ STATUS FfsParser::parseVolumeBody(const QModelIndex & index)
|
|||||||
UINT32 FfsParser::getFileSize(const QByteArray & volume, const UINT32 fileOffset, const UINT8 ffsVersion)
|
UINT32 FfsParser::getFileSize(const QByteArray & volume, const UINT32 fileOffset, const UINT8 ffsVersion)
|
||||||
{
|
{
|
||||||
if (ffsVersion == 2) {
|
if (ffsVersion == 2) {
|
||||||
|
if ((UINT32)volume.size() < fileOffset + sizeof(EFI_FFS_FILE_HEADER))
|
||||||
|
return 0;
|
||||||
const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)(volume.constData() + fileOffset);
|
const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)(volume.constData() + fileOffset);
|
||||||
return uint24ToUint32(fileHeader->Size);
|
return uint24ToUint32(fileHeader->Size);
|
||||||
}
|
}
|
||||||
else if (ffsVersion == 3) {
|
else if (ffsVersion == 3) {
|
||||||
|
if ((UINT32)volume.size() < fileOffset + sizeof(EFI_FFS_FILE_HEADER2))
|
||||||
|
return 0;
|
||||||
const EFI_FFS_FILE_HEADER2* fileHeader = (const EFI_FFS_FILE_HEADER2*)(volume.constData() + fileOffset);
|
const EFI_FFS_FILE_HEADER2* fileHeader = (const EFI_FFS_FILE_HEADER2*)(volume.constData() + fileOffset);
|
||||||
if (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)
|
if (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)
|
||||||
return fileHeader->ExtendedSize;
|
return fileHeader->ExtendedSize;
|
||||||
@ -1412,6 +1525,9 @@ STATUS FfsParser::parseFileHeader(const QByteArray & file, const UINT32 parentOf
|
|||||||
if (file.isEmpty())
|
if (file.isEmpty())
|
||||||
return ERR_INVALID_PARAMETER;
|
return ERR_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if ((UINT32)file.size() < sizeof(EFI_FFS_FILE_HEADER))
|
||||||
|
return ERR_INVALID_FILE;
|
||||||
|
|
||||||
// Get parent's parsing data
|
// Get parent's parsing data
|
||||||
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
||||||
|
|
||||||
@ -1419,6 +1535,8 @@ STATUS FfsParser::parseFileHeader(const QByteArray & file, const UINT32 parentOf
|
|||||||
QByteArray header = file.left(sizeof(EFI_FFS_FILE_HEADER));
|
QByteArray header = file.left(sizeof(EFI_FFS_FILE_HEADER));
|
||||||
const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)header.constData();
|
const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)header.constData();
|
||||||
if (pdata.ffsVersion == 3 && (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)) {
|
if (pdata.ffsVersion == 3 && (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)) {
|
||||||
|
if ((UINT32)file.size() < sizeof(EFI_FFS_FILE_HEADER2))
|
||||||
|
return ERR_INVALID_FILE;
|
||||||
header = file.left(sizeof(EFI_FFS_FILE_HEADER2));
|
header = file.left(sizeof(EFI_FFS_FILE_HEADER2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1430,9 +1548,9 @@ STATUS FfsParser::parseFileHeader(const QByteArray & file, const UINT32 parentOf
|
|||||||
msgUnalignedFile = true;
|
msgUnalignedFile = true;
|
||||||
|
|
||||||
// Check file alignment agains volume alignment
|
// Check file alignment agains volume alignment
|
||||||
bool msgFileAlignmentIsGreaterThenVolumes = false;
|
bool msgFileAlignmentIsGreaterThanVolumes = false;
|
||||||
if (!pdata.volume.isWeakAligned && pdata.volume.alignment < alignment)
|
if (!pdata.volume.isWeakAligned && pdata.volume.alignment < alignment)
|
||||||
msgFileAlignmentIsGreaterThenVolumes = true;
|
msgFileAlignmentIsGreaterThanVolumes = true;
|
||||||
|
|
||||||
// Check header checksum
|
// Check header checksum
|
||||||
QByteArray tempHeader = header;
|
QByteArray tempHeader = header;
|
||||||
@ -1538,7 +1656,7 @@ STATUS FfsParser::parseFileHeader(const QByteArray & file, const UINT32 parentOf
|
|||||||
// Show messages
|
// Show messages
|
||||||
if (msgUnalignedFile)
|
if (msgUnalignedFile)
|
||||||
msg(tr("parseFileHeader: unaligned file"), index);
|
msg(tr("parseFileHeader: unaligned file"), index);
|
||||||
if (msgFileAlignmentIsGreaterThenVolumes)
|
if (msgFileAlignmentIsGreaterThanVolumes)
|
||||||
msg(tr("parseFileHeader: file alignment %1h is greater than parent volume alignment %2h").hexarg(alignment).hexarg(pdata.volume.alignment), index);
|
msg(tr("parseFileHeader: file alignment %1h is greater than parent volume alignment %2h").hexarg(alignment).hexarg(pdata.volume.alignment), index);
|
||||||
if (msgInvalidHeaderChecksum)
|
if (msgInvalidHeaderChecksum)
|
||||||
msg(tr("parseFileHeader: invalid header checksum"), index);
|
msg(tr("parseFileHeader: invalid header checksum"), index);
|
||||||
@ -1555,10 +1673,14 @@ STATUS FfsParser::parseFileHeader(const QByteArray & file, const UINT32 parentOf
|
|||||||
UINT32 FfsParser::getSectionSize(const QByteArray & file, const UINT32 sectionOffset, const UINT8 ffsVersion)
|
UINT32 FfsParser::getSectionSize(const QByteArray & file, const UINT32 sectionOffset, const UINT8 ffsVersion)
|
||||||
{
|
{
|
||||||
if (ffsVersion == 2) {
|
if (ffsVersion == 2) {
|
||||||
|
if ((UINT32)file.size() < sectionOffset + sizeof(EFI_COMMON_SECTION_HEADER))
|
||||||
|
return 0;
|
||||||
const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(file.constData() + sectionOffset);
|
const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(file.constData() + sectionOffset);
|
||||||
return uint24ToUint32(sectionHeader->Size);
|
return uint24ToUint32(sectionHeader->Size);
|
||||||
}
|
}
|
||||||
else if (ffsVersion == 3) {
|
else if (ffsVersion == 3) {
|
||||||
|
if ((UINT32)file.size() < sectionOffset + sizeof(EFI_COMMON_SECTION_HEADER2))
|
||||||
|
return 0;
|
||||||
const EFI_COMMON_SECTION_HEADER2* sectionHeader = (const EFI_COMMON_SECTION_HEADER2*)(file.constData() + sectionOffset);
|
const EFI_COMMON_SECTION_HEADER2* sectionHeader = (const EFI_COMMON_SECTION_HEADER2*)(file.constData() + sectionOffset);
|
||||||
UINT32 size = uint24ToUint32(sectionHeader->Size);
|
UINT32 size = uint24ToUint32(sectionHeader->Size);
|
||||||
if (size == EFI_SECTION2_IS_USED)
|
if (size == EFI_SECTION2_IS_USED)
|
||||||
@ -1732,8 +1854,11 @@ STATUS FfsParser::parseSections(const QByteArray & sections, const QModelIndex &
|
|||||||
|
|
||||||
STATUS FfsParser::parseSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
STATUS FfsParser::parseSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
||||||
{
|
{
|
||||||
const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData());
|
// Check sanity
|
||||||
|
if ((UINT32)section.size() < sizeof(EFI_COMMON_SECTION_HEADER))
|
||||||
|
return ERR_INVALID_SECTION;
|
||||||
|
|
||||||
|
const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData());
|
||||||
switch (sectionHeader->Type) {
|
switch (sectionHeader->Type) {
|
||||||
// Special
|
// Special
|
||||||
case EFI_SECTION_COMPRESSION: return parseCompressedSectionHeader(section, parentOffset, parent, index);
|
case EFI_SECTION_COMPRESSION: return parseCompressedSectionHeader(section, parentOffset, parent, index);
|
||||||
@ -1764,6 +1889,10 @@ STATUS FfsParser::parseSectionHeader(const QByteArray & section, const UINT32 pa
|
|||||||
|
|
||||||
STATUS FfsParser::parseCommonSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
STATUS FfsParser::parseCommonSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
||||||
{
|
{
|
||||||
|
// Check sanity
|
||||||
|
if ((UINT32)section.size() < sizeof(EFI_COMMON_SECTION_HEADER))
|
||||||
|
return ERR_INVALID_SECTION;
|
||||||
|
|
||||||
// Get data from parent's parsing data
|
// Get data from parent's parsing data
|
||||||
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
||||||
|
|
||||||
@ -1796,6 +1925,10 @@ STATUS FfsParser::parseCommonSectionHeader(const QByteArray & section, const UIN
|
|||||||
|
|
||||||
STATUS FfsParser::parseCompressedSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
STATUS FfsParser::parseCompressedSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
||||||
{
|
{
|
||||||
|
// Check sanity
|
||||||
|
if ((UINT32)section.size() < sizeof(EFI_COMPRESSION_SECTION))
|
||||||
|
return ERR_INVALID_SECTION;
|
||||||
|
|
||||||
// Get data from parent's parsing data
|
// Get data from parent's parsing data
|
||||||
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
||||||
|
|
||||||
@ -1806,6 +1939,8 @@ STATUS FfsParser::parseCompressedSectionHeader(const QByteArray & section, const
|
|||||||
UINT8 compressionType = compressedSectionHeader->CompressionType;
|
UINT8 compressionType = compressedSectionHeader->CompressionType;
|
||||||
UINT32 uncompressedLength = compressedSectionHeader->UncompressedLength;
|
UINT32 uncompressedLength = compressedSectionHeader->UncompressedLength;
|
||||||
if (pdata.ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) {
|
if (pdata.ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) {
|
||||||
|
if ((UINT32)section.size() < sizeof(EFI_COMPRESSION_SECTION2))
|
||||||
|
return ERR_INVALID_SECTION;
|
||||||
const EFI_COMPRESSION_SECTION2* compressedSectionHeader2 = (const EFI_COMPRESSION_SECTION2*)sectionHeader;
|
const EFI_COMPRESSION_SECTION2* compressedSectionHeader2 = (const EFI_COMPRESSION_SECTION2*)sectionHeader;
|
||||||
headerSize = sizeof(EFI_COMPRESSION_SECTION2);
|
headerSize = sizeof(EFI_COMPRESSION_SECTION2);
|
||||||
compressionType = compressedSectionHeader2->CompressionType;
|
compressionType = compressedSectionHeader2->CompressionType;
|
||||||
@ -1839,6 +1974,10 @@ STATUS FfsParser::parseCompressedSectionHeader(const QByteArray & section, const
|
|||||||
|
|
||||||
STATUS FfsParser::parseGuidedSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
STATUS FfsParser::parseGuidedSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
||||||
{
|
{
|
||||||
|
// Check sanity
|
||||||
|
if ((UINT32)section.size() < sizeof(EFI_GUID_DEFINED_SECTION))
|
||||||
|
return ERR_INVALID_SECTION;
|
||||||
|
|
||||||
// Get data from parent's parsing data
|
// Get data from parent's parsing data
|
||||||
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
||||||
|
|
||||||
@ -1848,11 +1987,93 @@ STATUS FfsParser::parseGuidedSectionHeader(const QByteArray & section, const UIN
|
|||||||
EFI_GUID guid = guidDefinedSectionHeader->SectionDefinitionGuid;
|
EFI_GUID guid = guidDefinedSectionHeader->SectionDefinitionGuid;
|
||||||
UINT16 dataOffset = guidDefinedSectionHeader->DataOffset;
|
UINT16 dataOffset = guidDefinedSectionHeader->DataOffset;
|
||||||
UINT16 attributes = guidDefinedSectionHeader->Attributes;
|
UINT16 attributes = guidDefinedSectionHeader->Attributes;
|
||||||
|
UINT32 nextHeaderOffset = sizeof(EFI_GUID_DEFINED_SECTION);
|
||||||
if (pdata.ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) {
|
if (pdata.ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) {
|
||||||
|
if ((UINT32)section.size() < sizeof(EFI_GUID_DEFINED_SECTION2))
|
||||||
|
return ERR_INVALID_SECTION;
|
||||||
const EFI_GUID_DEFINED_SECTION2* guidDefinedSectionHeader2 = (const EFI_GUID_DEFINED_SECTION2*)sectionHeader;
|
const EFI_GUID_DEFINED_SECTION2* guidDefinedSectionHeader2 = (const EFI_GUID_DEFINED_SECTION2*)sectionHeader;
|
||||||
guid = guidDefinedSectionHeader2->SectionDefinitionGuid;
|
guid = guidDefinedSectionHeader2->SectionDefinitionGuid;
|
||||||
dataOffset = guidDefinedSectionHeader2->DataOffset;
|
dataOffset = guidDefinedSectionHeader2->DataOffset;
|
||||||
attributes = guidDefinedSectionHeader2->Attributes;
|
attributes = guidDefinedSectionHeader2->Attributes;
|
||||||
|
nextHeaderOffset = sizeof(EFI_GUID_DEFINED_SECTION2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for special GUIDed sections
|
||||||
|
QByteArray additionalInfo;
|
||||||
|
QByteArray baGuid((const char*)&guid, sizeof(EFI_GUID));
|
||||||
|
bool msgNoAuthStatusAttribute = false;
|
||||||
|
bool msgNoProcessingRequiredAttributeCompressed = false;
|
||||||
|
bool msgNoProcessingRequiredAttributeSigned = false;
|
||||||
|
bool msgInvalidCrc = false;
|
||||||
|
bool msgUnknownCertType = false;
|
||||||
|
bool msgUnknownCertSubtype = false;
|
||||||
|
if (baGuid == EFI_GUIDED_SECTION_CRC32) {
|
||||||
|
if ((attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) == 0) { // Check that AuthStatusValid attribute is set on compressed GUIDed sections
|
||||||
|
msgNoAuthStatusAttribute = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((UINT32)section.size() < nextHeaderOffset + sizeof(UINT32))
|
||||||
|
return ERR_INVALID_SECTION;
|
||||||
|
|
||||||
|
UINT32 crc = *(UINT32*)(section.constData() + nextHeaderOffset);
|
||||||
|
additionalInfo += tr("\nChecksum type: CRC32");
|
||||||
|
// Calculate CRC32 of section data
|
||||||
|
UINT32 calculated = crc32(0, (const UINT8*)section.constData() + dataOffset, section.size() - dataOffset);
|
||||||
|
if (crc == calculated) {
|
||||||
|
additionalInfo += tr("\nChecksum: %1h, valid").hexarg2(crc, 8);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
additionalInfo += tr("\nChecksum: %1h, invalid, should be %2h").hexarg2(crc, 8).hexarg2(calculated, 8);
|
||||||
|
msgInvalidCrc = true;
|
||||||
|
}
|
||||||
|
// No need to change dataOffset here
|
||||||
|
}
|
||||||
|
else if (baGuid == EFI_GUIDED_SECTION_LZMA || baGuid == EFI_GUIDED_SECTION_TIANO) {
|
||||||
|
if ((attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) { // Check that ProcessingRequired attribute is set on compressed GUIDed sections
|
||||||
|
msgNoProcessingRequiredAttributeCompressed = true;
|
||||||
|
}
|
||||||
|
// No need to change dataOffset here
|
||||||
|
}
|
||||||
|
else if (baGuid == EFI_FIRMWARE_CONTENTS_SIGNED_GUID) {
|
||||||
|
if ((attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) { // Check that ProcessingRequired attribute is set on signed GUIDed sections
|
||||||
|
msgNoProcessingRequiredAttributeSigned = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get certificate type and length
|
||||||
|
if ((UINT32)section.size() < nextHeaderOffset + sizeof(WIN_CERTIFICATE))
|
||||||
|
return ERR_INVALID_SECTION;
|
||||||
|
|
||||||
|
const WIN_CERTIFICATE* winCertificate = (const WIN_CERTIFICATE*)(section.constData() + nextHeaderOffset);
|
||||||
|
UINT32 certLength = winCertificate->Length;
|
||||||
|
UINT16 certType = winCertificate->CertificateType;
|
||||||
|
|
||||||
|
// Adjust dataOffset
|
||||||
|
dataOffset += certLength;
|
||||||
|
|
||||||
|
// Check section size once again
|
||||||
|
if ((UINT32)section.size() < dataOffset)
|
||||||
|
return ERR_INVALID_SECTION;
|
||||||
|
|
||||||
|
// Check certificate type
|
||||||
|
if (certType == WIN_CERT_TYPE_EFI_GUID) {
|
||||||
|
additionalInfo += tr("\nCertificate type: UEFI").hexarg2(certType, 4);
|
||||||
|
|
||||||
|
// Get certificate GUID
|
||||||
|
const WIN_CERTIFICATE_UEFI_GUID* winCertificateUefiGuid = (const WIN_CERTIFICATE_UEFI_GUID*)(section.constData() + nextHeaderOffset);
|
||||||
|
QByteArray certTypeGuid((const char*)&winCertificateUefiGuid->CertType, sizeof(EFI_GUID));
|
||||||
|
|
||||||
|
if (certTypeGuid == EFI_CERT_TYPE_RSA2048_SHA256_GUID) {
|
||||||
|
additionalInfo += tr("\nCertificate subtype: RSA2048/SHA256");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
additionalInfo += tr("\nCertificate subtype: unknown, GUID %1").arg(guidToQString(winCertificateUefiGuid->CertType));
|
||||||
|
msgUnknownCertSubtype = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
additionalInfo += tr("\nCertificate type: unknown (%1h)").hexarg2(certType, 4);
|
||||||
|
msgUnknownCertType = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray header = section.left(dataOffset);
|
QByteArray header = section.left(dataOffset);
|
||||||
@ -1869,20 +2090,40 @@ STATUS FfsParser::parseGuidedSectionHeader(const QByteArray & section, const UIN
|
|||||||
.hexarg(dataOffset)
|
.hexarg(dataOffset)
|
||||||
.hexarg2(attributes, 4);
|
.hexarg2(attributes, 4);
|
||||||
|
|
||||||
|
// Append additional info
|
||||||
|
info.append(additionalInfo);
|
||||||
|
|
||||||
// Construct parsing data
|
// Construct parsing data
|
||||||
pdata.offset += parentOffset;
|
pdata.offset += parentOffset;
|
||||||
pdata.section.guidDefined.attributes = attributes;
|
|
||||||
pdata.section.guidDefined.guid = guid;
|
pdata.section.guidDefined.guid = guid;
|
||||||
if (pdata.isOnFlash) info.prepend(tr("Offset: %1h\n").hexarg(pdata.offset));
|
if (pdata.isOnFlash) info.prepend(tr("Offset: %1h\n").hexarg(pdata.offset));
|
||||||
|
|
||||||
// Add tree item
|
// Add tree item
|
||||||
index = model->addItem(Types::Section, sectionHeader->Type, name, QString(), info, header, body, parsingDataToQByteArray(pdata), parent);
|
index = model->addItem(Types::Section, sectionHeader->Type, name, QString(), info, header, body, parsingDataToQByteArray(pdata), parent);
|
||||||
|
|
||||||
|
// Show messages
|
||||||
|
if (msgNoAuthStatusAttribute)
|
||||||
|
msg(tr("parseGuidedSectionHeader: CRC32 GUIDed section without AuthStatusValid attribute"), index);
|
||||||
|
if (msgNoProcessingRequiredAttributeCompressed)
|
||||||
|
msg(tr("parseGuidedSectionHeader: compressed GUIDed section without ProcessingRequired attribute"), index);
|
||||||
|
if (msgNoProcessingRequiredAttributeSigned)
|
||||||
|
msg(tr("parseGuidedSectionHeader: signed GUIDed section without ProcessingRequired attribute"), index);
|
||||||
|
if (msgInvalidCrc)
|
||||||
|
msg(tr("parseGuidedSectionHeader: GUID defined section with invalid CRC32"), index);
|
||||||
|
if (msgUnknownCertType)
|
||||||
|
msg(tr("parseGuidedSectionHeader: signed GUIDed section with unknown type"), index);
|
||||||
|
if (msgUnknownCertSubtype)
|
||||||
|
msg(tr("parseGuidedSectionHeader: signed GUIDed section with unknown subtype"), index);
|
||||||
|
|
||||||
return ERR_SUCCESS;
|
return ERR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATUS FfsParser::parseFreeformGuidedSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
STATUS FfsParser::parseFreeformGuidedSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
||||||
{
|
{
|
||||||
|
// Check sanity
|
||||||
|
if ((UINT32)section.size() < sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION))
|
||||||
|
return ERR_INVALID_SECTION;
|
||||||
|
|
||||||
// Get data from parent's parsing data
|
// Get data from parent's parsing data
|
||||||
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
||||||
|
|
||||||
@ -1892,6 +2133,8 @@ STATUS FfsParser::parseFreeformGuidedSectionHeader(const QByteArray & section, c
|
|||||||
UINT32 headerSize = sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION);
|
UINT32 headerSize = sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION);
|
||||||
EFI_GUID guid = fsgHeader->SubTypeGuid;
|
EFI_GUID guid = fsgHeader->SubTypeGuid;
|
||||||
if (pdata.ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) {
|
if (pdata.ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) {
|
||||||
|
if ((UINT32)section.size() < sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION2))
|
||||||
|
return ERR_INVALID_SECTION;
|
||||||
const EFI_FREEFORM_SUBTYPE_GUID_SECTION2* fsgHeader2 = (const EFI_FREEFORM_SUBTYPE_GUID_SECTION2*)sectionHeader;
|
const EFI_FREEFORM_SUBTYPE_GUID_SECTION2* fsgHeader2 = (const EFI_FREEFORM_SUBTYPE_GUID_SECTION2*)sectionHeader;
|
||||||
headerSize = sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION2);
|
headerSize = sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION2);
|
||||||
guid = fsgHeader2->SubTypeGuid;
|
guid = fsgHeader2->SubTypeGuid;
|
||||||
@ -1925,6 +2168,10 @@ STATUS FfsParser::parseFreeformGuidedSectionHeader(const QByteArray & section, c
|
|||||||
|
|
||||||
STATUS FfsParser::parseVersionSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
STATUS FfsParser::parseVersionSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
||||||
{
|
{
|
||||||
|
// Check sanity
|
||||||
|
if ((UINT32)section.size() < sizeof(EFI_VERSION_SECTION))
|
||||||
|
return ERR_INVALID_SECTION;
|
||||||
|
|
||||||
// Get data from parent's parsing data
|
// Get data from parent's parsing data
|
||||||
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
||||||
|
|
||||||
@ -1934,6 +2181,8 @@ STATUS FfsParser::parseVersionSectionHeader(const QByteArray & section, const UI
|
|||||||
UINT32 headerSize = sizeof(EFI_VERSION_SECTION);
|
UINT32 headerSize = sizeof(EFI_VERSION_SECTION);
|
||||||
UINT16 buildNumber = versionHeader->BuildNumber;
|
UINT16 buildNumber = versionHeader->BuildNumber;
|
||||||
if (pdata.ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) {
|
if (pdata.ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) {
|
||||||
|
if ((UINT32)section.size() < sizeof(EFI_VERSION_SECTION2))
|
||||||
|
return ERR_INVALID_SECTION;
|
||||||
const EFI_VERSION_SECTION2* versionHeader2 = (const EFI_VERSION_SECTION2*)sectionHeader;
|
const EFI_VERSION_SECTION2* versionHeader2 = (const EFI_VERSION_SECTION2*)sectionHeader;
|
||||||
headerSize = sizeof(EFI_VERSION_SECTION2);
|
headerSize = sizeof(EFI_VERSION_SECTION2);
|
||||||
buildNumber = versionHeader2->BuildNumber;
|
buildNumber = versionHeader2->BuildNumber;
|
||||||
@ -1963,6 +2212,10 @@ STATUS FfsParser::parseVersionSectionHeader(const QByteArray & section, const UI
|
|||||||
|
|
||||||
STATUS FfsParser::parsePostcodeSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
STATUS FfsParser::parsePostcodeSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
||||||
{
|
{
|
||||||
|
// Check sanity
|
||||||
|
if ((UINT32)section.size() < sizeof(POSTCODE_SECTION))
|
||||||
|
return ERR_INVALID_SECTION;
|
||||||
|
|
||||||
// Get data from parent's parsing data
|
// Get data from parent's parsing data
|
||||||
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
||||||
|
|
||||||
@ -1972,6 +2225,8 @@ STATUS FfsParser::parsePostcodeSectionHeader(const QByteArray & section, const U
|
|||||||
UINT32 headerSize = sizeof(POSTCODE_SECTION);
|
UINT32 headerSize = sizeof(POSTCODE_SECTION);
|
||||||
UINT32 postCode = postcodeHeader->Postcode;
|
UINT32 postCode = postcodeHeader->Postcode;
|
||||||
if (pdata.ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) {
|
if (pdata.ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) {
|
||||||
|
if ((UINT32)section.size() < sizeof(POSTCODE_SECTION2))
|
||||||
|
return ERR_INVALID_SECTION;
|
||||||
const POSTCODE_SECTION2* postcodeHeader2 = (const POSTCODE_SECTION2*)sectionHeader;
|
const POSTCODE_SECTION2* postcodeHeader2 = (const POSTCODE_SECTION2*)sectionHeader;
|
||||||
headerSize = sizeof(POSTCODE_SECTION2);
|
headerSize = sizeof(POSTCODE_SECTION2);
|
||||||
postCode = postcodeHeader2->Postcode;
|
postCode = postcodeHeader2->Postcode;
|
||||||
@ -2005,6 +2260,8 @@ STATUS FfsParser::parseSectionBody(const QModelIndex & index)
|
|||||||
// Sanity check
|
// Sanity check
|
||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
return ERR_INVALID_PARAMETER;
|
return ERR_INVALID_PARAMETER;
|
||||||
|
if ((UINT32)model->header(index).size() < sizeof(EFI_COMMON_SECTION_HEADER))
|
||||||
|
return ERR_INVALID_SECTION;
|
||||||
|
|
||||||
const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(model->header(index).constData());
|
const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(model->header(index).constData());
|
||||||
|
|
||||||
@ -2082,7 +2339,6 @@ STATUS FfsParser::parseGuidedSectionBody(const QModelIndex & index)
|
|||||||
|
|
||||||
// Get data from parsing data
|
// Get data from parsing data
|
||||||
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
|
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
|
||||||
UINT32 attributes = pdata.section.guidDefined.attributes;
|
|
||||||
EFI_GUID guid = pdata.section.guidDefined.guid;
|
EFI_GUID guid = pdata.section.guidDefined.guid;
|
||||||
|
|
||||||
// Check if section requires processing
|
// Check if section requires processing
|
||||||
@ -2090,7 +2346,6 @@ STATUS FfsParser::parseGuidedSectionBody(const QModelIndex & index)
|
|||||||
QString info;
|
QString info;
|
||||||
bool parseCurrentSection = true;
|
bool parseCurrentSection = true;
|
||||||
UINT8 algorithm = COMPRESSION_ALGORITHM_NONE;
|
UINT8 algorithm = COMPRESSION_ALGORITHM_NONE;
|
||||||
if (attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) {
|
|
||||||
// Tiano compressed section
|
// Tiano compressed section
|
||||||
if (QByteArray((const char*)&guid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_TIANO) {
|
if (QByteArray((const char*)&guid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_TIANO) {
|
||||||
algorithm = EFI_STANDARD_COMPRESSION;
|
algorithm = EFI_STANDARD_COMPRESSION;
|
||||||
@ -2129,85 +2384,6 @@ STATUS FfsParser::parseGuidedSectionBody(const QModelIndex & index)
|
|||||||
else
|
else
|
||||||
info += tr("\nCompression algorithm: unknown");
|
info += tr("\nCompression algorithm: unknown");
|
||||||
}
|
}
|
||||||
// Signed section
|
|
||||||
else if (QByteArray((const char*)&guid, sizeof(EFI_GUID)) == EFI_FIRMWARE_CONTENTS_SIGNED_GUID) {
|
|
||||||
UINT8 subtype = 0;
|
|
||||||
bool msgUnknownSubtype = false;
|
|
||||||
const WIN_CERTIFICATE* certificateHeader = (const WIN_CERTIFICATE*)model->body(index).constData();
|
|
||||||
QString signInfo = tr("Full Size: %1h (%2)").hexarg2(certificateHeader->Length, 8).arg(certificateHeader->Length);
|
|
||||||
signInfo += tr("\nType: Signature");
|
|
||||||
if (certificateHeader->CertificateType == WIN_CERT_TYPE_EFI_GUID) {
|
|
||||||
const WIN_CERTIFICATE_UEFI_GUID* guidCertificateHeader = (const WIN_CERTIFICATE_UEFI_GUID*)certificateHeader;
|
|
||||||
if (QByteArray((const char*)&guidCertificateHeader->CertType, sizeof(EFI_GUID)) == EFI_CERT_TYPE_RSA2048_SHA256_GUID) {
|
|
||||||
signInfo += tr("\nSubtype: RSA2048/SHA256");
|
|
||||||
subtype = Subtypes::UefiSignature;
|
|
||||||
}
|
|
||||||
else if (QByteArray((const char*)&guidCertificateHeader->CertType, sizeof(EFI_GUID)) == EFI_CERT_TYPE_PKCS7_GUID) {
|
|
||||||
signInfo += tr("\nSubtype: PKCS7");
|
|
||||||
subtype = Subtypes::Pkcs7Signature;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
signInfo += tr("\nSubtype: unknown");
|
|
||||||
msgUnknownSubtype = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (certificateHeader->CertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
|
|
||||||
signInfo += tr("\nSubtype: PKCS7");
|
|
||||||
subtype = Subtypes::Pkcs7Signature;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
signInfo += tr("\nSubtype: unknown");
|
|
||||||
msgUnknownSubtype = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Get parsing data
|
|
||||||
PARSING_DATA signPdata = parsingDataFromQModelIndex(index);
|
|
||||||
signPdata.offset += model->header(index).size();
|
|
||||||
if (signPdata.isOnFlash) signInfo.prepend(tr("Offset: %1h\n").hexarg(signPdata.offset));
|
|
||||||
|
|
||||||
// Add signature data to the tree
|
|
||||||
QModelIndex signatureIndex = model->addItem(Types::Signature, subtype, tr("Signature"), "", signInfo, QByteArray(), processed.left(certificateHeader->Length), parsingDataToQByteArray(signPdata), index);
|
|
||||||
|
|
||||||
// Show messages
|
|
||||||
msg(tr("parseGuidedSectionBody: signature may become invalid after any modification"), signatureIndex);
|
|
||||||
if (msgUnknownSubtype)
|
|
||||||
msg(tr("parseGuidedSectionBody: signature with unknown subtype"), signatureIndex);
|
|
||||||
|
|
||||||
// Change offset
|
|
||||||
pdata.offset += certificateHeader->Length;
|
|
||||||
|
|
||||||
// Get new body
|
|
||||||
processed = processed.mid(certificateHeader->Length);
|
|
||||||
}
|
|
||||||
// Unknown GUIDed section
|
|
||||||
else {
|
|
||||||
parseCurrentSection = false;
|
|
||||||
msg(tr("parseGuidedSectionBody: GUID defined section with unknown processing method"), index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if section requires checksum calculation
|
|
||||||
if (attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID)
|
|
||||||
{
|
|
||||||
// CRC32 section
|
|
||||||
if (QByteArray((const char*)&guid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_CRC32) {
|
|
||||||
info += tr("\nChecksum type: CRC32");
|
|
||||||
// Calculate CRC32 of section data
|
|
||||||
QByteArray body = model->body(index);
|
|
||||||
UINT32 crc = crc32(0, (const UINT8*)body.constData(), body.size());
|
|
||||||
// Check stored CRC32
|
|
||||||
UINT32 stored = *(const UINT32*)(model->header(index).constData() + sizeof(EFI_GUID_DEFINED_SECTION));
|
|
||||||
if (crc == stored) {
|
|
||||||
info += tr("\nChecksum %1h: valid").hexarg2(stored, 8);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
info += tr("\nChecksum %1h: invalid").hexarg2(stored, 8);
|
|
||||||
msg(tr("parseGuidedSectionBody: GUID defined section with invalid CRC32"), index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
msg(tr("parseGuidedSectionBody: GUID defined section with unknown authentication method"), index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add info
|
// Add info
|
||||||
model->addInfo(index, info);
|
model->addInfo(index, info);
|
||||||
@ -2246,8 +2422,10 @@ STATUS FfsParser::parseDepexSectionBody(const QModelIndex & index)
|
|||||||
QString parsed;
|
QString parsed;
|
||||||
|
|
||||||
// Check data to be present
|
// Check data to be present
|
||||||
if (!body.size())
|
if (body.size() < 2) { // 2 is a minimal sane value, i.e TRUE + END
|
||||||
return ERR_INVALID_PARAMETER;
|
msg(tr("parseDepexSectionBody: DEPEX section too short"), index);
|
||||||
|
return ERR_DEPEX_PARSE_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
const EFI_GUID * guid;
|
const EFI_GUID * guid;
|
||||||
const UINT8* current = (const UINT8*)body.constData();
|
const UINT8* current = (const UINT8*)body.constData();
|
||||||
@ -2364,7 +2542,7 @@ STATUS FfsParser::parseUiSectionBody(const QModelIndex & index)
|
|||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
return ERR_INVALID_PARAMETER;
|
return ERR_INVALID_PARAMETER;
|
||||||
|
|
||||||
QString text = QString::fromUtf16((const ushort*)model->body(index).constData());
|
QString text = QString::fromUtf16((const ushort*)model->body(index).constData(), model->body(index).size()/2);
|
||||||
|
|
||||||
// Add info
|
// Add info
|
||||||
model->addInfo(index, tr("\nText: %1").arg(text));
|
model->addInfo(index, tr("\nText: %1").arg(text));
|
||||||
@ -2377,8 +2555,11 @@ STATUS FfsParser::parseUiSectionBody(const QModelIndex & index)
|
|||||||
|
|
||||||
STATUS FfsParser::parseAprioriRawSection(const QByteArray & body, QString & parsed)
|
STATUS FfsParser::parseAprioriRawSection(const QByteArray & body, QString & parsed)
|
||||||
{
|
{
|
||||||
|
// Sanity check
|
||||||
|
if (body.size() % sizeof(EFI_GUID)) {
|
||||||
|
msg(tr("parseAprioriRawSection: apriori file has size is not a multiple of 16"));
|
||||||
|
}
|
||||||
parsed.clear();
|
parsed.clear();
|
||||||
|
|
||||||
UINT32 count = body.size() / sizeof(EFI_GUID);
|
UINT32 count = body.size() / sizeof(EFI_GUID);
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
for (UINT32 i = 0; i < count; i++) {
|
for (UINT32 i = 0; i < count; i++) {
|
||||||
@ -2437,23 +2618,43 @@ STATUS FfsParser::parsePeImageSectionBody(const QModelIndex & index)
|
|||||||
|
|
||||||
// Get section body
|
// Get section body
|
||||||
QByteArray body = model->body(index);
|
QByteArray body = model->body(index);
|
||||||
|
if ((UINT32)body.size() < sizeof(EFI_IMAGE_DOS_HEADER)) {
|
||||||
|
msg(tr("parsePeImageSectionBody: section body size is smaller than DOS header size"), index);
|
||||||
|
return ERR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
// Get PE info
|
|
||||||
QByteArray info;
|
QByteArray info;
|
||||||
|
|
||||||
const EFI_IMAGE_DOS_HEADER* dosHeader = (const EFI_IMAGE_DOS_HEADER*)body.constData();
|
const EFI_IMAGE_DOS_HEADER* dosHeader = (const EFI_IMAGE_DOS_HEADER*)body.constData();
|
||||||
if (dosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
|
if (dosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
|
||||||
info += tr("\nDOS signature: %1h, invalid").hexarg2(dosHeader->e_magic, 4);
|
info += tr("\nDOS signature: %1h, invalid").hexarg2(dosHeader->e_magic, 4);
|
||||||
msg(tr("parsePeImageSectionBody: PE32 image with invalid DOS signature"), index);
|
msg(tr("parsePeImageSectionBody: PE32 image with invalid DOS signature"), index);
|
||||||
|
model->addInfo(index, info);
|
||||||
|
return ERR_SUCCESS;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
const EFI_IMAGE_PE_HEADER* peHeader = (EFI_IMAGE_PE_HEADER*)(body.constData() + dosHeader->e_lfanew);
|
const EFI_IMAGE_PE_HEADER* peHeader = (EFI_IMAGE_PE_HEADER*)(body.constData() + dosHeader->e_lfanew);
|
||||||
|
if (body.size() < (UINT8*)peHeader - (UINT8*)dosHeader) {
|
||||||
|
info += tr("\nDOS header: invalid");
|
||||||
|
msg(tr("parsePeImageSectionBody: PE32 image with invalid DOS header"), index);
|
||||||
|
model->addInfo(index, info);
|
||||||
|
return ERR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
if (peHeader->Signature != EFI_IMAGE_PE_SIGNATURE) {
|
if (peHeader->Signature != EFI_IMAGE_PE_SIGNATURE) {
|
||||||
info += tr("\nPE signature: %1h, invalid").hexarg2(peHeader->Signature, 8);
|
info += tr("\nPE signature: %1h, invalid").hexarg2(peHeader->Signature, 8);
|
||||||
msg(tr("parsePeImageSectionBody: PE32 image with invalid PE signature"), index);
|
msg(tr("parsePeImageSectionBody: PE32 image with invalid PE signature"), index);
|
||||||
|
model->addInfo(index, info);
|
||||||
|
return ERR_SUCCESS;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
const EFI_IMAGE_FILE_HEADER* imageFileHeader = (const EFI_IMAGE_FILE_HEADER*)(peHeader + 1);
|
const EFI_IMAGE_FILE_HEADER* imageFileHeader = (const EFI_IMAGE_FILE_HEADER*)(peHeader + 1);
|
||||||
|
if (body.size() < (UINT8*)imageFileHeader - (UINT8*)dosHeader) {
|
||||||
|
info += tr("\nPE header: invalid");
|
||||||
|
msg(tr("parsePeImageSectionBody: PE32 image with invalid PE header"), index);
|
||||||
|
model->addInfo(index, info);
|
||||||
|
return ERR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
info += tr("\nDOS signature: %1h\nPE signature: %2h\nMachine type: %3\nNumber of sections: %4\nCharacteristics: %5h")
|
info += tr("\nDOS signature: %1h\nPE signature: %2h\nMachine type: %3\nNumber of sections: %4\nCharacteristics: %5h")
|
||||||
.hexarg2(dosHeader->e_magic, 4)
|
.hexarg2(dosHeader->e_magic, 4)
|
||||||
.hexarg2(peHeader->Signature, 8)
|
.hexarg2(peHeader->Signature, 8)
|
||||||
@ -2463,6 +2664,13 @@ STATUS FfsParser::parsePeImageSectionBody(const QModelIndex & index)
|
|||||||
|
|
||||||
EFI_IMAGE_OPTIONAL_HEADER_POINTERS_UNION optionalHeader;
|
EFI_IMAGE_OPTIONAL_HEADER_POINTERS_UNION optionalHeader;
|
||||||
optionalHeader.H32 = (const EFI_IMAGE_OPTIONAL_HEADER32*)(imageFileHeader + 1);
|
optionalHeader.H32 = (const EFI_IMAGE_OPTIONAL_HEADER32*)(imageFileHeader + 1);
|
||||||
|
if (body.size() < (UINT8*)optionalHeader.H32 - (UINT8*)dosHeader) {
|
||||||
|
info += tr("\nPE optional header: invalid");
|
||||||
|
msg(tr("parsePeImageSectionBody: PE32 image with invalid PE optional header"), index);
|
||||||
|
model->addInfo(index, info);
|
||||||
|
return ERR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
if (optionalHeader.H32->Magic == EFI_IMAGE_PE_OPTIONAL_HDR32_MAGIC) {
|
if (optionalHeader.H32->Magic == EFI_IMAGE_PE_OPTIONAL_HDR32_MAGIC) {
|
||||||
info += tr("\nOptional header signature: %1h\nSubsystem: %2h\nAddress of entry point: %3h\nBase of code: %4h\nImage base: %5h")
|
info += tr("\nOptional header signature: %1h\nSubsystem: %2h\nAddress of entry point: %3h\nBase of code: %4h\nImage base: %5h")
|
||||||
.hexarg2(optionalHeader.H32->Magic, 4)
|
.hexarg2(optionalHeader.H32->Magic, 4)
|
||||||
@ -2480,29 +2688,28 @@ STATUS FfsParser::parsePeImageSectionBody(const QModelIndex & index)
|
|||||||
.hexarg(optionalHeader.H64->ImageBase);
|
.hexarg(optionalHeader.H64->ImageBase);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
info += tr("\nOptional header signature: %1h, unknown").hexarg2(optionalHeader.H64->Magic, 4);
|
info += tr("\nOptional header signature: %1h, unknown").hexarg2(optionalHeader.H32->Magic, 4);
|
||||||
msg(tr("parsePeImageSectionBody: PE32 image with invalid optional PE header signature"), index);
|
msg(tr("parsePeImageSectionBody: PE32 image with invalid optional PE header signature"), index);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add PE info
|
|
||||||
model->addInfo(index, info);
|
model->addInfo(index, info);
|
||||||
|
|
||||||
return ERR_SUCCESS;
|
return ERR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
STATUS FfsParser::parseTeImageSectionBody(const QModelIndex & index)
|
STATUS FfsParser::parseTeImageSectionBody(const QModelIndex & index)
|
||||||
{
|
{
|
||||||
// Sanity check
|
// Check sanity
|
||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
return ERR_INVALID_PARAMETER;
|
return ERR_INVALID_PARAMETER;
|
||||||
|
|
||||||
// Get section body
|
// Get section body
|
||||||
QByteArray body = model->body(index);
|
QByteArray body = model->body(index);
|
||||||
|
if ((UINT32)body.size() < sizeof(EFI_IMAGE_TE_HEADER)) {
|
||||||
|
msg(tr("parsePeImageSectionBody: section body size is smaller than TE header size"), index);
|
||||||
|
return ERR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
// Get TE info
|
|
||||||
QByteArray info;
|
QByteArray info;
|
||||||
const EFI_IMAGE_TE_HEADER* teHeader = (const EFI_IMAGE_TE_HEADER*)body.constData();
|
const EFI_IMAGE_TE_HEADER* teHeader = (const EFI_IMAGE_TE_HEADER*)body.constData();
|
||||||
if (teHeader->Signature != EFI_IMAGE_TE_SIGNATURE) {
|
if (teHeader->Signature != EFI_IMAGE_TE_SIGNATURE) {
|
||||||
@ -2611,4 +2818,3 @@ STATUS FfsParser::addMemoryAddressesRecursive(const QModelIndex & index, const U
|
|||||||
|
|
||||||
return ERR_SUCCESS;
|
return ERR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,6 @@ typedef struct _COMPRESSED_SECTION_PARSING_DATA {
|
|||||||
|
|
||||||
typedef struct _GUIDED_SECTION_PARSING_DATA {
|
typedef struct _GUIDED_SECTION_PARSING_DATA {
|
||||||
EFI_GUID guid;
|
EFI_GUID guid;
|
||||||
UINT32 attributes;
|
|
||||||
} GUIDED_SECTION_PARSING_DATA;
|
} GUIDED_SECTION_PARSING_DATA;
|
||||||
|
|
||||||
typedef struct _FREEFORM_GUIDED_SECTION_PARSING_DATA {
|
typedef struct _FREEFORM_GUIDED_SECTION_PARSING_DATA {
|
||||||
|
@ -93,6 +93,7 @@ QString errorCodeToQString(UINT8 errorCode)
|
|||||||
//case ERR_NOTHING_TO_PATCH: return QObject::tr("Nothing to patch");
|
//case ERR_NOTHING_TO_PATCH: return QObject::tr("Nothing to patch");
|
||||||
case ERR_DEPEX_PARSE_FAILED: return QObject::tr("Dependency expression parsing failed");
|
case ERR_DEPEX_PARSE_FAILED: return QObject::tr("Dependency expression parsing failed");
|
||||||
case ERR_TRUNCATED_IMAGE: return QObject::tr("Image is truncated");
|
case ERR_TRUNCATED_IMAGE: return QObject::tr("Image is truncated");
|
||||||
|
case ERR_INVALID_CAPSULE: return QObject::tr("Invalid capsule");
|
||||||
default: return QObject::tr("Unknown error %1").arg(errorCode);
|
default: return QObject::tr("Unknown error %1").arg(errorCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user