diff mbox series

[04/52] drm: Set final_kfree in drm_dev_alloc

Message ID 20200219102122.1607365-5-daniel.vetter@ffwll.ch (mailing list archive)
State New, archived
Headers show
Series None | expand

Commit Message

Daniel Vetter Feb. 19, 2020, 10:20 a.m. UTC
I also did a full review of all callers, and only the xen driver
forgot to call drm_dev_put in the failure path. Fix that up too.

v2: I noticed that xen has a drm_driver.release hook, and uses
drm_dev_alloc(). We need to remove the kfree from
xen_drm_drv_release().

bochs also has a release hook, but leaked the drm_device ever since

commit 0a6659bdc5e8221da99eebb176fd9591435e38de
Author: Gerd Hoffmann <kraxel@redhat.com>
Date:   Tue Dec 17 18:04:46 2013 +0100

    drm/bochs: new driver

This patch here fixes that leak.

Same for virtio, started leaking with

commit b1df3a2b24a917f8853d43fe9683c0e360d2c33a
Author: Gerd Hoffmann <kraxel@redhat.com>
Date:   Tue Feb 11 14:58:04 2020 +0100

    drm/virtio: add drm_driver.release callback.

Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
Cc: xen-devel@lists.xenproject.org

Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Maxime Ripard <mripard@kernel.org>
Cc: Thomas Zimmermann <tzimmermann@suse.de>
Cc: David Airlie <airlied@linux.ie>
Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
Cc: xen-devel@lists.xenproject.org
---
 drivers/gpu/drm/drm_drv.c           | 3 +++
 drivers/gpu/drm/xen/xen_drm_front.c | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

Comments

