Hi,Jiewen, I modify the PE file again, this time it can pass the check in PeCoffLib and cause offset overflow.
First, create a PE file and sign it(only one signature), then using binary edit tool to modify content of PE file like below, 1.check the value of SecDataDir->VirtualAddress, in my PE file, it's 0xE000 2.changing SecDataDir->Size from 0x5F8 to 0xFFFF1FFC 3.changing WinCertificate->dwLength from 0x5F1 to 0xFFFF1FFB 4.padding PE file with 0 until the size of the file is 0xFFFFFFFC(it will make the PE file so large) OffSet + WinCertificate->dwLength + ALIGN_SIZE (WinCertificate->dwLength) is 0xE000 + 0xFFFF1FFB + 0x5 = 0x100000000 Below is the DEBUG code and log, in second loop the offset overflow and become 0 for (OffSet = SecDataDir->VirtualAddress; OffSet < (SecDataDir->VirtualAddress + SecDataDir->Size); OffSet += (WinCertificate->dwLength + ALIGN_SIZE (WinCertificate->dwLength))) { WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet); DEBUG((DEBUG_INFO, "OffSet=0x%x.\n", OffSet)); if ((SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) <= sizeof (WIN_CERTIFICATE) || (SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) < WinCertificate->dwLength) { break; } DEBUG((DEBUG_INFO, "WinCertificate->dwLength=0x%x, ALIGN_SIZE (WinCertificate->dwLength)=0x%x.\n", WinCertificate->dwLength, ALIGN_SIZE(WinCertificate->dwLength))); SecDataDir->VirtualAddress=0xE000, SecDataDir->Size=0xFFFF1FFC. OffSet=0xE000. WinCertificate->dwLength=0xFFFF1FFB, ALIGN_SIZE (WinCertificate->dwLength)=0x5. DxeImageVerificationLib: Image is signed but signature is not allowed by DB and SHA256 hash of image is notOffSet=0x0. WinCertificate->dwLength=0x5A4D, ALIGN_SIZE (WinCertificate->dwLength)=0x3. OffSet=0x5A50. WinCertificate->dwLength=0x9024, ALIGN_SIZE (WinCertificate->dwLength)=0x4. OffSet=0xEA78. WinCertificate->dwLength=0x0, ALIGN_SIZE (WinCertificate->dwLength)=0x0. The image doesn't pass verification: VenHw(5CF32E0B-8EDF-2E44-9CDA-93205E99EC1C,00000000)/VenHw(964E5B22-6459-11D2-8E39-00A0C969723B,00000000)/\signed_1234_4G.efi Regards Wenyi On 2020/8/28 14:43, Yao, Jiewen wrote: > Apology that I did not say clearly. > I mean you should not modify any code to perform an attack. > > I am not asking you to exploit the system. Attack here just means: to cause > system hang or buffer overflow. That is enough. > But you cannot modify code to remove any existing checker. > > Thank you > Yao Jiewen > >> -----Original Message----- >> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of wenyi,xie >> via groups.io >> Sent: Friday, August 28, 2020 2:18 PM >> To: Yao, Jiewen <jiewen....@intel.com>; devel@edk2.groups.io; Laszlo Ersek >> <ler...@redhat.com>; Wang, Jian J <jian.j.w...@intel.com> >> Cc: songdongku...@huawei.com; Mathews, John <john.math...@intel.com> >> Subject: Re: [edk2-devel] [PATCH EDK2 v2 1/1] >> SecurityPkg/DxeImageVerificationLib:Enhanced verification of Offset >> >> Hi,Jiewen, >> >> I don't really get the meaning "create a case that bypass all checks in >> PeCoffLib", >> do you mean I need to create a PE file that can bypass all check in PeCoffLib >> without modify any >> code and then cause the problem in DxeImageVerificationLib, or just modify >> some code in PeCoffLib to bypass check instead of removing the calling of >> PeCoffLoaderGetImageInfo. Would >> you mind explaining a little more specifically? As far as I tried, it's >> really hard to >> reproduce the issue without touching any code. >> >> Thanks >> Wenyi >> >> On 2020/8/28 11:50, Yao, Jiewen wrote: >>> HI Wenyi >>> Thank you very much to take time to reproduce. >>> >>> I am particular interested in below: >>> "As PE file is modified, function PeCoffLoaderGetImageInfo will return >> error, so I have to remove it so that for loop can be tested in >> DxeImageVerificationHandler." >>> >>> By design, the PeCoffLib should catch illegal PE/COFF image and return >>> error. >> (even it cannot catch all, it should catch most ones). >>> Other PE/COFF parser may rely on the checker in PeCoffLib and *no need* to >> duplicate all checkers. >>> As such, DxeImageVerificationLib (and other PeCoff consumer) just need >> checks what has passed the check in PeCoffLib. >>> >>> I don’t think you should remove the checker. If people can remove the >>> checker, >> I am sure the rest code will be vulnerable, according to the current design. >>> Could you please to create a case that bypass all checks in PeCoffLib, then >>> run >> into DxeImageVerificationLib and cause the problem? That would be more >> valuable for us. >>> >>> Thank you >>> Yao Jiewen >>> >>>> -----Original Message----- >>>> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of >> wenyi,xie >>>> via groups.io >>>> Sent: Friday, August 28, 2020 11:18 AM >>>> To: Laszlo Ersek <ler...@redhat.com>; Wang, Jian J >> <jian.j.w...@intel.com>; >>>> devel@edk2.groups.io; Yao, Jiewen <jiewen....@intel.com> >>>> Cc: songdongku...@huawei.com; Mathews, John >> <john.math...@intel.com> >>>> Subject: Re: [edk2-devel] [PATCH EDK2 v2 1/1] >>>> SecurityPkg/DxeImageVerificationLib:Enhanced verification of Offset >>>> >>>> Hi,Laszlo and everyone, >>>> >>>> These days I tried to reproduce the issue,and made some progress. I think >>>> there are two way to cause overflow from a mathematical point of view, >>>> 1.As Laszlo analysed before, if WinCertificate->dwLength is large enough, >> close >>>> to MAX_UINT32, then (WinCertificate->dwLength + ALIGN_SIZE >> (WinCertificate- >>>>> dwLength)) will cause overflow. >>>> 2.(WinCertificate->dwLength + ALIGN_SIZE (WinCertificate->dwLength)) is >> good, >>>> OffSet is good, but OffSet += (WinCertificate->dwLength + ALIGN_SIZE >>>> (WinCertificate->dwLength)) cause overflow. >>>> >>>> Here I choose the second way to reproduce the issue, I choose a PE file and >> sign >>>> it with my own db certificate. Then I use binary edit tool to modify the >>>> PE file >> like >>>> below, >>>> >>>> 1.change SecDataDir->Size from 0x5F8 to 0xFFFF1FFF >>>> 2.change WinCertificate->dwLength from 0x5F1 to 0xFFFF1FFE >>>> SecDataDir->VirtualAddress in my PE is 0xe000 and no need to change. >>>> >>>> As PE file is modified, function PeCoffLoaderGetImageInfo will return >>>> error, >> so I >>>> have to remove it so that for loop can be tested in >> DxeImageVerificationHandler. >>>> The log is as below, >>>> >>>> SecDataDir->VirtualAddress=0xE000, SecDataDir->Size=0xFFFF1FFF. >>>> (First Loop) >>>> OffSet=0xE000. >>>> WinCertificate->dwLength=0xFFFF1FFE, ALIGN_SIZE (WinCertificate- >>>>> dwLength)=0x2. >>>> (Second Loop) >>>> OffSet=0x0. >>>> WinCertificate->dwLength=0x5A4D, ALIGN_SIZE (WinCertificate- >>>>> dwLength)=0x3. >>>> (Third Loop) >>>> OffSet=0x5A50. >>>> WinCertificate->dwLength=0x9024, ALIGN_SIZE (WinCertificate- >>>>> dwLength)=0x4. >>>> (Forth Loop) >>>> OffSet=0xEA78. >>>> WinCertificate->dwLength=0xAFAFAFAF, ALIGN_SIZE (WinCertificate- >>>>> dwLength)=0x1. >>>> (Fifth Loop) >>>> OffSet=0xAFB09A28. >>>> >>>> As I modify SecDataDir->Size and WinCertificate->dwLength, so in first loop >> the >>>> condition check whether the Security Data Directory has enough room left >> for >>>> "WinCertificate->dwLength" is ok. >>>> >>>> if ((SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) <= sizeof >>>> (WIN_CERTIFICATE) || >>>> (SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) < >>>> WinCertificate- >>>>> dwLength) { >>>> break; >>>> } >>>> >>>> In the beginning of second loop, WinCertificate->dwLength + ALIGN_SIZE >>>> (WinCertificate->dwLength) is 0xFFFF2000, offset is 0xE000 >>>> >>>> OffSet += (WinCertificate->dwLength + ALIGN_SIZE (WinCertificate- >>> dwLength)) >>>> >>>> Offset now is 0 and overflow happens. So even if my PE only have one >> signature, >>>> the for loop is still going untill exception happens. >>>> >>>> >>>> I can't reproduce the issue using the first way, because if WinCertificate- >>>>> dwLength is close to MAX_UINT32, it means SecDataDir->Size should also >> close >>>> to MAX_UINT32, or the condition check >>>> "(SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) < WinCertificate- >>>>> dwLength" will break. But if SecDataDir->Size is very large, SecDataDir- >>>>> VirtualAddress have to be smaller than 8 bytes, >>>> because SecDataDir->VirtualAddress + SecDataDir->Size < MAX_UINT32. >>>> SecDataDir->VirtualAddress is the beginning address of the signature, and >> before >>>> SecDataDir->VirtualAddress is the content of origin PE file, I think it's >> impossible >>>> that the size of PE file is only 8 bytes. >>>> >>>> As I changed the one line code in DxeImageVerificationHandler to reproduce >> the >>>> issue, I'm not sure whether it's ok. >>>> >>>> Thanks >>>> Wenyi >>>> >>>> On 2020/8/19 17:26, Laszlo Ersek wrote: >>>>> On 08/18/20 17:18, Mathews, John wrote: >>>>>> I dug up the original report details. This was noted as a concern >>>>>> during a >>>> source code inspection. There was no demonstration of how it might be >>>> triggered. >>>>>> >>>>>> " There is an integer overflow vulnerability in the >>>> 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." >>>>>> >>>>>> The recommendation was to add stricter checking of "Offset" and the >>>> embedded length fields of certificate data >>>>>> before using them. >>>>> >>>>> Thanks for checking! >>>>> >>>>> Laszlo >>>>> >>>>>> >>>>>> >>>>>> >>>>>> -----Original Message----- >>>>>> From: Laszlo Ersek <ler...@redhat.com> >>>>>> Sent: Tuesday, August 18, 2020 1:59 AM >>>>>> To: Wang, Jian J <jian.j.w...@intel.com>; devel@edk2.groups.io; Yao, >>>> Jiewen <jiewen....@intel.com>; xiewen...@huawei.com >>>>>> Cc: huangmin...@huawei.com; songdongku...@huawei.com; Mathews, >>>> John <john.math...@intel.com> >>>>>> Subject: Re: [edk2-devel] [PATCH EDK2 v2 1/1] >>>> SecurityPkg/DxeImageVerificationLib:Enhanced verification of Offset >>>>>> >>>>>> 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/DxeImageVerificationL >>>>>>>>>>>> ib.inf >>>>>>>> | >>>>>>>>>> 1 + >>>>>>>>>>>> >>>>>>>>>>>> >> SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>>>> ib.h >>>>>>>> | >>>>>>>>>> 1 + >>>>>>>>>>>> >>>>>>>>>>>> >> SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>>>> ib.c >>>>>>>> | >>>>>>>>>> 111 +++++++++++--------- >>>>>>>>>>>> 3 files changed, 63 insertions(+), 50 deletions(-) >>>>>>>>>>>> >>>>>>>>>>>> diff --git >>>>>>>>>> >> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>> ib.inf >>>>>>>>>> >> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>> ib.inf >>>>>>>>>>>> index 1e1a639857e0..a7ac4830b3d4 100644 >>>>>>>>>>>> --- >>>>>>>>>> >> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>> ib.inf >>>>>>>>>>>> +++ >>>>>>>>>> >> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>> ib.inf >>>>>>>>>>>> @@ -53,6 +53,7 @@ [LibraryClasses] >>>>>>>>>>>> SecurityManagementLib >>>>>>>>>>>> PeCoffLib >>>>>>>>>>>> TpmMeasurementLib >>>>>>>>>>>> + SafeIntLib >>>>>>>>>>>> >>>>>>>>>>>> [Protocols] >>>>>>>>>>>> gEfiFirmwareVolume2ProtocolGuid ## >> SOMETIMES_CONSUMES >>>>>>>>>>>> diff --git >>>>>>>>>> >> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>> ib.h >>>>>>>>>> >> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>> ib.h >>>>>>>>>>>> index 17955ff9774c..060273917d5d 100644 >>>>>>>>>>>> --- >>>>>>>>>> >> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>> ib.h >>>>>>>>>>>> +++ >>>>>>>>>> >> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>> ib.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/DxeImageVerificationL >>>>>>>>>> ib.c >>>>>>>>>> >> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>> ib.c >>>>>>>>>>>> index 36b87e16d53d..dbc03e28c05b 100644 >>>>>>>>>>>> --- >>>>>>>> >> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib >>>>>>>> .c >>>>>>>>>>>> +++ >>>>>>>>>> >> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>> ib.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/DxeImageVerificationL >>>>>>>>>>>> ib.c | >>>>>>>> 12 >>>>>>>>>> ++++++++---- >>>>>>>>>>>> 1 file changed, 8 insertions(+), 4 deletions(-) >>>>>>>>>>>> >>>>>>>>>>>> diff --git >>>>>>>>>> >> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>> ib.c >>>>>>>>>> >> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>> ib.c >>>>>>>>>>>> index 36b87e16d53d..8761980c88aa 100644 >>>>>>>>>>>> --- >>>>>>>> >> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib >>>>>>>> .c >>>>>>>>>>>> +++ >>>>>>>>>> >> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>> ib.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/DxeImageVerificationL >>>>>>>>>>>> ib.c | >>>>>>>> 8 >>>>>>>>>> +++++--- >>>>>>>>>>>> 1 file changed, 5 insertions(+), 3 deletions(-) >>>>>>>>>>>> >>>>>>>>>>>> diff --git >>>>>>>>>> >> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>> ib.c >>>>>>>>>> >> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>> ib.c >>>>>>>>>>>> index 8761980c88aa..461ed7cfb5ac 100644 >>>>>>>>>>>> --- >>>>>>>> >> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib >>>>>>>> .c >>>>>>>>>>>> +++ >>>>>>>>>> >> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>> ib.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/DxeImageVerificationL >>>>>>>>>>>> ib.c | >>>>>>>> 4 >>>>>>>>>> +++- >>>>>>>>>>>> 1 file changed, 3 insertions(+), 1 deletion(-) >>>>>>>>>>>> >>>>>>>>>>>> diff --git >>>>>>>>>> >> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>> ib.c >>>>>>>>>> >> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>> ib.c >>>>>>>>>>>> index 461ed7cfb5ac..e38eb981b7a0 100644 >>>>>>>>>>>> --- >>>>>>>> >> a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib >>>>>>>> .c >>>>>>>>>>>> +++ >>>>>>>>>> >> b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationL >>>>>>>>>> ib.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 (#64828): https://edk2.groups.io/g/devel/message/64828 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] -=-=-=-=-=-=-=-=-=-=-=-