[U-Boot] [RFC] efi_loader: memory leak in bootefi
Alexander Graf
agraf at suse.de
Thu Jul 6 19:24:11 UTC 2017
On 06.07.17 20:23, Heinrich Schuchardt wrote:
> On 07/06/2017 05:52 PM, Alexander Graf wrote:
>> Hi Heinrich,
>>
>> On 07/06/2017 05:43 PM, Heinrich Schuchardt wrote:
>>> Hello Alex,
>>>
>>> in bootefi.c do_bootefi_exec we build the efi_obj_list. This includes
>>> allocation of memory for some handlers (e.g. in efi_gop_register).
>>>
>>> After returning from the efi appliation we have no clean up code to
>>> release these objects.
>>>
>>> We do not remove the list elements from efi_obj_list.
>>>
>>> Furthermore we rely on a lot of static initializations e.g. for
>>> protocols. We know that this data may be changed by the application but
>>> we do not care to restore the original state.
>>>
>>> So if an application registers protocols and exits without unregistering
>>> we will offer invalid function pointers to the next efi application to
>>> be started.
>>>
>>> I suggest the following:
>>>
>>> In structure struct efi_object we add a function pointer to a clean-up
>>> function which takes as only argument the efi_object:
>>>
>>> struct efi_object {
>>> struct list_head link;
>>> struct efi_handler protocols[4];
>>> void (*cleanup)(struct efi_object *obj);
>>> void *handle;
>>> };
>>>
>>> A clean up function may look like this:
>>> void efi_gop_cleanup(struct efi_object *obj) {
>>> free(obj);
>>> }
>>>
>>> When returning from the EFI application we would work our way from the
>>> tail to the head of the object list:
>>>
>>> while (list is not empty) {
>>> Remove last object from list.
>>> Call cleanup function of removed object.
>>> }
>>>
>>> We should get rid of the static structures loaded_image_info_obj
>>> and boot_efi_obj. Let's use register functions with calloc here too.
>>>
>>> Would you agree to this design?
>>
>> The basic long-term plan was to instead integrate the efi object model
>> with the DM object model and slowly make every DM object potentially an
>> EFI object. That way we would only initialize the objects once on bootup.
>>
>> The fact that then an application may modify pointers is actually
>> intended by UEFI. A driver may want to intercept what another driver
>> does or route things through itself. It works the same way in edk2 as
>> far as I can tell :).
>>
>>
>
> There are two types of EFI binaries:
> - applications
> - drivers
>
> In the "Microsoft Portable Executable and Common Object File Format
> Specification" this is described as field "Windows Subsystem":
>
> /* An Extensible Firmware Interface (EFI) application */
> IMAGE_SUBSYSTEM_EFI_APPLICATION = 10
> /* An EFI driver with boot services */
> IMAGE_SUBSYSTEM_EFI_BOOT_ SERVICE_DRIVER = 11
>
> In my notes above I only related to EFI applications. And you are right
> in that we may have to treat drivers differently.
I don't think edk2 treats them that differently. The object model is
persistent across binary invocations. That's the thing we're lacking in
U-Boot right now.
> My test was running the iPXE application and terminating it from the
> shell with "exit".
> When I tried to run it again I got an error EFI_OUT_OF_RESOURCES which I
> did not get on the first run.
>
> Currently we are using bootefi to run applications like grub.
> Do we want to use the same command to install drivers?
If we ever want to support drivers (not sure we do yet), then yes.
> If yes, bootefi should evaluate the PE32+ header to find out if the
> binary is a driver or an application binary.
Would it make a difference?
> In case of an application returning we should restore the situation
> before the application was started.
Again, I don't think this is what edk2 does. But let's ask Ard.
> Independent of the discussion above there is a design error that is
> relevant for any type of binary:
>
> We calloc a new efi object for efi_driver and efi_gop and add it to the
> efi object list every time that bootefi is called. We never free the
> objects. So this results in a memory leak.
Yes. Recreating the object model in itself is problematic. We really
should only create it once on U-Boot instantiation - together with the
U-Boot internal device model.
> According to the UEFI specification additional protocols should be
> installed on the system handle. So I guess the efi_gop and efi_driver
> objects can be safely freed after use.
No, instead they should simply persist before and after bootefi :).
The reason I didn't always create efi objects without bootefi invocation
was simply because I didn't want to incur any overhead on people that
don't want to run efi binaries. I guess a quick fix would be to just
remember that the efi object model is instantiated already and only
create objects if it's not initialized yet.
Alex
More information about the U-Boot
mailing list