X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=SecurityPkg%2FLibrary%2FDxeImageVerificationLib%2FDxeImageVerificationLib.c;h=2a54296134b5835ed7f5645f58fd79fbf6d9a189;hp=6e3e9eea95200a7a5b73ea230ffc39de3bbae490;hb=de2447dd4ca93ca37ff067c325e478dc586235ca;hpb=28186d45660c92b8d98b8b19b5f8e6ff71ea5fba diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c index 6e3e9eea95..2a54296134 100644 --- a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c +++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c @@ -67,7 +67,7 @@ HASH_TABLE mHash[] = { **/ EFI_STATUS EFIAPI -ImageRead ( +DxeImageVerificationLibImageRead ( IN VOID *FileHandle, IN UINTN FileOffset, IN OUT UINTN *ReadSize, @@ -251,8 +251,8 @@ HashPeImage ( EFI_IMAGE_SECTION_HEADER *SectionHeader; UINTN Index; UINTN Pos; - UINTN SumOfSectionBytes; - EFI_IMAGE_SECTION_HEADER *SectionCache; + UINT32 CertSize; + UINT32 NumberOfRvaAndSizes; HashCtx = NULL; SectionHeader = NULL; @@ -292,11 +292,26 @@ HashPeImage ( if (!Status) { goto Done; } + // // Measuring PE/COFF Image Header; // But CheckSum field and SECURITY data directory (certificate) are excluded // - Magic = mNtHeader.Pe32->OptionalHeader.Magic; + if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value + // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the + // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC + // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC + // + Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; + } else { + // + // Get the magic value from the PE/COFF Optional Header + // + Magic = mNtHeader.Pe32->OptionalHeader.Magic; + } + // // 3. Calculate the distance from the base of the image header to the image checksum address. // 4. Hash the image header from its base to beginning of the image checksum. @@ -307,11 +322,13 @@ HashPeImage ( // Use PE32 offset. // HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - HashBase); + NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes; } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { // // Use PE32+ offset. // HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - HashBase); + NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; } else { // // Invalid header magic number. @@ -324,51 +341,86 @@ HashPeImage ( if (!Status) { goto Done; } + // // 5. Skip over the image checksum (it occupies a single ULONG). - // 6. Get the address of the beginning of the Cert Directory. - // 7. Hash everything from the end of the checksum to the start of the Cert Directory. // - if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { // - // Use PE32 offset. + // 6. Since there is no Cert Directory in optional header, hash everything + // from the end of the checksum to the end of image header. // - HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase); + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase); + } else { + // + // Use PE32+ offset. + // + HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase); + } + + if (HashSize != 0) { + Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); + if (!Status) { + goto Done; + } + } } else { // - // Use PE32+ offset. + // 7. Hash everything from the end of the checksum to the start of the Cert Directory. // - HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase); - } + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase); + } else { + // + // Use PE32+ offset. + // + HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase); + } + + if (HashSize != 0) { + Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); + if (!Status) { + goto Done; + } + } - Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); - if (!Status) { - goto Done; - } - // - // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.) - // 9. Hash everything from the end of the Cert Directory to the end of image header. - // - if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset - // - HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; - HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase); - } else { // - // Use PE32+ offset. + // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.) + // 9. Hash everything from the end of the Cert Directory to the end of image header. // - HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; - HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase); - } + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; + HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase); + } else { + // + // Use PE32+ offset. + // + HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; + HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase); + } - Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); - if (!Status) { - goto Done; + if (HashSize != 0) { + Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); + if (!Status) { + goto Done; + } + } } + // // 10. Set the SUM_OF_BYTES_HASHED to the size of the header. // @@ -393,20 +445,6 @@ HashPeImage ( mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader ); - SectionCache = Section; - for (Index = 0, SumOfSectionBytes = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++, SectionCache++) { - SumOfSectionBytes += SectionCache->SizeOfRawData; - } - - // - // Sanity check for file corruption. Sections raw data size should be smaller - // than Image Size. - // - if (SumOfSectionBytes >= mImageSize) { - Status = FALSE; - goto Done; - } - // // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER // structures in the image. The 'NumberOfSections' field of the image @@ -465,37 +503,36 @@ HashPeImage ( // if (mImageSize > SumOfBytesHashed) { HashBase = mImageBase + SumOfBytesHashed; - if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - if (mImageSize - SumOfBytesHashed < mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) { - Status = FALSE; - goto Done; - } - // - // Use PE32 offset. - // - HashSize = (UINTN)( - mImageSize - - mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - - SumOfBytesHashed); + + if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { + CertSize = 0; } else { - if (mImageSize - SumOfBytesHashed < mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) { - Status = FALSE; - goto Done; + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + CertSize = mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; + } else { + // + // Use PE32+ offset. + // + CertSize = mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; } - // - // Use PE32+ offset. - // - HashSize = (UINTN)( - mImageSize - - mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - - SumOfBytesHashed); } - Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); - if (!Status) { + if (mImageSize > CertSize + SumOfBytesHashed) { + HashSize = (UINTN) (mImageSize - CertSize - SumOfBytesHashed); + + Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); + if (!Status) { + goto Done; + } + } else if (mImageSize < CertSize + SumOfBytesHashed) { + Status = FALSE; goto Done; } } + Status = mHash[HashAlg].HashFinal(HashCtx, mImageDigest); Done: @@ -527,6 +564,10 @@ HashPeImageByType ( PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress); + if (PkcsCertData->Hdr.dwLength < sizeof (WIN_CERTIFICATE_EFI_PKCS) + 32) { + return EFI_UNSUPPORTED; + } + for (Index = 0; Index < HASHALG_MAX; Index++) { // // Check the Hash algorithm in PE/COFF Authenticode. @@ -547,6 +588,10 @@ HashPeImageByType ( continue; } + if (PkcsCertData->Hdr.dwLength < sizeof (WIN_CERTIFICATE_EFI_PKCS) + 32 + mHash[Index].OidLength) { + return EFI_UNSUPPORTED; + } + if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) { break; } @@ -915,7 +960,7 @@ IsPkcsSignedDataVerifiedBySignatureList ( // VerifyStatus = AuthenticodeVerify ( PkcsCertData->CertData, - mSecDataDir->Size - sizeof(PkcsCertData->Hdr), + PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr), RootCert, RootCertSize, mImageDigest, @@ -1034,7 +1079,7 @@ VerifyCertUefiGuid ( // // Get KEK database variable. // - KekList = GetEfiGlobalVariable (EFI_KEY_EXCHANGE_KEY_NAME); + GetEfiGlobalVariable2 (EFI_KEY_EXCHANGE_KEY_NAME, (VOID**)&KekList, NULL); if (KekList == NULL) { return EFI_SECURITY_VIOLATION; } @@ -1170,19 +1215,21 @@ DxeImageVerificationHandler ( IN UINTN FileSize ) { - EFI_STATUS Status; - UINT16 Magic; - EFI_IMAGE_DOS_HEADER *DosHdr; - EFI_STATUS VerifyStatus; - UINT8 *SetupMode; - EFI_SIGNATURE_LIST *SignatureList; - UINTN SignatureListSize; - EFI_SIGNATURE_DATA *Signature; - EFI_IMAGE_EXECUTION_ACTION Action; - WIN_CERTIFICATE *WinCertificate; - UINT32 Policy; - UINT8 *SecureBootEnable; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + EFI_STATUS Status; + UINT16 Magic; + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_STATUS VerifyStatus; + UINT8 *SetupMode; + EFI_SIGNATURE_LIST *SignatureList; + UINTN SignatureListSize; + EFI_SIGNATURE_DATA *Signature; + EFI_IMAGE_EXECUTION_ACTION Action; + WIN_CERTIFICATE *WinCertificate; + UINT32 Policy; + UINT8 *SecureBootEnable; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + UINT32 NumberOfRvaAndSizes; + UINT32 CertSize; if (File == NULL) { return EFI_INVALID_PARAMETER; @@ -1227,7 +1274,7 @@ DxeImageVerificationHandler ( return EFI_ACCESS_DENIED; } - SecureBootEnable = GetVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid); + GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL); // // Skip verification if SecureBootEnable variable doesn't exist. // @@ -1243,7 +1290,9 @@ DxeImageVerificationHandler ( return EFI_SUCCESS; } - SetupMode = GetEfiGlobalVariable (EFI_SETUP_MODE_NAME); + FreePool (SecureBootEnable); + + GetEfiGlobalVariable2 (EFI_SETUP_MODE_NAME, (VOID**)&SetupMode, NULL); // // SetupMode doesn't exist means no AuthVar driver is dispatched, @@ -1260,19 +1309,22 @@ DxeImageVerificationHandler ( FreePool (SetupMode); return EFI_SUCCESS; } + + FreePool (SetupMode); + // // Read the Dos header. // if (FileBuffer == NULL) { - FreePool (SetupMode); return EFI_INVALID_PARAMETER; } + mImageBase = (UINT8 *) FileBuffer; mImageSize = FileSize; ZeroMem (&ImageContext, sizeof (ImageContext)); ImageContext.Handle = (VOID *) FileBuffer; - ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) ImageRead; + ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeImageVerificationLibImageRead; // // Get information about the image being loaded @@ -1285,7 +1337,9 @@ DxeImageVerificationHandler ( goto Done; } - DosHdr = (EFI_IMAGE_DOS_HEADER *) mImageBase; + Status = EFI_ACCESS_DENIED; + + DosHdr = (EFI_IMAGE_DOS_HEADER *) mImageBase; if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { // // DOS image header is present, @@ -1303,37 +1357,43 @@ DxeImageVerificationHandler ( // // It is not a valid Pe/Coff file. // - return EFI_ACCESS_DENIED; + goto Done; } - Magic = mNtHeader.Pe32->OptionalHeader.Magic; - if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { // - // Use PE32 offset. - // - mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; - } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value + // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the + // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC + // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC // - // Use PE32+ offset. - // - mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; + Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; } else { // - // Invalid header magic number. + // Get the magic value from the PE/COFF Optional Header // - Status = EFI_INVALID_PARAMETER; - goto Done; + Magic = mNtHeader.Pe32->OptionalHeader.Magic; } - - if (mSecDataDir->VirtualAddress >= mImageSize) { + + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { // - // Sanity check to see if this file is corrupted. + // Use PE32 offset. // - Status = EFI_INVALID_PARAMETER; - goto Done; + NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes; + if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { + mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; + } + } else { + // + // Use PE32+ offset. + // + NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; + if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { + mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; + } } - if (mSecDataDir->Size == 0) { + if ((mSecDataDir == NULL) || ((mSecDataDir != NULL) && (mSecDataDir->Size == 0))) { // // This image is not signed. // @@ -1345,8 +1405,6 @@ DxeImageVerificationHandler ( // // Image Hash is in forbidden database (DBX). // - Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED; - Status = EFI_ACCESS_DENIED; goto Done; } @@ -1360,8 +1418,6 @@ DxeImageVerificationHandler ( // // Image Hash is not found in both forbidden and allowed database. // - Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED; - Status = EFI_ACCESS_DENIED; goto Done; } @@ -1370,9 +1426,20 @@ DxeImageVerificationHandler ( // WinCertificate = (WIN_CERTIFICATE *) (mImageBase + mSecDataDir->VirtualAddress); + CertSize = sizeof (WIN_CERTIFICATE); + + if ((mSecDataDir->Size <= CertSize) || (mSecDataDir->Size < WinCertificate->dwLength)) { + goto Done; + } + switch (WinCertificate->wCertificateType) { case WIN_CERT_TYPE_EFI_GUID: + CertSize = sizeof (WIN_CERTIFICATE_UEFI_GUID) + sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256) - sizeof (UINT8); + if (WinCertificate->dwLength < CertSize) { + goto Done; + } + // // Verify UEFI GUID type. // @@ -1387,7 +1454,7 @@ DxeImageVerificationHandler ( // // Verify Pkcs signed data type. // - Status = HashPeImageByType(); + Status = HashPeImageByType(); if (EFI_ERROR (Status)) { goto Done; } @@ -1406,7 +1473,6 @@ DxeImageVerificationHandler ( break; default: - Status = EFI_ACCESS_DENIED; goto Done; } // @@ -1474,8 +1540,6 @@ Done: FreePool (SignatureList); } - FreePool (SetupMode); - return Status; } @@ -1508,7 +1572,7 @@ VariableWriteCallBack ( // If this library is built-in, it means firmware has capability to perform // driver signing verification. // - SecureBootModePtr = GetEfiGlobalVariable (EFI_SECURE_BOOT_MODE_NAME); + GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBootModePtr, NULL); if (SecureBootModePtr == NULL) { SecureBootMode = SECURE_BOOT_MODE_DISABLE; //