Oleksandr Andrushchenko Feb. 19, 2020, 12:03 p.m. UTC | #1
On 2/19/20 12:20 PM, Daniel Vetter wrote:
> I also did a full review of all callers, and only the xen driver
> forgot to call drm_dev_put in the failure path. Fix that up too.
>
> v2: I noticed that xen has a drm_driver.release hook, and uses
> drm_dev_alloc(). We need to remove the kfree from
> xen_drm_drv_release().
>
> bochs also has a release hook, but leaked the drm_device ever since
>
> commit 0a6659bdc5e8221da99eebb176fd9591435e38de
> Author: Gerd Hoffmann <kraxel@redhat.com>
> Date:   Tue Dec 17 18:04:46 2013 +0100
>
>      drm/bochs: new driver
>
> This patch here fixes that leak.
>
> Same for virtio, started leaking with
>
> commit b1df3a2b24a917f8853d43fe9683c0e360d2c33a
> Author: Gerd Hoffmann <kraxel@redhat.com>
> Date:   Tue Feb 11 14:58:04 2020 +0100
>
>      drm/virtio: add drm_driver.release callback.
>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
> Cc: xen-devel@lists.xenproject.org
>
> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Thank you,
Reviewed-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> Cc: Maxime Ripard <mripard@kernel.org>
> Cc: Thomas Zimmermann <tzimmermann@suse.de>
> Cc: David Airlie <airlied@linux.ie>
> Cc: Daniel Vetter <daniel@ffwll.ch>
> Cc: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
> Cc: xen-devel@lists.xenproject.org
> ---
>   drivers/gpu/drm/drm_drv.c           | 3 +++
>   drivers/gpu/drm/xen/xen_drm_front.c | 2 +-
>   2 files changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
> index 3e5627d6eba6..9e62e28bbc62 100644
> --- a/drivers/gpu/drm/drm_drv.c
> +++ b/drivers/gpu/drm/drm_drv.c
> @@ -39,6 +39,7 @@
>   #include <drm/drm_color_mgmt.h>
>   #include <drm/drm_drv.h>
>   #include <drm/drm_file.h>
> +#include <drm/drm_managed.h>
>   #include <drm/drm_mode_object.h>
>   #include <drm/drm_print.h>
>   
> @@ -819,6 +820,8 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
>   		return ERR_PTR(ret);
>   	}
>   
> +	drmm_add_final_kfree(dev, dev);
> +
>   	return dev;
>   }
>   EXPORT_SYMBOL(drm_dev_alloc);
> diff --git a/drivers/gpu/drm/xen/xen_drm_front.c b/drivers/gpu/drm/xen/xen_drm_front.c
> index 4be49c1aef51..d22b5da38935 100644
> --- a/drivers/gpu/drm/xen/xen_drm_front.c
> +++ b/drivers/gpu/drm/xen/xen_drm_front.c
> @@ -461,7 +461,6 @@ static void xen_drm_drv_release(struct drm_device *dev)
>   	drm_mode_config_cleanup(dev);
>   
>   	drm_dev_fini(dev);
> -	kfree(dev);
>   
>   	if (front_info->cfg.be_alloc)
>   		xenbus_switch_state(front_info->xb_dev,
> @@ -561,6 +560,7 @@ static int xen_drm_drv_init(struct xen_drm_front_info *front_info)
>   fail_modeset:
>   	drm_kms_helper_poll_fini(drm_dev);
>   	drm_mode_config_cleanup(drm_dev);
> +	drm_dev_put(drm_dev);
>   fail:
>   	kfree(drm_info);
>   	return ret;
Laurent Pinchart Feb. 19, 2020, 1:39 p.m. UTC | #2
Hi Daniel,

Thank you for the patch.

On Wed, Feb 19, 2020 at 11:20:34AM +0100, Daniel Vetter wrote:
> I also did a full review of all callers, and only the xen driver
> forgot to call drm_dev_put in the failure path. Fix that up too.

I'd split this patch in two then, with the Xen first coming first, and
with an explanation in the commit message of the second patch about why
you call drmm_add_final_kfree() in drm_dev_alloc().

> v2: I noticed that xen has a drm_driver.release hook, and uses
> drm_dev_alloc(). We need to remove the kfree from
> xen_drm_drv_release().
> 
> bochs also has a release hook, but leaked the drm_device ever since
> 
> commit 0a6659bdc5e8221da99eebb176fd9591435e38de
> Author: Gerd Hoffmann <kraxel@redhat.com>
> Date:   Tue Dec 17 18:04:46 2013 +0100
> 
>     drm/bochs: new driver
> 
> This patch here fixes that leak.
> 
> Same for virtio, started leaking with
> 
> commit b1df3a2b24a917f8853d43fe9683c0e360d2c33a
> Author: Gerd Hoffmann <kraxel@redhat.com>
> Date:   Tue Feb 11 14:58:04 2020 +0100
> 
>     drm/virtio: add drm_driver.release callback.
> 
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
> Cc: xen-devel@lists.xenproject.org
> 
> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> Cc: Maxime Ripard <mripard@kernel.org>
> Cc: Thomas Zimmermann <tzimmermann@suse.de>
> Cc: David Airlie <airlied@linux.ie>
> Cc: Daniel Vetter <daniel@ffwll.ch>
> Cc: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
> Cc: xen-devel@lists.xenproject.org
> ---
>  drivers/gpu/drm/drm_drv.c           | 3 +++
>  drivers/gpu/drm/xen/xen_drm_front.c | 2 +-
>  2 files changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
> index 3e5627d6eba6..9e62e28bbc62 100644
> --- a/drivers/gpu/drm/drm_drv.c
> +++ b/drivers/gpu/drm/drm_drv.c
> @@ -39,6 +39,7 @@
>  #include <drm/drm_color_mgmt.h>
>  #include <drm/drm_drv.h>
>  #include <drm/drm_file.h>
> +#include <drm/drm_managed.h>
>  #include <drm/drm_mode_object.h>
>  #include <drm/drm_print.h>
>  
> @@ -819,6 +820,8 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
>  		return ERR_PTR(ret);
>  	}
>  
> +	drmm_add_final_kfree(dev, dev);

drmm_add_final_kfree() can only be called once. Does this mean that a
driver using drm_dev_alloc() isn't allowed to use drmm_add_final_kfree()
to tract its own private structure ?

