On 08/18/20 04:10, Wang, Jian J wrote: > Laszlo, > > My apologies for the slow response. I'm not the original reporter but just > the BZ > submitter. And I didn't do deep analysis to this issue. The issues was > reported from > one internal team. Add John in loop to see if he knows more about it or not. > > My superficial understanding on such issue is that, if there's "potential" > issue in > theory and hard to reproduce, it's still worthy of using an alternative way > to replace > the original implementation with no "potential" issue at all. Maybe we don't > have > to prove old way is something wrong but must prove that the new way is really > safe.
I agree, thanks. It would be nice to hear more from the internal team about the originally reported (even if hard-to-trigger) issue. Thanks! Laszlo > > Regards, > Jian > >> -----Original Message----- >> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Laszlo Ersek >> Sent: Tuesday, August 18, 2020 12:53 AM >> To: Yao, Jiewen <jiewen....@intel.com>; devel@edk2.groups.io; >> xiewen...@huawei.com; Wang, Jian J <jian.j.w...@intel.com> >> Cc: huangmin...@huawei.com; songdongku...@huawei.com >> Subject: Re: [edk2-devel] [PATCH EDK2 v2 1/1] >> SecurityPkg/DxeImageVerificationLib:Enhanced verification of Offset >> >> Hi Jiewen, >> >> On 08/14/20 10:53, Yao, Jiewen wrote: >>>> To Jiewen, >>>> Sorry, I don't have environment to reproduce the issue. >>> >>> Please help me understand, if you don’t have environment to reproduce the >> issue, how do you guarantee that your patch does fix the problem and we don’t >> have any other vulnerabilities? >> >> The original bug report in >> <https://bugzilla.tianocore.org/show_bug.cgi?id=2215#c0> is seriously >> lacking. It does not go into detail about the alleged integer overflow. >> It does not quote the code, does not explain the control flow, does not >> identify the exact edk2 commit at which the vulnerability exists. >> >> The bug report also does not offer a reproducer. >> >> Additionally, the exact statement that the bug report does make, namely >> >> it's possible to overflow Offset back to 0 causing an endless loop >> >> is wrong (as far as I can tell anyway). It is not "OffSet" that can be >> overflowed to zero, but the *addend* that is added to OffSet can be >> overflowed to zero. Therefore the infinite loop will arise because >> OffSet remains stuck at its present value, and not because OffSet will >> be re-set to zero. >> >> For the reasons, we can only speculate as to what the actual problem is, >> unless Jian decides to join the discussion and clarifies what he had in >> mind originally. >> >> My understanding (or even "reconstruction") of the vulnerability is >> described above, and in the patches that I proposed. >> >> We can write a patch based on code analysis. It's possible to identify >> integer overflows based on code analysis, and it's possible to verify >> the correctness of fixes by code review. Obviously testing is always >> good, but many times, constructing reproducers for such issues that were >> found by code review, is difficult and time consuming. We can say that >> we don't fix vulnerabilities without reproducers, or we can say that we >> make an effort to fix them even if all we have is code analysis (and not >> a reproducer). >> >> So the above paragraph concerns "correctness". Regarding "completeness", >> I guarantee you that this patch does not fix *all* problems related to >> PE parsing. (See the other BZ tickets.) It does fix *one* issue with PE >> parsing. We can say that we try to fix such issues gradually (give >> different CVE numbers to different issues, and address them one at a >> time), or we can say that we rewrite PE parsing from the ground up. >> (BTW: I have seriously attempted that in the past, and I gave up, >> because the PE format is FUBAR.) >> >> In summary: >> >> - the problem statement is unclear, >> >> - it seems like there is indeed an integer overflow problem in the >> SecDataDir parsing loop, but it's uncertain whether the bug reporter had >> exactly that in mind >> >> - PE parsing is guaranteed to have other vulnerabilities elsewhere in >> edk2, but I'm currently unaware of other such issues in >> DxeImageVerificationLib specifically >> >> - even if there are other such problems (in DxeImageVerificationLib or >> elswehere), fixing this bug that we know about is likely worthwhile >> >> - for many such bugs, constructing a reproducer is difficult and time >> consuming; code analysis, and *regression-testing* are frequently the >> only tools we have. That doesn't mean we should ignore this class of bugs. >> >> (Fixing integer overflows retro-actively is more difficult than writing >> overflow-free code in the first place, but that ship has sailed; so we >> can only fight these bugs incrementally now, unless we can rewrite PE >> parsing with a new data structure from the ground up. Again I tried that >> and gave up, because the spec is not public, and what I did manage to >> learn about PE, showed that it was insanely over-engineered. I'm not >> saying that other binary / executable formats are better, of course.) >> >> Please check out my patches (inlined elsewhere in this thread), and >> comment whether you'd like me to post them to the list as a standalone >> series. >> >> Jian: it wouldn't hurt if you commented as well. >> >> Thanks >> Laszlo >> >>>> -----Original Message----- >>>> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of >> wenyi,xie >>>> via groups.io >>>> Sent: Friday, August 14, 2020 3:54 PM >>>> To: Laszlo Ersek <ler...@redhat.com>; devel@edk2.groups.io; Yao, Jiewen >>>> <jiewen....@intel.com>; Wang, Jian J <jian.j.w...@intel.com> >>>> Cc: huangmin...@huawei.com; songdongku...@huawei.com >>>> Subject: Re: [edk2-devel] [PATCH EDK2 v2 1/1] >>>> SecurityPkg/DxeImageVerificationLib:Enhanced verification of Offset >>>> >>>> To Laszlo, >>>> Thank you for your detailed description, I agree with what you analyzed and >> I'm >>>> OK with your patches, it's >>>> correct and much simpler. >>>> >>>> To Jiewen, >>>> Sorry, I don't have environment to reproduce the issue. >>>> >>>> Thanks >>>> Wenyi >>>> >>>> On 2020/8/14 2:50, Laszlo Ersek wrote: >>>>> On 08/13/20 13:55, Wenyi Xie wrote: >>>>>> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=2215 >>>>>> >>>>>> There is an integer overflow vulnerability in DxeImageVerificationHandler >>>>>> function when parsing the PE files attribute certificate table. In cases >>>>>> where WinCertificate->dwLength is sufficiently large, it's possible to >>>>>> overflow Offset back to 0 causing an endless loop. >>>>>> >>>>>> Check offset inbetween VirtualAddress and VirtualAddress + Size. >>>>>> Using SafeintLib to do offset addition with result check. >>>>>> >>>>>> Cc: Jiewen Yao <jiewen....@intel.com> >>>>>> Cc: Jian J Wang <jian.j.w...@intel.com> >>>>>> Cc: Laszlo Ersek <ler...@redhat.com> >>>>>> Signed-off-by: Wenyi Xie <xiewen...@huawei.com> >>>>>> --- >>>>>> SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf >> | >>>> 1 + >>>>>> SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h >> | >>>> 1 + >>>>>> SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c >> | >>>> 111 +++++++++++--------- >>>>>> 3 files changed, 63 insertions(+), 50 deletions(-) >>>>>> >>>>>> diff --git >>>> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf >>>> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf >>>>>> index 1e1a639857e0..a7ac4830b3d4 100644 >>>>>> --- >>>> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf >>>>>> +++ >>>> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf >>>>>> @@ -53,6 +53,7 @@ [LibraryClasses] >>>>>> SecurityManagementLib >>>>>> PeCoffLib >>>>>> TpmMeasurementLib >>>>>> + SafeIntLib >>>>>> >>>>>> [Protocols] >>>>>> gEfiFirmwareVolume2ProtocolGuid ## SOMETIMES_CONSUMES >>>>>> diff --git >>>> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h >>>> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h >>>>>> index 17955ff9774c..060273917d5d 100644 >>>>>> --- >>>> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h >>>>>> +++ >>>> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h >>>>>> @@ -23,6 +23,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent >>>>>> #include <Library/DevicePathLib.h> >>>>>> #include <Library/SecurityManagementLib.h> >>>>>> #include <Library/PeCoffLib.h> >>>>>> +#include <Library/SafeIntLib.h> >>>>>> #include <Protocol/FirmwareVolume2.h> >>>>>> #include <Protocol/DevicePath.h> >>>>>> #include <Protocol/BlockIo.h> >>>>>> diff --git >>>> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c >>>> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c >>>>>> index 36b87e16d53d..dbc03e28c05b 100644 >>>>>> --- >> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c >>>>>> +++ >>>> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c >>>>>> @@ -1658,6 +1658,10 @@ DxeImageVerificationHandler ( >>>>>> EFI_STATUS HashStatus; >>>>>> EFI_STATUS DbStatus; >>>>>> BOOLEAN IsFound; >>>>>> + UINT32 AlignedLength; >>>>>> + UINT32 Result; >>>>>> + EFI_STATUS AddStatus; >>>>>> + BOOLEAN IsAuthDataAssigned; >>>>>> >>>>>> SignatureList = NULL; >>>>>> SignatureListSize = 0; >>>>>> @@ -1667,6 +1671,7 @@ DxeImageVerificationHandler ( >>>>>> Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED; >>>>>> IsVerified = FALSE; >>>>>> IsFound = FALSE; >>>>>> + Result = 0; >>>>>> >>>>>> // >>>>>> // Check the image type and get policy setting. >>>>>> @@ -1850,9 +1855,10 @@ DxeImageVerificationHandler ( >>>>>> // The first certificate starts at offset >>>>>> (SecDataDir->VirtualAddress) from >> the >>>> start of the file. >>>>>> // >>>>>> for (OffSet = SecDataDir->VirtualAddress; >>>>>> - OffSet < (SecDataDir->VirtualAddress + SecDataDir->Size); >>>>>> - OffSet += (WinCertificate->dwLength + ALIGN_SIZE (WinCertificate- >>>>> dwLength))) { >>>>>> + (OffSet >= SecDataDir->VirtualAddress) && (OffSet < (SecDataDir- >>>>> VirtualAddress + SecDataDir->Size));) { >>>>>> + IsAuthDataAssigned = FALSE; >>>>>> WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet); >>>>>> + AlignedLength = WinCertificate->dwLength + ALIGN_SIZE >> (WinCertificate- >>>>> dwLength); >>>>> >>>>> I disagree with this patch. >>>>> >>>>> The primary reason for my disagreement is that the bug report >>>>> <https://bugzilla.tianocore.org/show_bug.cgi?id=2215#c0> is inexact, and >>>>> so this patch tries to fix the wrong thing. >>>>> >>>>> With edk2 master at commit 65904cdbb33c, it is *not* possible to >>>>> overflow the OffSet variable to zero with "WinCertificate->dwLength" >>>>> *purely*, and cause an endless loop. Note that we have (at commit >>>>> 65904cdbb33c): >>>>> >>>>> for (OffSet = SecDataDir->VirtualAddress; >>>>> OffSet < (SecDataDir->VirtualAddress + SecDataDir->Size); >>>>> OffSet += (WinCertificate->dwLength + ALIGN_SIZE (WinCertificate- >>>>> dwLength))) { >>>>> WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet); >>>>> if ((SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) <= sizeof >>>> (WIN_CERTIFICATE) || >>>>> (SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) < >> WinCertificate- >>>>> dwLength) { >>>>> break; >>>>> } >>>>> >>>>> The last sub-condition checks whether the Security Data Directory has >>>>> enough room left for "WinCertificate->dwLength". If not, then we break >>>>> out of the loop. >>>>> >>>>> If we *do* have enough room, that is: >>>>> >>>>> (SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) >= >> WinCertificate- >>>>> dwLength >>>>> >>>>> then we have (by adding OffSet to both sides): >>>>> >>>>> SecDataDir->VirtualAddress + SecDataDir->Size >= OffSet + >>>>> WinCertificate- >>>>> dwLength >>>>> >>>>> The left hand side is a known-good UINT32, and so incrementing OffSet (a >>>>> UINT32) *solely* by "WinCertificate->dwLength" (also a UINT32) does not >>>>> cause an overflow. >>>>> >>>>> Instead, the problem is with the alignment. The "if" statement checks >>>>> whether we have enough room for "dwLength", but then "OffSet" is >>>>> advanced by "dwLength" *aligned up* to the next multiple of 8. And that >>>>> may indeed cause various overflows. >>>>> >>>>> Now, the main problem with the present patch is that it does not fix one >>>>> of those overflows. Namely, consider that "dwLength" is very close to >>>>> MAX_UINT32 (or even think it's exactly MAX_UINT32). Then aligning it up >>>>> to the next multiple of 8 will yield 0. In other words, "AlignedLength" >>>>> will be zero. >>>>> >>>>> And when that happens, there's going to be an infinite loop just the >>>>> same: "OffSet" will not be zero, but it will be *stuck*. The >>>>> SafeUint32Add() call at the bottom will succeed, but it will not change >>>>> the value of "OffSet". >>>>> >>>>> More at the bottom. >>>>> >>>>> >>>>>> if ((SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) <= >>>>>> sizeof >>>> (WIN_CERTIFICATE) || >>>>>> (SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) < >>>> WinCertificate->dwLength) { >>>>>> break; >>>>>> @@ -1872,6 +1878,8 @@ DxeImageVerificationHandler ( >>>>>> } >>>>>> AuthData = PkcsCertData->CertData; >>>>>> AuthDataSize = PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData- >>> Hdr); >>>>>> + IsAuthDataAssigned = TRUE; >>>>>> + HashStatus = HashPeImageByType (AuthData, AuthDataSize); >>>>>> } else if (WinCertificate->wCertificateType == >> WIN_CERT_TYPE_EFI_GUID) >>>> { >>>>>> // >>>>>> // The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which >> is >>>> described in UEFI Spec. >>>>>> @@ -1880,72 +1888,75 @@ DxeImageVerificationHandler ( >>>>>> if (WinCertUefiGuid->Hdr.dwLength <= >>>> OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) { >>>>>> break; >>>>>> } >>>>>> - if (!CompareGuid (&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid)) >> { >>>>>> - continue; >>>>>> + if (CompareGuid (&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid)) >> { >>>>>> + AuthData = WinCertUefiGuid->CertData; >>>>>> + AuthDataSize = WinCertUefiGuid->Hdr.dwLength - >>>> OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData); >>>>>> + IsAuthDataAssigned = TRUE; >>>>>> + HashStatus = HashPeImageByType (AuthData, AuthDataSize); >>>>>> } >>>>>> - AuthData = WinCertUefiGuid->CertData; >>>>>> - AuthDataSize = WinCertUefiGuid->Hdr.dwLength - >>>> OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData); >>>>>> } else { >>>>>> if (WinCertificate->dwLength < sizeof (WIN_CERTIFICATE)) { >>>>>> break; >>>>>> } >>>>>> - continue; >>>>>> } >>>>>> >>>>>> - HashStatus = HashPeImageByType (AuthData, AuthDataSize); >>>>>> - if (EFI_ERROR (HashStatus)) { >>>>>> - continue; >>>>>> - } >>>>>> - >>>>>> - // >>>>>> - // Check the digital signature against the revoked certificate in >> forbidden >>>> database (dbx). >>>>>> - // >>>>>> - if (IsForbiddenByDbx (AuthData, AuthDataSize)) { >>>>>> - Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED; >>>>>> - IsVerified = FALSE; >>>>>> - break; >>>>>> - } >>>>>> - >>>>>> - // >>>>>> - // Check the digital signature against the valid certificate in >>>>>> allowed >>>> database (db). >>>>>> - // >>>>>> - if (!IsVerified) { >>>>>> - if (IsAllowedByDb (AuthData, AuthDataSize)) { >>>>>> - IsVerified = TRUE; >>>>>> + if (IsAuthDataAssigned && !EFI_ERROR (HashStatus)) { >>>>>> + // >>>>>> + // Check the digital signature against the revoked certificate in >> forbidden >>>> database (dbx). >>>>>> + // >>>>>> + if (IsForbiddenByDbx (AuthData, AuthDataSize)) { >>>>>> + Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED; >>>>>> + IsVerified = FALSE; >>>>>> + break; >>>>>> } >>>>>> - } >>>>>> >>>>>> - // >>>>>> - // Check the image's hash value. >>>>>> - // >>>>>> - DbStatus = IsSignatureFoundInDatabase ( >>>>>> - EFI_IMAGE_SECURITY_DATABASE1, >>>>>> - mImageDigest, >>>>>> - &mCertType, >>>>>> - mImageDigestSize, >>>>>> - &IsFound >>>>>> - ); >>>>>> - if (EFI_ERROR (DbStatus) || IsFound) { >>>>>> - Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND; >>>>>> - DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed >> but %s >>>> hash of image is found in DBX.\n", mHashTypeStr)); >>>>>> - IsVerified = FALSE; >>>>>> - break; >>>>>> - } >>>>>> + // >>>>>> + // Check the digital signature against the valid certificate in >>>>>> allowed >>>> database (db). >>>>>> + // >>>>>> + if (!IsVerified) { >>>>>> + if (IsAllowedByDb (AuthData, AuthDataSize)) { >>>>>> + IsVerified = TRUE; >>>>>> + } >>>>>> + } >>>>>> >>>>>> - if (!IsVerified) { >>>>>> + // >>>>>> + // Check the image's hash value. >>>>>> + // >>>>>> DbStatus = IsSignatureFoundInDatabase ( >>>>>> - EFI_IMAGE_SECURITY_DATABASE, >>>>>> + EFI_IMAGE_SECURITY_DATABASE1, >>>>>> mImageDigest, >>>>>> &mCertType, >>>>>> mImageDigestSize, >>>>>> &IsFound >>>>>> ); >>>>>> - if (!EFI_ERROR (DbStatus) && IsFound) { >>>>>> - IsVerified = TRUE; >>>>>> - } else { >>>>>> - DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed >> but >>>> signature is not allowed by DB and %s hash of image is not found in >> DB/DBX.\n", >>>> mHashTypeStr)); >>>>>> + if (EFI_ERROR (DbStatus) || IsFound) { >>>>>> + Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND; >>>>>> + DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed >>>> but %s hash of image is found in DBX.\n", mHashTypeStr)); >>>>>> + IsVerified = FALSE; >>>>>> + break; >>>>>> } >>>>>> + >>>>>> + if (!IsVerified) { >>>>>> + DbStatus = IsSignatureFoundInDatabase ( >>>>>> + EFI_IMAGE_SECURITY_DATABASE, >>>>>> + mImageDigest, >>>>>> + &mCertType, >>>>>> + mImageDigestSize, >>>>>> + &IsFound >>>>>> + ); >>>>>> + if (!EFI_ERROR (DbStatus) && IsFound) { >>>>>> + IsVerified = TRUE; >>>>>> + } else { >>>>>> + DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed >> but >>>> signature is not allowed by DB and %s hash of image is not found in >> DB/DBX.\n", >>>> mHashTypeStr)); >>>>>> + } >>>>>> + } >>>>>> + } >>>>>> + >>>>>> + AddStatus = SafeUint32Add (OffSet, AlignedLength, &Result); >>>>>> + if (EFI_ERROR (AddStatus)) { >>>>>> + break; >>>>>> } >>>>>> + OffSet = Result; >>>>>> } >>>>>> >>>>>> if (OffSet != (SecDataDir->VirtualAddress + SecDataDir->Size)) { >>>>>> >>>>> >>>>> There are other (smaller) reasons why I dislike this patch: >>>>> >>>>> - The "IsAuthDataAssigned" variable is superfluous; we could use the >>>>> existent "AuthData" variable (with a NULL-check and a NULL-assignment) >>>>> similarly. >>>>> >>>>> - The patch complicates / reorganizes the control flow needlessly. This >>>>> complication originates from placing the checked "OffSet" increment at >>>>> the bottom of the loop, which then requires the removal of all the >>>>> "continue" statements. But we don't need to check-and-increment at the >>>>> bottom. We can keep the increment inside the "for" statement, only >>>>> extend the *existent* room check (which I've quoted) to take the >>>>> alignment into account as well. If there is enough room for the >>>>> alignment in the security data directory, then that guarantees there >>>>> won't be a UINT32 overflow either. >>>>> >>>>> All in all, I'm proposing the following three patches instead. The first >>>>> two patches are preparation, the last patch is the fix. >>>>> >>>>> Patch#1: >>>>> >>>>>> From 11af0a104d34d39bf1b1aab256428ae4edbddd77 Mon Sep 17 >> 00:00:00 >>>> 2001 >>>>>> From: Laszlo Ersek <ler...@redhat.com> >>>>>> Date: Thu, 13 Aug 2020 19:11:39 +0200 >>>>>> Subject: [PATCH 1/3] SecurityPkg/DxeImageVerificationLib: extract >>>>>> SecDataDirEnd, SecDataDirLeft >>>>>> >>>>>> The following two quantities: >>>>>> >>>>>> SecDataDir->VirtualAddress + SecDataDir->Size >>>>>> SecDataDir->VirtualAddress + SecDataDir->Size - OffSet >>>>>> >>>>>> are used multiple times in DxeImageVerificationHandler(). Introduce >>>>>> helper >>>>>> variables for them: "SecDataDirEnd" and "SecDataDirLeft", respectively. >>>>>> This saves us multiple calculations and significantly simplifies the >>>>>> code. >>>>>> >>>>>> Note that all three summands above have type UINT32, therefore the new >>>>>> variables are also of type UINT32. >>>>>> >>>>>> This patch does not change behavior. >>>>>> >>>>>> (Note that the code already handles the case when the >>>>>> >>>>>> SecDataDir->VirtualAddress + SecDataDir->Size >>>>>> >>>>>> UINT32 addition overflows -- namely, in that case, the certificate loop >>>>>> is >>>>>> never entered, and the corruption check right after the loop fires.) >>>>>> >>>>>> Signed-off-by: Laszlo Ersek <ler...@redhat.com> >>>>>> --- >>>>>> SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c | >> 12 >>>> ++++++++---- >>>>>> 1 file changed, 8 insertions(+), 4 deletions(-) >>>>>> >>>>>> diff --git >>>> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c >>>> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c >>>>>> index 36b87e16d53d..8761980c88aa 100644 >>>>>> --- >> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c >>>>>> +++ >>>> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c >>>>>> @@ -1652,6 +1652,8 @@ DxeImageVerificationHandler ( >>>>>> UINT8 *AuthData; >>>>>> UINTN AuthDataSize; >>>>>> EFI_IMAGE_DATA_DIRECTORY *SecDataDir; >>>>>> + UINT32 SecDataDirEnd; >>>>>> + UINT32 SecDataDirLeft; >>>>>> UINT32 OffSet; >>>>>> CHAR16 *NameStr; >>>>>> RETURN_STATUS PeCoffStatus; >>>>>> @@ -1849,12 +1851,14 @@ DxeImageVerificationHandler ( >>>>>> // "Attribute Certificate Table". >>>>>> // The first certificate starts at offset >>>>>> (SecDataDir->VirtualAddress) from >> the >>>> start of the file. >>>>>> // >>>>>> + SecDataDirEnd = SecDataDir->VirtualAddress + SecDataDir->Size; >>>>>> for (OffSet = SecDataDir->VirtualAddress; >>>>>> - OffSet < (SecDataDir->VirtualAddress + SecDataDir->Size); >>>>>> + OffSet < SecDataDirEnd; >>>>>> OffSet += (WinCertificate->dwLength + ALIGN_SIZE (WinCertificate- >>>>> dwLength))) { >>>>>> WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet); >>>>>> - if ((SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) <= >>>>>> sizeof >>>> (WIN_CERTIFICATE) || >>>>>> - (SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) < >>>> WinCertificate->dwLength) { >>>>>> + SecDataDirLeft = SecDataDirEnd - OffSet; >>>>>> + if (SecDataDirLeft <= sizeof (WIN_CERTIFICATE) || >>>>>> + SecDataDirLeft < WinCertificate->dwLength) { >>>>>> break; >>>>>> } >>>>>> >>>>>> @@ -1948,7 +1952,7 @@ DxeImageVerificationHandler ( >>>>>> } >>>>>> } >>>>>> >>>>>> - if (OffSet != (SecDataDir->VirtualAddress + SecDataDir->Size)) { >>>>>> + if (OffSet != SecDataDirEnd) { >>>>>> // >>>>>> // The Size in Certificate Table or the attribute certificate table >>>>>> is >> corrupted. >>>>>> // >>>>>> -- >>>>>> 2.19.1.3.g30247aa5d201 >>>>>> >>>>> >>>>> Patch#2: >>>>> >>>>>> From 72012c065a53582f7df695e7b9730c45f49226c6 Mon Sep 17 00:00:00 >>>> 2001 >>>>>> From: Laszlo Ersek <ler...@redhat.com> >>>>>> Date: Thu, 13 Aug 2020 19:19:06 +0200 >>>>>> Subject: [PATCH 2/3] SecurityPkg/DxeImageVerificationLib: assign >>>>>> WinCertificate after size check >>>>>> >>>>>> Currently the (SecDataDirLeft <= sizeof (WIN_CERTIFICATE)) check only >>>>>> guards the de-referencing of the "WinCertificate" pointer. It does not >>>>>> guard the calculation of hte pointer itself: >>>>>> >>>>>> WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet); >>>>>> >>>>>> This is wrong; if we don't know for sure that we have enough room for a >>>>>> WIN_CERTIFICATE, then even creating such a pointer, not just >>>>>> de-referencing it, may invoke undefined behavior. >>>>>> >>>>>> Move the pointer calculation after the size check. >>>>>> >>>>>> Signed-off-by: Laszlo Ersek <ler...@redhat.com> >>>>>> --- >>>>>> SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c | >> 8 >>>> +++++--- >>>>>> 1 file changed, 5 insertions(+), 3 deletions(-) >>>>>> >>>>>> diff --git >>>> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c >>>> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c >>>>>> index 8761980c88aa..461ed7cfb5ac 100644 >>>>>> --- >> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c >>>>>> +++ >>>> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c >>>>>> @@ -1855,10 +1855,12 @@ DxeImageVerificationHandler ( >>>>>> for (OffSet = SecDataDir->VirtualAddress; >>>>>> OffSet < SecDataDirEnd; >>>>>> OffSet += (WinCertificate->dwLength + ALIGN_SIZE (WinCertificate- >>>>> dwLength))) { >>>>>> - WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet); >>>>>> SecDataDirLeft = SecDataDirEnd - OffSet; >>>>>> - if (SecDataDirLeft <= sizeof (WIN_CERTIFICATE) || >>>>>> - SecDataDirLeft < WinCertificate->dwLength) { >>>>>> + if (SecDataDirLeft <= sizeof (WIN_CERTIFICATE)) { >>>>>> + break; >>>>>> + } >>>>>> + WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet); >>>>>> + if (SecDataDirLeft < WinCertificate->dwLength) { >>>>>> break; >>>>>> } >>>>>> >>>>>> -- >>>>>> 2.19.1.3.g30247aa5d201 >>>>>> >>>>> >>>>> Patch#3: >>>>> >>>>>> From 0bbba15b84f8f9f2cdc770a89f418aaec6cfb31e Mon Sep 17 00:00:00 >>>> 2001 >>>>>> From: Laszlo Ersek <ler...@redhat.com> >>>>>> Date: Thu, 13 Aug 2020 19:34:33 +0200 >>>>>> Subject: [PATCH 3/3] SecurityPkg/DxeImageVerificationLib: catch >> alignment >>>>>> overflow (CVE-2019-14562) >>>>>> >>>>>> The DxeImageVerificationHandler() function currently checks whether >>>>>> "SecDataDir" has enough room for "WinCertificate->dwLength". However, >>>> for >>>>>> advancing "OffSet", "WinCertificate->dwLength" is aligned to the next >>>>>> multiple of 8. If "WinCertificate->dwLength" is large enough, the >>>>>> alignment will return 0, and "OffSet" will be stuck at the same value. >>>>>> >>>>>> Check whether "SecDataDir" has room left for both >>>>>> "WinCertificate->dwLength" and the alignment. >>>>>> >>>>>> Signed-off-by: Laszlo Ersek <ler...@redhat.com> >>>>>> --- >>>>>> SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c | >> 4 >>>> +++- >>>>>> 1 file changed, 3 insertions(+), 1 deletion(-) >>>>>> >>>>>> diff --git >>>> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c >>>> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c >>>>>> index 461ed7cfb5ac..e38eb981b7a0 100644 >>>>>> --- >> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c >>>>>> +++ >>>> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c >>>>>> @@ -1860,7 +1860,9 @@ DxeImageVerificationHandler ( >>>>>> break; >>>>>> } >>>>>> WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet); >>>>>> - if (SecDataDirLeft < WinCertificate->dwLength) { >>>>>> + if (SecDataDirLeft < WinCertificate->dwLength || >>>>>> + (SecDataDirLeft - WinCertificate->dwLength < >>>>>> + ALIGN_SIZE (WinCertificate->dwLength))) { >>>>>> break; >>>>>> } >>>>>> >>>>>> -- >>>>>> 2.19.1.3.g30247aa5d201 >>>>>> >>>>> >>>>> If Wenyi and the reviewers are OK with these patches, I can submit them >>>>> as a standalone patch series. >>>>> >>>>> Note that I do not have any reproducer for the issue; the best testing >>>>> that I could offer would be some light-weight Secure Boot regression >>>>> tests. >>>>> >>>>> Thanks >>>>> Laszlo >>>>> >>>>> >>>>> . >>>>> >>>> >>>> >>>> >>> >> >> >> > -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#64368): https://edk2.groups.io/g/devel/message/64368 Mute This Topic: https://groups.io/mt/76165658/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-