On 2020/8/14 16: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?

Hi, Jiewen,
You're right, as I can't reproduce the issue, I can't guarantee my patches can 
fix the problem.
And as Laszlo analyzed, my patches can't solve overflow issue indeed.

Sincerely
Wenyi
> 
> 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 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 (#64289): https://edk2.groups.io/g/devel/message/64289
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]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to