> +
>  	return dev;
>  }
>  EXPORT_SYMBOL(drm_dev_alloc);
> diff --git a/drivers/gpu/drm/xen/xen_drm_front.c b/drivers/gpu/drm/xen/xen_drm_front.c
> index 4be49c1aef51..d22b5da38935 100644
> --- a/drivers/gpu/drm/xen/xen_drm_front.c
> +++ b/drivers/gpu/drm/xen/xen_drm_front.c
> @@ -461,7 +461,6 @@ static void xen_drm_drv_release(struct drm_device *dev)
>  	drm_mode_config_cleanup(dev);
>  
>  	drm_dev_fini(dev);
> -	kfree(dev);
>  
>  	if (front_info->cfg.be_alloc)
>  		xenbus_switch_state(front_info->xb_dev,
> @@ -561,6 +560,7 @@ static int xen_drm_drv_init(struct xen_drm_front_info *front_info)
>  fail_modeset:
>  	drm_kms_helper_poll_fini(drm_dev);
>  	drm_mode_config_cleanup(drm_dev);
> +	drm_dev_put(drm_dev);
>  fail:
>  	kfree(drm_info);
>  	return ret;
Daniel Vetter Feb. 19, 2020, 2:41 p.m. UTC | #3
On Wed, Feb 19, 2020 at 2:39 PM Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Daniel,
>
> Thank you for the patch.
>
> On Wed, Feb 19, 2020 at 11:20:34AM +0100, Daniel Vetter wrote:
> > I also did a full review of all callers, and only the xen driver
> > forgot to call drm_dev_put in the failure path. Fix that up too.
>
> I'd split this patch in two then, with the Xen first coming first, and
> with an explanation in the commit message of the second patch about why
> you call drmm_add_final_kfree() in drm_dev_alloc().
>
> > v2: I noticed that xen has a drm_driver.release hook, and uses
> > drm_dev_alloc(). We need to remove the kfree from
> > xen_drm_drv_release().
> >
> > bochs also has a release hook, but leaked the drm_device ever since
> >
> > commit 0a6659bdc5e8221da99eebb176fd9591435e38de
> > Author: Gerd Hoffmann <kraxel@redhat.com>
> > Date:   Tue Dec 17 18:04:46 2013 +0100
> >
> >     drm/bochs: new driver
> >
> > This patch here fixes that leak.
> >
> > Same for virtio, started leaking with
> >
> > commit b1df3a2b24a917f8853d43fe9683c0e360d2c33a
> > Author: Gerd Hoffmann <kraxel@redhat.com>
> > Date:   Tue Feb 11 14:58:04 2020 +0100
> >
> >     drm/virtio: add drm_driver.release callback.
> >
> > Cc: Gerd Hoffmann <kraxel@redhat.com>
> > Cc: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
> > Cc: xen-devel@lists.xenproject.org
> >
> > Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
> > Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> > Cc: Maxime Ripard <mripard@kernel.org>
> > Cc: Thomas Zimmermann <tzimmermann@suse.de>
> > Cc: David Airlie <airlied@linux.ie>
> > Cc: Daniel Vetter <daniel@ffwll.ch>
> > Cc: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
> > Cc: xen-devel@lists.xenproject.org
> > ---
> >  drivers/gpu/drm/drm_drv.c           | 3 +++
> >  drivers/gpu/drm/xen/xen_drm_front.c | 2 +-
> >  2 files changed, 4 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
> > index 3e5627d6eba6..9e62e28bbc62 100644
> > --- a/drivers/gpu/drm/drm_drv.c
> > +++ b/drivers/gpu/drm/drm_drv.c
> > @@ -39,6 +39,7 @@
> >  #include <drm/drm_color_mgmt.h>
> >  #include <drm/drm_drv.h>
> >  #include <drm/drm_file.h>
> > +#include <drm/drm_managed.h>
> >  #include <drm/drm_mode_object.h>
> >  #include <drm/drm_print.h>
> >
> > @@ -819,6 +820,8 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
> >               return ERR_PTR(ret);
> >       }
> >
> > +     drmm_add_final_kfree(dev, dev);
>
> drmm_add_final_kfree() can only be called once. Does this mean that a
> driver using drm_dev_alloc() isn't allowed to use drmm_add_final_kfree()
> to tract its own private structure ?

There is only _one_ final kfree() for the structure containing
drm_device. Anything else you can just allocate with drmm_kzalloc, and
it will be cleaned up before. The chicken/egg doesn't just exist
around init time with drm_device, but also at cleanup time - the list
of cleanup actions is stored in drm_device, plus the logging macros
also need a drm_device. Which means we really, really, really need to
make sure that the drm_device is the very last thing that goes away.
Hence this special case. I was semi-tempted to drill through the slab
debug layer and add a check that the drm_device pointer in the
final_kfree is actually within the slab allocation block. Just to make
sure people use this correctly, and not just as a "hey here's a random
kmalloc block I want you to release, thxokbye". Because doing that
would cause a few use-after-free (or a leak).
-Daniel

