Skip to content

Commit 95c8381

Browse files
author
Nikolaj Schlej
committed
Improve microcode header detection, parse DevExp1 region as ME region
1 parent 90ff196 commit 95c8381

File tree

4 files changed

+128
-96
lines changed

4 files changed

+128
-96
lines changed

common/ffsparser.cpp

Lines changed: 117 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,8 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l
630630
result = parsePdrRegion(region.data, region.offset, index, regionIndex);
631631
break;
632632
case Subtypes::DevExp1Region:
633+
result = parseDevExp1Region(region.data, region.offset, index, regionIndex);
634+
break;
633635
case Subtypes::Bios2Region:
634636
case Subtypes::MicrocodeRegion:
635637
case Subtypes::EcRegion:
@@ -779,6 +781,33 @@ USTATUS FfsParser::parsePdrRegion(const UByteArray & pdr, const UINT32 localOffs
779781
return U_SUCCESS;
780782
}
781783

784+
USTATUS FfsParser::parseDevExp1Region(const UByteArray & devExp1, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
785+
{
786+
// Check sanity
787+
if (devExp1.isEmpty())
788+
return U_EMPTY_REGION;
789+
790+
// Get info
791+
UString name("DevExp1 region");
792+
UString info = usprintf("Full size: %Xh (%u)", devExp1.size(), devExp1.size());
793+
794+
bool emptyRegion = false;
795+
// Check for empty region
796+
if (devExp1.size() == devExp1.count('\xFF') || devExp1.size() == devExp1.count('\x00')) {
797+
// Further parsing not needed
798+
emptyRegion = true;
799+
info += ("\nState: empty");
800+
}
801+
802+
// Add tree item
803+
index = model->addItem(localOffset, Types::Region, Subtypes::DevExp1Region, name, UString(), info, UByteArray(), devExp1, UByteArray(), Fixed, parent);
804+
805+
if (!emptyRegion) {
806+
meParser->parseMeRegionBody(index);
807+
}
808+
return U_SUCCESS;
809+
}
810+
782811
USTATUS FfsParser::parseGenericRegion(const UINT8 subtype, const UByteArray & region, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
783812
{
784813
// Check sanity
@@ -1189,6 +1218,75 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc
11891218
return U_SUCCESS;
11901219
}
11911220

1221+
BOOLEAN FfsParser::microcodeHeaderValid(const INTEL_MICROCODE_HEADER* ucodeHeader)
1222+
{
1223+
// Check main reserved bytes to be zero
1224+
bool reservedBytesValid = true;
1225+
for (UINT32 i = 0; i < sizeof(ucodeHeader->Reserved); i++) {
1226+
if (ucodeHeader->Reserved[i] != 0x00) {
1227+
reservedBytesValid = false;
1228+
break;
1229+
}
1230+
}
1231+
if (!reservedBytesValid) {
1232+
return FALSE;
1233+
}
1234+
1235+
// Check CpuFlags reserved bytes to be zero
1236+
for (UINT32 i = 0; i < sizeof(ucodeHeader->CpuFlagsReserved); i++) {
1237+
if (ucodeHeader->CpuFlagsReserved[i] != 0x00) {
1238+
reservedBytesValid = false;
1239+
break;
1240+
}
1241+
}
1242+
if (!reservedBytesValid) {
1243+
return FALSE;
1244+
}
1245+
1246+
// Check data size to be multiple of 4
1247+
if (ucodeHeader->DataSize % 4 != 0) {
1248+
return FALSE;
1249+
}
1250+
1251+
// Check TotalSize to be greater then DataSize and multiple of 1024
1252+
if (ucodeHeader->TotalSize <= ucodeHeader->DataSize || ucodeHeader->TotalSize % 1024 != 0) {
1253+
return FALSE;
1254+
}
1255+
1256+
// Check date to be sane
1257+
// Check day to be in 0x01-0x09, 0x10-0x19, 0x20-0x29, 0x30-0x31
1258+
if (ucodeHeader->DateDay < 0x01 ||
1259+
(ucodeHeader->DateDay > 0x09 && ucodeHeader->DateDay < 0x10) ||
1260+
(ucodeHeader->DateDay > 0x19 && ucodeHeader->DateDay < 0x20) ||
1261+
(ucodeHeader->DateDay > 0x29 && ucodeHeader->DateDay < 0x30) ||
1262+
ucodeHeader->DateDay > 0x31) {
1263+
return FALSE;
1264+
}
1265+
// Check month to be in 0x01-0x09, 0x10-0x12
1266+
if (ucodeHeader->DateMonth < 0x01 ||
1267+
(ucodeHeader->DateMonth > 0x09 && ucodeHeader->DateMonth < 0x10) ||
1268+
ucodeHeader->DateMonth > 0x12) {
1269+
return FALSE;
1270+
}
1271+
// Check year to be in 0x1990-0x1999, 0x2000-0x2009, 0x2010-0x2019, 0x2020-0x2029, 0x2030-0x2030, 0x2040-0x2049
1272+
if (ucodeHeader->DateYear < 0x1990 ||
1273+
(ucodeHeader->DateYear > 0x1999 && ucodeHeader->DateYear < 0x2000) ||
1274+
(ucodeHeader->DateYear > 0x2009 && ucodeHeader->DateYear < 0x2010) ||
1275+
(ucodeHeader->DateYear > 0x2019 && ucodeHeader->DateYear < 0x2020) ||
1276+
(ucodeHeader->DateYear > 0x2029 && ucodeHeader->DateYear < 0x2030) ||
1277+
(ucodeHeader->DateYear > 0x2039 && ucodeHeader->DateYear < 0x2040) ||
1278+
ucodeHeader->DateYear > 0x2049) {
1279+
return FALSE;
1280+
}
1281+
1282+
// Check loader revision to be sane
1283+
if (ucodeHeader->LoaderRevision > INTEL_MICROCODE_MAX_LOADER_REVISION) {
1284+
return FALSE;
1285+
}
1286+
1287+
return TRUE;
1288+
}
1289+
11921290
USTATUS FfsParser::findNextRawAreaItem(const UModelIndex & index, const UINT32 localOffset, UINT8 & nextItemType, UINT32 & nextItemOffset, UINT32 & nextItemSize, UINT32 & nextItemAlternativeSize)
11931291
{
11941292
UByteArray data = model->body(index);
@@ -1203,29 +1301,14 @@ USTATUS FfsParser::findNextRawAreaItem(const UModelIndex & index, const UINT32 l
12031301
const UINT32 restSize = dataSize - offset;
12041302
if (readUnaligned(currentPos) == INTEL_MICROCODE_HEADER_VERSION_1) {// Intel microcode
12051303
// Check data size
1206-
if (restSize < sizeof(INTEL_MICROCODE_HEADER))
1207-
continue;
1208-
1209-
// Check microcode size
1210-
const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)currentPos;
1211-
1212-
// Check reserved bytes
1213-
bool reservedBytesValid = true;
1214-
for (UINT32 i = 0; i < sizeof(ucodeHeader->Reserved); i++)
1215-
if (ucodeHeader->Reserved[i] != 0x00) {
1216-
reservedBytesValid = false;
1217-
break;
1218-
}
1219-
if (!reservedBytesValid)
1220-
continue;
1221-
1222-
// Data size is multiple of 4
1223-
if (ucodeHeader->DataSize % 4 != 0) {
1304+
if (restSize < sizeof(INTEL_MICROCODE_HEADER)) {
12241305
continue;
12251306
}
12261307

1227-
// TotalSize is greater then DataSize and is multiple of 1024
1228-
if (ucodeHeader->TotalSize <= ucodeHeader->DataSize || ucodeHeader->TotalSize % 1024 != 0) {
1308+
// Check microcode header candidate
1309+
const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)currentPos;
1310+
1311+
if (FALSE == microcodeHeaderValid(ucodeHeader)) {
12291312
continue;
12301313
}
12311314

@@ -3742,47 +3825,27 @@ void FfsParser::findFitRecursive(const UModelIndex & index, UModelIndex & found,
37423825
USTATUS FfsParser::parseFitEntryMicrocode(const UByteArray & microcode, const UINT32 localOffset, const UModelIndex & parent, UString & info, UINT32 &realSize)
37433826
{
37443827
U_UNUSED_PARAMETER(parent);
3745-
if ((UINT32)microcode.size() < localOffset + sizeof(INTEL_MICROCODE_HEADER)) {
3828+
if ((UINT32)microcode.size() - localOffset < sizeof(INTEL_MICROCODE_HEADER)) {
37463829
return U_INVALID_MICROCODE;
37473830
}
37483831

3749-
const INTEL_MICROCODE_HEADER* header = (const INTEL_MICROCODE_HEADER*)(microcode.constData() + localOffset);
3750-
if (header->Version != INTEL_MICROCODE_HEADER_VERSION_1) {
3751-
return U_INVALID_MICROCODE;
3752-
}
3753-
3754-
bool reservedBytesValid = true;
3755-
for (UINT8 i = 0; i < sizeof(header->Reserved); i++)
3756-
if (header->Reserved[i] != 0x00) {
3757-
reservedBytesValid = false;
3758-
break;
3759-
}
3760-
if (!reservedBytesValid) {
3761-
return U_INVALID_MICROCODE;
3762-
}
3763-
3764-
if (header->DataSize % 4 != 0) {
3832+
const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)(microcode.constData() + localOffset);
3833+
if (!microcodeHeaderValid(ucodeHeader)) {
37653834
return U_INVALID_MICROCODE;
37663835
}
37673836

3768-
if (header->TotalSize <= header->DataSize || header->TotalSize % 1024 != 0) {
3837+
if ((UINT32)microcode.size() - localOffset < ucodeHeader->TotalSize) {
37693838
return U_INVALID_MICROCODE;
37703839
}
37713840

3772-
UINT32 mcSize = header->TotalSize;
3773-
if ((UINT32)microcode.size() < localOffset + mcSize) {
3774-
return U_INVALID_MICROCODE;
3775-
}
3776-
37773841
// Valid microcode found
37783842
info = usprintf("CpuSignature: %08Xh, Revision: %08Xh, Date: %02X.%02X.%04X",
3779-
header->CpuSignature,
3780-
header->Revision,
3781-
header->DateDay,
3782-
header->DateMonth,
3783-
header->DateYear
3784-
);
3785-
realSize = mcSize;
3843+
ucodeHeader->CpuSignature,
3844+
ucodeHeader->Revision,
3845+
ucodeHeader->DateDay,
3846+
ucodeHeader->DateMonth,
3847+
ucodeHeader->DateYear);
3848+
realSize = ucodeHeader->TotalSize;
37863849
return U_SUCCESS;
37873850
}
37883851

@@ -4214,38 +4277,15 @@ USTATUS FfsParser::parseIntelMicrocodeHeader(const UByteArray & microcode, const
42144277

42154278
const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)microcode.constData();
42164279

4217-
// Header version is 1
4218-
if (ucodeHeader->Version != INTEL_MICROCODE_HEADER_VERSION_1) {
4219-
return U_INVALID_MICROCODE;
4220-
}
4221-
4222-
// Reserved bytes are all zeroes
4223-
bool reservedBytesValid = true;
4224-
for (UINT8 i = 0; i < sizeof(ucodeHeader->Reserved); i++) {
4225-
if (ucodeHeader->Reserved[i] != 0x00) {
4226-
reservedBytesValid = false;
4227-
break;
4228-
}
4229-
}
4230-
if (!reservedBytesValid) {
4280+
if (!microcodeHeaderValid(ucodeHeader)) {
42314281
return U_INVALID_MICROCODE;
42324282
}
42334283

4234-
// Data size is multiple of 4
4235-
if (ucodeHeader->DataSize % 4 != 0) {
4236-
return U_INVALID_MICROCODE;
4237-
}
4238-
4239-
// TotalSize is greater then DataSize and is multiple of 1024
4240-
if (ucodeHeader->TotalSize <= ucodeHeader->DataSize || ucodeHeader->TotalSize % 1024 != 0) {
4241-
return U_INVALID_MICROCODE;
4242-
}
4243-
42444284
// We have enough data to fit the whole TotalSize
42454285
if ((UINT32)microcode.size() < ucodeHeader->TotalSize) {
42464286
return U_INVALID_MICROCODE;
42474287
}
4248-
4288+
42494289
// Valid microcode found
42504290
UINT32 dataSize = ucodeHeader->DataSize;
42514291
if (dataSize == 0)
@@ -4301,8 +4341,7 @@ USTATUS FfsParser::parseIntelMicrocodeHeader(const UByteArray & microcode, const
43014341
tempUcodeHeader->CpuSignature = entry->CpuSignature;
43024342
UINT32 entryCalculated = calculateChecksum32((const UINT32*)tempMicrocode.constData(), sizeof(INTEL_MICROCODE_HEADER) + dataSize);
43034343

4304-
4305-
extendedHeaderInfo += usprintf("\nCPU signature #%u: %08Xh\nCPU flags #%u: %08Xh\nChecksum #%u: %08Xh, ",
4344+
extendedHeaderInfo += usprintf("\nCPU signature #%u: %08Xh\nCPU flags #%u: %02Xh\nChecksum #%u: %08Xh, ",
43064345
i + 1, entry->CpuSignature,
43074346
i + 1, entry->CpuFlags,
43084347
i + 1, entry->Checksum)
@@ -4314,7 +4353,7 @@ USTATUS FfsParser::parseIntelMicrocodeHeader(const UByteArray & microcode, const
43144353
// Add info
43154354
UString name("Intel microcode");
43164355
UString info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nTail size: %Xh (%u)\n"
4317-
"Date: %02X.%02X.%04x\nCPU signature: %08Xh\nRevision: %08Xh\nLoader revision: %08Xh\nCPU flags: %08Xh\nChecksum: %08Xh, ",
4356+
"Date: %02X.%02X.%04x\nCPU signature: %08Xh\nRevision: %08Xh\nLoader revision: %08Xh\nCPU flags: %02Xh\nChecksum: %08Xh, ",
43184357
dataSize, dataSize,
43194358
header.size(), header.size(),
43204359
body.size(), body.size(),

common/ffsparser.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ class FfsParser
115115
USTATUS parseMeRegion(const UByteArray & me, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
116116
USTATUS parseBiosRegion(const UByteArray & bios, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
117117
USTATUS parsePdrRegion(const UByteArray & pdr, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
118+
USTATUS parseDevExp1Region(const UByteArray & devExp1, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
118119
USTATUS parseGenericRegion(const UINT8 subtype, const UByteArray & region, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
119120

120121
USTATUS parsePadFileBody(const UModelIndex & index);
@@ -141,6 +142,9 @@ class FfsParser
141142
USTATUS findNextRawAreaItem(const UModelIndex & index, const UINT32 localOffset, UINT8 & nextItemType, UINT32 & nextItemOffset, UINT32 & nextItemSize, UINT32 & nextItemAlternativeSize);
142143
UINT32 getFileSize(const UByteArray & volume, const UINT32 fileOffset, const UINT8 ffsVersion);
143144
UINT32 getSectionSize(const UByteArray & file, const UINT32 sectionOffset, const UINT8 ffsVersion);
145+
146+
USTATUS parseIntelMicrocodeHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
147+
BOOLEAN microcodeHeaderValid(const INTEL_MICROCODE_HEADER* ucodeHeader);
144148

145149
// Second pass
146150
USTATUS performSecondPass(const UModelIndex & index);
@@ -152,7 +156,7 @@ class FfsParser
152156
USTATUS parseResetVectorData();
153157
USTATUS parseFit(const UModelIndex & index);
154158
USTATUS parseVendorHashFile(const UByteArray & fileGuid, const UModelIndex & index);
155-
USTATUS parseIntelMicrocodeHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
159+
156160

157161
#ifdef U_ENABLE_FIT_PARSING_SUPPORT
158162
void findFitRecursive(const UModelIndex & index, UModelIndex & found, UINT32 & fitOffset);

common/fit.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ typedef struct INTEL_MICROCODE_HEADER_ {
7171
// that comprise the microcode update result in 00000000H.
7272

7373
UINT32 LoaderRevision;
74-
UINT32 CpuFlags;
74+
UINT8 CpuFlags;
75+
UINT8 CpuFlagsReserved[3];
7576
UINT32 DataSize; // Specifies the size of the encrypted data in bytes, and must be a multiple of DWORDs.
7677
// If this value is 00000000H, then the microcode update encrypted data is 2000 bytes (or 500 DWORDs).
7778

@@ -102,7 +103,8 @@ typedef struct INTEL_MICROCODE_EXTENDED_HEADER_ENTRY_ {
102103
// Checksum is correct when the summation of all DWORDs that comprise the created Extended Processor Patch results in 00000000H.
103104
} INTEL_MICROCODE_EXTENDED_HEADER_ENTRY;
104105

105-
#define INTEL_MICROCODE_HEADER_VERSION_1 0x00000001
106+
#define INTEL_MICROCODE_HEADER_VERSION_1 0x00000001
107+
#define INTEL_MICROCODE_MAX_LOADER_REVISION 0x00000010
106108

107109
#pragma pack(pop)
108110

common/nvramparser.cpp

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,7 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray &
533533
if (dataSize < sizeof(UINT32))
534534
return U_STORES_NOT_FOUND;
535535

536+
// TODO: add checks for restSize
536537
UINT32 offset = storeOffset;
537538
for (; offset < dataSize - sizeof(UINT32); offset++) {
538539
const UINT32* currentPos = (const UINT32*)(volume.constData() + offset);
@@ -646,24 +647,10 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray &
646647
break;
647648
}
648649
else if (*currentPos == INTEL_MICROCODE_HEADER_VERSION_1) {// Intel microcode
649-
// Check reserved bytes
650650
const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)currentPos;
651-
bool reservedBytesValid = true;
652-
for (UINT32 i = 0; i < sizeof(ucodeHeader->Reserved); i++)
653-
if (ucodeHeader->Reserved[i] != 0x00) {
654-
reservedBytesValid = false;
655-
break;
656-
}
657-
if (!reservedBytesValid)
658-
continue;
659-
660-
// Data size is multiple of 4
661-
if (ucodeHeader->DataSize % 4 != 0) {
662-
continue;
663-
}
664651

665652
// TotalSize is greater then DataSize and is multiple of 1024
666-
if (ucodeHeader->TotalSize <= ucodeHeader->DataSize || ucodeHeader->TotalSize % 1024 != 0) {
653+
if (FALSE == ffsParser->microcodeHeaderValid(ucodeHeader)) {
667654
continue;
668655
}
669656

0 commit comments

Comments
 (0)