[PATCH v2 1/3] efi_loader: avoid pointer access after calling efi_delete_handle
Masahisa Kojima
masahisa.kojima at linaro.org
Thu Jan 18 01:16:14 CET 2024
On Wed, 17 Jan 2024 at 20:52, Ilias Apalodimas
<ilias.apalodimas at linaro.org> wrote:
>
> Hi Kojima-san
>
> On Wed, 17 Jan 2024 at 11:46, Masahisa Kojima
> <masahisa.kojima at linaro.org> wrote:
> >
> > efi_delete_handle() calls efi_purge_handle(), then it finally
> > frees the EFI handle.
> > Both diskobj and handle variables in efi_disk_remove() have
> > the same pointer, we can not access diskobj->dp after calling
> > efi_delete_handle().
> >
> > This commit saves the struct efi_device_path pointer before
> > calling efi_delete_handle(). This commit also fixes the
> > missing free for volume member in struct efi_disk_obj.
> >
> > This commit also removes the container_of() calls, and
> > adds the TODO comment of missing efi_close_protocol() call
> > for the parent EFI_BLOCK_IO_PROTOCOL.
> >
> > Signed-off-by: Masahisa Kojima <masahisa.kojima at linaro.org>
> > ---
> > lib/efi_loader/efi_disk.c | 23 +++++++++++++++++------
> > 1 file changed, 17 insertions(+), 6 deletions(-)
> >
> > diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
> > index 013842f077..ce46c1092a 100644
> > --- a/lib/efi_loader/efi_disk.c
> > +++ b/lib/efi_loader/efi_disk.c
> > @@ -707,35 +707,46 @@ int efi_disk_remove(void *ctx, struct event *event)
> > struct udevice *dev = event->data.dm.dev;
> > efi_handle_t handle;
> > struct blk_desc *desc;
> > + struct efi_device_path *dp = NULL;
> > struct efi_disk_obj *diskobj = NULL;
> > + struct efi_simple_file_system_protocol *volume = NULL;
> > efi_status_t ret;
> >
> > if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle))
> > return 0;
> >
> > + if (!handle)
> > + return 0;
> > +
>
> Is there a chance dev_tag_get_ptr() will return a NULL handle?
There is no chance unless we actually set a NULL.
Checking the return value of dev_tag_get_ptr above is enough, I will
remove this.
>
> > id = device_get_uclass_id(dev);
> > switch (id) {
> > case UCLASS_BLK:
> > desc = dev_get_uclass_plat(dev);
> > if (desc && desc->uclass_id != UCLASS_EFI_LOADER)
> > - diskobj = container_of(handle, struct efi_disk_obj,
> > - header);
> > + diskobj = (struct efi_disk_obj *)handle;
> > break;
> > case UCLASS_PARTITION:
> > - diskobj = container_of(handle, struct efi_disk_obj, header);
> > + diskobj = (struct efi_disk_obj *)handle;
> > +
> > + /* TODO: closing the parent EFI_BLOCK_IO_PROTOCOL is missing. */
> > +
> > break;
> > default:
> > return 0;
> > }
> >
> > + if (diskobj) {
> > + dp = diskobj->dp;
> > + volume = diskobj->volume;
> > + }
> > +
> > ret = efi_delete_handle(handle);
>
> Hmm, in which context are the dp and volume pointers allocated? The
> handle is now freed, can we reliably access dp and volume ptrs?
dp and volume are allocated in efi_disk_add_dev() when the block
device is probed.
efi_delete_handle() will remove all protocols from the handle,
efi_uninstall_protocol()
checks whether protocol_interface is actually installed. So dp and
volume should be
freed after efi_delete_handle().
Thanks,
Masahisa Kojima
>
> > /* Do not delete DM device if there are still EFI drivers attached. */
> > if (ret != EFI_SUCCESS)
> > return -1;
> >
> > - if (diskobj)
> > - efi_free_pool(diskobj->dp);
> > -
> > + efi_free_pool(dp);
> > + free(volume);
> > dev_tag_del(dev, DM_TAG_EFI);
> >
> > return 0;
> > --
> > 2.34.1
> >
>
> Thanks
> /Ilias
More information about the U-Boot
mailing list