>
> > +
> >       return dev;
> >  }
> >  EXPORT_SYMBOL(drm_dev_alloc);
> > diff --git a/drivers/gpu/drm/xen/xen_drm_front.c b/drivers/gpu/drm/xen/xen_drm_front.c
> > index 4be49c1aef51..d22b5da38935 100644
> > --- a/drivers/gpu/drm/xen/xen_drm_front.c
> > +++ b/drivers/gpu/drm/xen/xen_drm_front.c
> > @@ -461,7 +461,6 @@ static void xen_drm_drv_release(struct drm_device *dev)
> >       drm_mode_config_cleanup(dev);
> >
> >       drm_dev_fini(dev);
> > -     kfree(dev);
> >
> >       if (front_info->cfg.be_alloc)
> >               xenbus_switch_state(front_info->xb_dev,
> > @@ -561,6 +560,7 @@ static int xen_drm_drv_init(struct xen_drm_front_info *front_info)
> >  fail_modeset:
> >       drm_kms_helper_poll_fini(drm_dev);
> >       drm_mode_config_cleanup(drm_dev);
> > +     drm_dev_put(drm_dev);
> >  fail:
> >       kfree(drm_info);
> >       return ret;
>
> --
> Regards,
>
> Laurent Pinchart
Daniel Vetter Feb. 21, 2020, 7:07 p.m. UTC | #4
On Wed, Feb 19, 2020 at 03:41:07PM +0100, Daniel Vetter wrote:
> On Wed, Feb 19, 2020 at 2:39 PM Laurent Pinchart
> <laurent.pinchart@ideasonboard.com> wrote:
> >
> > Hi Daniel,
> >
> > Thank you for the patch.
> >
> > On Wed, Feb 19, 2020 at 11:20:34AM +0100, Daniel Vetter wrote:
> > > I also did a full review of all callers, and only the xen driver
> > > forgot to call drm_dev_put in the failure path. Fix that up too.
> >
> > I'd split this patch in two then, with the Xen first coming first, and
> > with an explanation in the commit message of the second patch about why
> > you call drmm_add_final_kfree() in drm_dev_alloc().

Forgot to reply to this I think.

Breaks biscting, so no can't split. It's just a leak, but this entire
series is full of these "would break bisecting because it would introduce
a subtle leak or use-after-free". Still isn't as simple as it looks
unfortunately :-/

> >
> > > v2: I noticed that xen has a drm_driver.release hook, and uses
> > > drm_dev_alloc(). We need to remove the kfree from
> > > xen_drm_drv_release().
> > >
> > > bochs also has a release hook, but leaked the drm_device ever since
> > >
> > > commit 0a6659bdc5e8221da99eebb176fd9591435e38de
> > > Author: Gerd Hoffmann <kraxel@redhat.com>
> > > Date:   Tue Dec 17 18:04:46 2013 +0100
> > >
> > >     drm/bochs: new driver
> > >
> > > This patch here fixes that leak.
> > >
> > > Same for virtio, started leaking with
> > >
> > > commit b1df3a2b24a917f8853d43fe9683c0e360d2c33a
> > > Author: Gerd Hoffmann <kraxel@redhat.com>
> > > Date:   Tue Feb 11 14:58:04 2020 +0100
> > >
> > >     drm/virtio: add drm_driver.release callback.
> > >
> > > Cc: Gerd Hoffmann <kraxel@redhat.com>
> > > Cc: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
> > > Cc: xen-devel@lists.xenproject.org
> > >
> > > Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
> > > Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> > > Cc: Maxime Ripard <mripard@kernel.org>
> > > Cc: Thomas Zimmermann <tzimmermann@suse.de>
> > > Cc: David Airlie <airlied@linux.ie>
> > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > Cc: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
> > > Cc: xen-devel@lists.xenproject.org
> > > ---
> > >  drivers/gpu/drm/drm_drv.c           | 3 +++
> > >  drivers/gpu/drm/xen/xen_drm_front.c | 2 +-
> > >  2 files changed, 4 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
> > > index 3e5627d6eba6..9e62e28bbc62 100644
> > > --- a/drivers/gpu/drm/drm_drv.c
> > > +++ b/drivers/gpu/drm/drm_drv.c
> > > @@ -39,6 +39,7 @@
> > >  #include <drm/drm_color_mgmt.h>
> > >  #include <drm/drm_drv.h>
> > >  #include <drm/drm_file.h>
> > > +#include <drm/drm_managed.h>
> > >  #include <drm/drm_mode_object.h>
> > >  #include <drm/drm_print.h>
> > >
> > > @@ -819,6 +820,8 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
> > >               return ERR_PTR(ret);
> > >       }
> > >
> > > +     drmm_add_final_kfree(dev, dev);
> >
> > drmm_add_final_kfree() can only be called once. Does this mean that a
> > driver using drm_dev_alloc() isn't allowed to use drmm_add_final_kfree()
> > to tract its own private structure ?
> 
> There is only _one_ final kfree() for the structure containing
> drm_device. Anything else you can just allocate with drmm_kzalloc, and
> it will be cleaned up before. The chicken/egg doesn't just exist
> around init time with drm_device, but also at cleanup time - the list
> of cleanup actions is stored in drm_device, plus the logging macros
> also need a drm_device. Which means we really, really, really need to
> make sure that the drm_device is the very last thing that goes away.
> Hence this special case. I was semi-tempted to drill through the slab
> debug layer and add a check that the drm_device pointer in the
> final_kfree is actually within the slab allocation block. Just to make
> sure people use this correctly, and not just as a "hey here's a random
> kmalloc block I want you to release, thxokbye". Because doing that
> would cause a few use-after-free (or a leak).

I've added those checks now.
-Daniel


> -Daniel
> 
> >
> > > +
> > >       return dev;
> > >  }
> > >  EXPORT_SYMBOL(drm_dev_alloc);
> > > diff --git a/drivers/gpu/drm/xen/xen_drm_front.c b/drivers/gpu/drm/xen/xen_drm_front.c
> > > index 4be49c1aef51..d22b5da38935 100644
> > > --- a/drivers/gpu/drm/xen/xen_drm_front.c
> > > +++ b/drivers/gpu/drm/xen/xen_drm_front.c
> > > @@ -461,7 +461,6 @@ static void xen_drm_drv_release(struct drm_device *dev)
> > >       drm_mode_config_cleanup(dev);
> > >
> > >       drm_dev_fini(dev);
> > > -     kfree(dev);
> > >
> > >       if (front_info->cfg.be_alloc)
> > >               xenbus_switch_state(front_info->xb_dev,
> > > @@ -561,6 +560,7 @@ static int xen_drm_drv_init(struct xen_drm_front_info *front_info)
> > >  fail_modeset:
> > >       drm_kms_helper_poll_fini(drm_dev);
> > >       drm_mode_config_cleanup(drm_dev);
> > > +     drm_dev_put(drm_dev);
> > >  fail:
> > >       kfree(drm_info);
> > >       return ret;
> >
> > --
> > Regards,
> >
> > Laurent Pinchart
> 
> 
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch
diff mbox series

Patch

diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 3e5627d6eba6..9e62e28bbc62 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -39,6 +39,7 @@ 
 #include <drm/drm_color_mgmt.h>
 #include <drm/drm_drv.h>
 #include <drm/drm_file.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_mode_object.h>
 #include <drm/drm_print.h>
 
@@ -819,6 +820,8 @@  struct drm_device *drm_dev_alloc(struct drm_driver *driver,
 		return ERR_PTR(ret);
 	}
 
+	drmm_add_final_kfree(dev, dev);
+
 	return dev;
 }
 EXPORT_SYMBOL(drm_dev_alloc);
diff --git a/drivers/gpu/drm/xen/xen_drm_front.c b/drivers/gpu/drm/xen/xen_drm_front.c
index 4be49c1aef51..d22b5da38935 100644
--- a/drivers/gpu/drm/xen/xen_drm_front.c
+++ b/drivers/gpu/drm/xen/xen_drm_front.c
@@ -461,7 +461,6 @@  static void xen_drm_drv_release(struct drm_device *dev)
 	drm_mode_config_cleanup(dev);
 
 	drm_dev_fini(dev);
-	kfree(dev);
 
 	if (front_info->cfg.be_alloc)
 		xenbus_switch_state(front_info->xb_dev,
@@ -561,6 +560,7 @@  static int xen_drm_drv_init(struct xen_drm_front_info *front_info)
 fail_modeset:
 	drm_kms_helper_poll_fini(drm_dev);
 	drm_mode_config_cleanup(drm_dev);
+	drm_dev_put(drm_dev);
 fail:
 	kfree(drm_info);
 	return ret;