On 04/26/18 05:12, Haojian Zhuang wrote:
> On 26 April 2018 at 00:10, Laszlo Ersek <ler...@redhat.com> wrote:

>> (4) In both patches, in both of the CreatePlatformBootOptionFromPath()
>> and CreatePlatformBootOptionFromGuid() helper functions, the
>> "DevicePath" variable is leaked when
>> EfiBootManagerInitializeLoadOption() fails.
>>
>> "DevicePath" should be freed unconditionally at that point, in both
>> patches and in both helper functions (4 instances in total). Simply
>> eliminate the following:
>>
>>   if (EFI_ERROR (Status)) {
>>     return Status;
>>   }
>>
>> and you will be left with:
>>
>>   Status = EfiBootManagerInitializeLoadOption (
>>              ...
>>              );
>>   FreePool (DevicePath);
>>   return Status;
>>
>> I believe I need not separately review this update either.
>>
> 
> For this one, I have a different opinion.
> 
> EFI_STATUS
> EFIAPI
> EfiBootManagerInitializeLoadOption (
>   ...
>   )
> {
>   if ((Option == NULL) || (Description == NULL) || (FilePath == NULL)) {
>     return EFI_INVALID_PARAMETER;
>   }
> 
>   if (((OptionalData != NULL) && (OptionalDataSize == 0)) ||
>       ((OptionalData == NULL) && (OptionalDataSize != 0))) {
>     return EFI_INVALID_PARAMETER;
>   }
>   if ((UINT32) OptionType >= LoadOptionTypeMax) {
>     return EFI_INVALID_PARAMETER;
>   }
> 
>   ZeroMem (Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
>   Option->OptionNumber       = OptionNumber;
>   Option->OptionType         = OptionType;
>   Option->Attributes         = Attributes;
>   Option->Description        = AllocateCopyPool (StrSize
> (Description), Description);
>   Option->FilePath           = DuplicateDevicePath (FilePath);
>   if (OptionalData != NULL) {
>     Option->OptionalData     = AllocateCopyPool (OptionalDataSize,
> OptionalData);
>     Option->OptionalDataSize = OptionalDataSize;
>   }
> 
>   return EFI_SUCCESS;
> }
> 
> We can find that no memory is allocated to "DevicePath" if it returns
> with error.
> 
> So we shouldn't free memory on "DevicePath" if "Status" is error code.

I disagree. We have:

  CreatePlatformBootOptionFromPath()
    DevicePath = ConvertTextToDevicePath(...)              #1
    EfiBootManagerInitializeLoadOption(... DevicePath ...)
      DuplicateDevicePath(FilePath=DevicePath)             #2

The ConvertTextToDevicePath() function returns the binary representation
of the device path in a dynamically allocated area. That is dynamic
object #1, tracked by the "DevicePath" variable. Then,
EfiBootManagerInitializeLoadOption() creates a deep copy, by calling the
DuplicateDevicePath() function. That creates dynamic object #2, tracked
by Option->FilePath.

- If EfiBootManagerInitializeLoadOption() returns with failure, then
dynamic object #2 does not exist, and we no longer need dynamic object
#1, so we have to free dynamic object #1.

- If EfiBootManagerInitializeLoadOption() returns with success, then
dynamic object #2 exists, and is correctly tracked by Option->FilePath.
We no longer need dynamic object #1, so we have to free it.

In other words, regardless of the return status of
EfiBootManagerInitializeLoadOption(), we must release dynamic object #1.
We need dynamic object #1 only temporarily, so we can call
EfiBootManagerInitializeLoadOption(), and let it make a copy.

The same applies to CreatePlatformBootOptionFromGuid(), except replace
ConvertTextToDevicePath() with AppendDevicePathNode():

  CreatePlatformBootOptionFromGuid()
    DevicePath = AppendDevicePathNode(...)                  #1
    EfiBootManagerInitializeLoadOption (... DevicePath ...)
      DuplicateDevicePath(FilePath=DevicePath)              #2

Again, AppendDevicePathNode() produces dynamic object #1, similarly to
ConvertTextToDevicePath().

Thanks
Laszlo
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to