REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1020
The function MicrocodeDetect may receive untrusted input. Add verification logic to check Microcode Payload Header. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Chen A Chen <chen.a.c...@intel.com> Cc: Ray Ni <ray...@intel.com> Cc: Eric Dong <eric.d...@intel.com> --- UefiCpuPkg/Library/MpInitLib/Microcode.c | 190 +++++++++++++++++++++---------- 1 file changed, 127 insertions(+), 63 deletions(-) diff --git a/UefiCpuPkg/Library/MpInitLib/Microcode.c b/UefiCpuPkg/Library/MpInitLib/Microcode.c index 5f9ae22794..1d5e964791 100644 --- a/UefiCpuPkg/Library/MpInitLib/Microcode.c +++ b/UefiCpuPkg/Library/MpInitLib/Microcode.c @@ -32,6 +32,69 @@ GetCurrentMicrocodeSignature ( return BiosSignIdMsr.Bits.MicrocodeUpdateSignature; } +/** + Verify Microcode. + + @param[in] MicrocodeHeader Point to the Microcode payload buffer. + + @retval TRUE Valid payload + @retval FALSE Invalid payload +**/ +BOOLEAN +VerifyMicrocodeHeader ( + IN CPU_MICROCODE_HEADER *MicrocodeHeader + ) +{ + UINTN TotalSize; + UINTN DataSize; + + if (MicrocodeHeader == NULL) { + return FALSE; + } + + /// + /// Verify Version + /// + if (MicrocodeHeader->HeaderVersion != 0x1) { + return FALSE; + } + if (MicrocodeHeader->LoaderRevision != 0x1) { + return FALSE; + } + + /// + /// Verify TotalSize + /// + if (MicrocodeHeader->DataSize == 0) { + TotalSize = 2048; + } else { + TotalSize = MicrocodeHeader->TotalSize; + } + if (TotalSize <= sizeof (CPU_MICROCODE_HEADER)) { + return FALSE; + } + if ((TotalSize & (SIZE_1KB - 1)) != 0) { + return FALSE; + } + + /// + /// Verify DataSize + /// + if (MicrocodeHeader->DataSize == 0) { + DataSize = 2048 - sizeof (CPU_MICROCODE_HEADER); + } else { + DataSize = MicrocodeHeader->DataSize; + } + if (DataSize > TotalSize - sizeof (CPU_MICROCODE_HEADER)) { + return FALSE; + } + if ((DataSize & 0x3) != 0) { + return FALSE; + } + + return TRUE; +} + /** Detect whether specified processor can find matching microcode patch and load it. @@ -166,6 +229,18 @@ MicrocodeDetect ( // CorrectMicrocode = FALSE; + if (!VerifyMicrocodeHeader (MicrocodeEntryPoint)) { + // + // It is the padding data between the microcode patches for microcode patches alignment. + // Because the microcode patch is the multiple of 1-KByte, the padding data should not + // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode + // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to + // find the next possible microcode patch header. + // + MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB); + continue; + } + // // Save an in-complete CheckSum32 from CheckSum Part1 for common parts. // @@ -184,90 +259,79 @@ MicrocodeDetect ( InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorFlags; InCompleteCheckSum32 -= MicrocodeEntryPoint->Checksum; - if (MicrocodeEntryPoint->HeaderVersion == 0x1) { + // + // It is the microcode header. It is not the padding data between microcode patches + // because the padding data should not include 0x00000001 and it should be the repeated + // byte format (like 0xXYXYXYXY....). + // + if (MicrocodeEntryPoint->ProcessorSignature.Uint32 == Eax.Uint32 && + MicrocodeEntryPoint->UpdateRevision > LatestRevision && + (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId)) + ) { // - // It is the microcode header. It is not the padding data between microcode patches - // because the padding data should not include 0x00000001 and it should be the repeated - // byte format (like 0xXYXYXYXY....). + // Calculate CheckSum Part1. // - if (MicrocodeEntryPoint->ProcessorSignature.Uint32 == Eax.Uint32 && - MicrocodeEntryPoint->UpdateRevision > LatestRevision && - (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId)) - ) { + CheckSum32 = InCompleteCheckSum32; + CheckSum32 += MicrocodeEntryPoint->ProcessorSignature.Uint32; + CheckSum32 += MicrocodeEntryPoint->ProcessorFlags; + CheckSum32 += MicrocodeEntryPoint->Checksum; + if (CheckSum32 == 0) { + CorrectMicrocode = TRUE; + ProcessorFlags = MicrocodeEntryPoint->ProcessorFlags; + } + } else if ((MicrocodeEntryPoint->DataSize != 0) && + (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) { + ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize + + sizeof (CPU_MICROCODE_HEADER)); + if (ExtendedTableLength != 0) { // - // Calculate CheckSum Part1. + // Extended Table exist, check if the CPU in support list // - CheckSum32 = InCompleteCheckSum32; - CheckSum32 += MicrocodeEntryPoint->ProcessorSignature.Uint32; - CheckSum32 += MicrocodeEntryPoint->ProcessorFlags; - CheckSum32 += MicrocodeEntryPoint->Checksum; - if (CheckSum32 == 0) { - CorrectMicrocode = TRUE; - ProcessorFlags = MicrocodeEntryPoint->ProcessorFlags; - } - } else if ((MicrocodeEntryPoint->DataSize != 0) && - (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) { - ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize + - sizeof (CPU_MICROCODE_HEADER)); - if (ExtendedTableLength != 0) { - // - // Extended Table exist, check if the CPU in support list - // - ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint) - + MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER)); + ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint) + + MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER)); + // + // Calculate Extended Checksum + // + if ((ExtendedTableLength % 4) == 0) { // - // Calculate Extended Checksum + // Calculate CheckSum Part2. // - if ((ExtendedTableLength % 4) == 0) { + CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength); + if (CheckSum32 == 0) { // - // Calculate CheckSum Part2. + // Checksum correct // - CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength); - if (CheckSum32 == 0) { + ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount; + ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1); + for (Index = 0; Index < ExtendedTableCount; Index ++) { // - // Checksum correct + // Calculate CheckSum Part3. // - ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount; - ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1); - for (Index = 0; Index < ExtendedTableCount; Index ++) { + CheckSum32 = InCompleteCheckSum32; + CheckSum32 += ExtendedTable->ProcessorSignature.Uint32; + CheckSum32 += ExtendedTable->ProcessorFlag; + CheckSum32 += ExtendedTable->Checksum; + if (CheckSum32 == 0) { // - // Calculate CheckSum Part3. + // Verify Header // - CheckSum32 = InCompleteCheckSum32; - CheckSum32 += ExtendedTable->ProcessorSignature.Uint32; - CheckSum32 += ExtendedTable->ProcessorFlag; - CheckSum32 += ExtendedTable->Checksum; - if (CheckSum32 == 0) { + if ((ExtendedTable->ProcessorSignature.Uint32 == Eax.Uint32) && + (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) { // - // Verify Header + // Find one // - if ((ExtendedTable->ProcessorSignature.Uint32 == Eax.Uint32) && - (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) { - // - // Find one - // - CorrectMicrocode = TRUE; - ProcessorFlags = ExtendedTable->ProcessorFlag; - break; - } + CorrectMicrocode = TRUE; + ProcessorFlags = ExtendedTable->ProcessorFlag; + break; } - ExtendedTable ++; } + ExtendedTable ++; } } } } - } else { - // - // It is the padding data between the microcode patches for microcode patches alignment. - // Because the microcode patch is the multiple of 1-KByte, the padding data should not - // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode - // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to - // find the next possible microcode patch header. - // - MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB); - continue; } + // // Get the next patch. // -- 2.16.2.windows.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel