public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Marc-André Lureau" <marcandre.lureau@gmail.com>
To: Laszlo Ersek <lersek@redhat.com>
Cc: edk2-devel@lists.01.org, Jiewen Yao <jiewen.yao@intel.com>,
	 Star Zeng <star.zeng@intel.com>,
	Chao Zhang <chao.b.zhang@intel.com>
Subject: Re: [PATCH 1/1] RFC: SecurityPkg: only clear HashInterface informations
Date: Wed, 7 Mar 2018 11:53:41 +0100	[thread overview]
Message-ID: <CAJ+F1C+XsGXfyNti4r8Oz0izJNHhRUEq-tJTVHMi6_9LUOidZA@mail.gmail.com> (raw)
In-Reply-To: <1dbffca1-c83e-0839-45b5-62875b0cfae0@redhat.com>

Hi

On Wed, Mar 7, 2018 at 10:06 AM, Laszlo Ersek <lersek@redhat.com> wrote:
> Hi Marc-André,
>
> On 03/06/18 21:27, marcandre.lureau@redhat.com wrote:
>> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>>
>> The ZeroMem() call goes beyond the HashInterfaceHob structure, causing
>> HOB list corruption. Instead, just clear the HashInterface fields, as
>> I suppose was originally intended.
>>
>> Cc: Jiewen Yao <jiewen.yao@intel.com>
>> Cc: Chao Zhang <chao.b.zhang@intel.com>
>> Cc: Star Zeng <star.zeng@intel.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Contributed-under: TianoCore Contribution Agreement 1.1
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>>  .../HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c       | 3 ++-
>>  1 file changed, 2 insertions(+), 1 deletion(-)
>>
>> diff --git a/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c b/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c
>> index dbee0f2531bc..361a4f6508a0 100644
>> --- a/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c
>> +++ b/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c
>> @@ -424,7 +424,8 @@ HashLibBaseCryptoRouterPeiConstructor (
>>      // This is the second execution of this module, clear the hash interface
>>      // information registered at its first execution.
>>      //
>> -    ZeroMem (&HashInterfaceHob->HashInterface, sizeof (*HashInterfaceHob) - sizeof (EFI_GUID));
>> +    ZeroMem (&HashInterfaceHob->HashInterface, sizeof (HashInterfaceHob->HashInterface));
>> +    HashInterfaceHob->HashInterfaceCount = 0;
>>    }
>>
>>    //
>>
>
> Excellent catch! :)
>
> I do have a question however, for the other reviewers on this patch, in
> line with your commit message saying, "clear the HashInterface fields,
> as *I suppose* was originally intended".
>
> I don't think the proposed update matches the original intent 100%.
> Namely, this is the definition of the HASH_INTERFACE_HOB type (from the
> same source file):
>
>> typedef struct {
>>   //
>>   // If gZeroGuid, SupportedHashMask is 0 for FIRST module which consumes HashLib
>>   //   or the hash algorithm bitmap of LAST module which consumes HashLib.
>>   //   HashInterfaceCount and HashInterface are all 0.
>>   // If gEfiCallerIdGuid, HashInterfaceCount, HashInterface and SupportedHashMask
>>   //   are the hash interface information of CURRENT module which consumes HashLib.
>>   //
>>   EFI_GUID         Identifier;
>>   UINTN            HashInterfaceCount;
>>   HASH_INTERFACE   HashInterface[HASH_COUNT];
>>   UINT32           SupportedHashMask;
>> } HASH_INTERFACE_HOB;
>
> Note that it says, if Identifier equals "gEfiCallerIdGuid", then *all
> three* subsequent fields carry information of the current module that
> consumes HashLib. Those three fields include "SupportedHashMask".
>
> Furthermore, the comment just preceding the bug / ZeroMem() call says,
>
>>     //
>>     // In PEI phase, some modules may call RegisterForShadow and will be
>>     // shadowed and executed again after memory is discovered.
>>     // This is the second execution of this module, clear the hash interface
>>     // information registered at its first execution.
>>     //
>
> And note that here we are just past the check
>
>>   HashInterfaceHob = InternalGetHashInterfaceHob (&gEfiCallerIdGuid);
>>   if (HashInterfaceHob != NULL) {
>
> in other words, the "Identifier equals gEfiCallerIdGuid" branch from the
> type definition applies; meaning that "SupportedHashMask" is defined
> too.
>
> Thus, I'd like the other reviewers to confirm whether we should clear
> "SupportedHashMask".
>
> From the original (buggy) code, I think we *should* clear
> SupportedHashMask as well. The "Length" argument of the original
> ZeroMem() call implies precisely that:
>
>   sizeof (*HashInterfaceHob) - sizeof (EFI_GUID)
>
> This stands for "all fields in *HashInterfaceHob except the leading
> EFI_GUID Identifier field".
>
> So, the actual bug is in the "Buffer" argument of the ZeroMem() call: it
> is a typo. Certainly the intent must have been "start clearing from the
> first field right after the EFI_GUID Identifier field", namely
> "HashInterfaceCount":
>
>   &HashInterfaceHob->HashInterfaceCount
>                                   ^^^^^
>
> Therefore I think the *first* approach to actually fixing this bug would
> be to simply add the "Count" suffix:
>
>> diff --git a/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c b/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c
>> index dbee0f2531bc..a869fffae3fe 100644
>> --- a/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c
>> +++ b/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c
>> @@ -424,7 +424,10 @@ HashLibBaseCryptoRouterPeiConstructor (
>>      // This is the second execution of this module, clear the hash interface
>>      // information registered at its first execution.
>>      //
>> -    ZeroMem (&HashInterfaceHob->HashInterface, sizeof (*HashInterfaceHob) - sizeof (EFI_GUID));
>> +    ZeroMem (
>> +      &HashInterfaceHob->HashInterfaceCount,
>> +      sizeof (*HashInterfaceHob) - sizeof (EFI_GUID)
>> +      );
>>    }
>>
>>    //
>
> On the other hand, I don't think such a fix would be great. First of
> all, the HASH_INTERFACE_HOB struct definition is not wrapped in
>
> #pragma pack (1)
> ...
> #pragma pack ()
>
> in other words, HASH_INTERFACE_HOB is not packed, hence there could be
> an unspecified amount of padding between "Identifier" and
> "HashInterfaceCount". That would lead to the same kind of buffer
> overflow, because "Length" includes the padding, but the "Buffer"
> argument doesn't.
>
> Second, even if there were no padding (and thus the byte count would be
> a perfect match for the full HOB structure), in the "Buffer" argument
> we take the address of the "HashInterfaceCount" field, and with the
> "Length" field, we still overflow that *individual* field. Although we
> wouldn't overflow the containing HOB structure, this is still (arguably)
> undefined behavior -- I seem to remember that some compilers actually
> blow up on this when you use the standard ISO C memcpy() or memset()
> functions in such contexts.
>
> So, long story short, I suggest the following fix instead:
>
>> diff --git a/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c b/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c
>> index dbee0f2531bc..84c1aaae70eb 100644
>> --- a/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c
>> +++ b/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c
>> @@ -397,6 +397,7 @@ HashLibBaseCryptoRouterPeiConstructor (
>>  {
>>    EFI_STATUS            Status;
>>    HASH_INTERFACE_HOB    *HashInterfaceHob;
>> +  UINTN                 ClearStartOffset;
>>
>>    HashInterfaceHob = InternalGetHashInterfaceHob (&gZeroGuid);
>>    if (HashInterfaceHob == NULL) {
>> @@ -424,7 +425,11 @@ HashLibBaseCryptoRouterPeiConstructor (
>>      // This is the second execution of this module, clear the hash interface
>>      // information registered at its first execution.
>>      //
>> -    ZeroMem (&HashInterfaceHob->HashInterface, sizeof (*HashInterfaceHob) - sizeof (EFI_GUID));
>> +    ClearStartOffset = OFFSET_OF (HASH_INTERFACE_HOB, HashInterfaceCount);
>> +    ZeroMem (
>> +      (UINT8 *)HashInterfaceHob + ClearStartOffset,
>> +      sizeof (*HashInterfaceHob) - ClearStartOffset
>> +      );
>>    }
>>
>>    //
>
> Thoughts?

Looking at RegisterHashInterfaceLib() code, I agree it makes sense to
clear both the array and the mask. Both seem to be closely related
during registration.

I agree with your argument as well about structure packing. I'll
resend the patch with your suggested changes.

thanks


      parent reply	other threads:[~2018-03-07 10:47 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-06 20:27 [PATCH 1/1] RFC: SecurityPkg: only clear HashInterface informations marcandre.lureau
2018-03-07  0:40 ` Zeng, Star
2018-03-07  0:40 ` Yao, Jiewen
2018-03-07  2:03 ` Zhang, Chao B
2018-03-07  9:06 ` Laszlo Ersek
2018-03-07  9:42   ` Zeng, Star
2018-03-07 15:05     ` Zeng, Star
2018-03-07 20:50     ` Laszlo Ersek
2018-03-07 10:53   ` Marc-André Lureau [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAJ+F1C+XsGXfyNti4r8Oz0izJNHhRUEq-tJTVHMi6_9LUOidZA@mail.gmail.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox