[PATCH 10/16] drm/gem: implement mmap access management

Daniel Vetter daniel at ffwll.ch
Tue Aug 13 14:05:53 PDT 2013


On Tue, Aug 13, 2013 at 09:38:31PM +0200, David Herrmann wrote:
> Implement automatic access management for mmap offsets for all GEM
> drivers. This prevents user-space applications from "guessing" GEM BO
> offsets and accessing buffers which they don't own.
> 
> TTM drivers or other modesetting drivers with custom mm handling might
> make use of GEM but don't need its mmap helpers. To avoid unnecessary
> overhead, we limit GEM access management to drivers using DRIVER_GEM_MMAP.
> So for TTM drivers GEM will not call any *_allow() or *_revoke() helpers.
> 
> Signed-off-by: David Herrmann <dh.herrmann at gmail.com>

Overall I'm not sold why we need the GEM_MMAP feature flag. Drivers that
don't use drm_gem_mmap shouldn't get hurt with it if we ignore the little
bit of useless overhead due to obj->vma_node. But they already have that
anyway with obj->vma, so meh. And more incentives to move ttm over to the
gem object manager completely ;-)

One comment below.

Cheers, Daniel

> ---
>  Documentation/DocBook/drm.tmpl | 13 +++++++++++++
>  drivers/gpu/drm/drm_gem.c      | 36 ++++++++++++++++++++++++++++++++----
>  include/drm/drmP.h             |  1 +
>  3 files changed, 46 insertions(+), 4 deletions(-)
> 
> diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
> index 87e22ec..a388749 100644
> --- a/Documentation/DocBook/drm.tmpl
> +++ b/Documentation/DocBook/drm.tmpl
> @@ -223,6 +223,19 @@
>              </para></listitem>
>            </varlistentry>
>            <varlistentry>
> +            <term>DRIVER_GEM_MMAP</term>
> +            <listitem><para>
> +              Driver uses default GEM mmap helpers. This flag guarantees that
> +              GEM core takes care of buffer access management and prevents
> +              unprivileged users from mapping random buffers. This flag should
> +              only be set by GEM-only drivers that use the drm_gem_mmap_*()
> +              helpers directly. TTM, on the other hand, takes care of access
> +              management itself, even though drivers might use DRIVER_GEM and
> +              TTM at the same time. See the DRM VMA Offset Manager interface for
> +              more information on buffer mmap() access management.
> +            </para></listitem>
> +          </varlistentry>
> +          <varlistentry>
>              <term>DRIVER_MODESET</term>
>              <listitem><para>
>                Driver supports mode setting interfaces (KMS).
> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> index 7043d89..887274f 100644
> --- a/drivers/gpu/drm/drm_gem.c
> +++ b/drivers/gpu/drm/drm_gem.c
> @@ -236,6 +236,9 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle)
>  
>  	drm_gem_remove_prime_handles(obj, filp);
>  
> +	if (drm_core_check_feature(dev, DRIVER_GEM_MMAP))
> +		drm_vma_node_revoke(&obj->vma_node, filp->filp);
> +
>  	if (dev->driver->gem_close_object)
>  		dev->driver->gem_close_object(obj, filp);
>  	drm_gem_object_handle_unreference_unlocked(obj);
> @@ -288,15 +291,26 @@ drm_gem_handle_create(struct drm_file *file_priv,
>  
>  	drm_gem_object_handle_reference(obj);
>  
> +	if (drm_core_check_feature(dev, DRIVER_GEM_MMAP)) {
> +		ret = drm_vma_node_allow(&obj->vma_node, file_priv->filp);
> +		if (ret)
> +			goto err_handle;
> +	}
> +
>  	if (dev->driver->gem_open_object) {
>  		ret = dev->driver->gem_open_object(obj, file_priv);
> -		if (ret) {
> -			drm_gem_handle_delete(file_priv, *handlep);
> -			return ret;
> -		}
> +		if (ret)
> +			goto err_node;

The error handling cleanup changes here aren't required since
handle_delete will dtrt anyway. Or at least I hope it does ;-)
-Daniel

>  	}
>  
>  	return 0;
> +
> +err_node:
> +	if (drm_core_check_feature(dev, DRIVER_GEM_MMAP))
> +		drm_vma_node_revoke(&obj->vma_node, file_priv->filp);
> +err_handle:
> +	drm_gem_handle_delete(file_priv, *handlep);
> +	return ret;
>  }
>  EXPORT_SYMBOL(drm_gem_handle_create);
>  
> @@ -486,6 +500,9 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
>  
>  	drm_gem_remove_prime_handles(obj, file_priv);
>  
> +	if (drm_core_check_feature(dev, DRIVER_GEM_MMAP))
> +		drm_vma_node_revoke(&obj->vma_node, file_priv->filp);
> +
>  	if (dev->driver->gem_close_object)
>  		dev->driver->gem_close_object(obj, file_priv);
>  
> @@ -610,6 +627,10 @@ EXPORT_SYMBOL(drm_gem_vm_close);
>   * the GEM object is not looked up based on its fake offset. To implement the
>   * DRM mmap operation, drivers should use the drm_gem_mmap() function.
>   *
> + * drm_gem_mmap_obj() assumes the user is granted access to the buffer while
> + * drm_gem_mmap() prevents unprivileged users from mapping random objects. So
> + * callers must verify access restrictions before calling this helper.
> + *
>   * NOTE: This function has to be protected with dev->struct_mutex
>   *
>   * Return 0 or success or -EINVAL if the object size is smaller than the VMA
> @@ -658,6 +679,9 @@ EXPORT_SYMBOL(drm_gem_mmap_obj);
>   * Look up the GEM object based on the offset passed in (vma->vm_pgoff will
>   * contain the fake offset we created when the GTT map ioctl was called on
>   * the object) and map it with a call to drm_gem_mmap_obj().
> + *
> + * If the caller is not granted access to the buffer object, the mmap will fail
> + * with EACCES. Please see DRIVER_GEM_MMAP for more information.
>   */
>  int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
>  {
> @@ -678,6 +702,10 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
>  	if (!node) {
>  		mutex_unlock(&dev->struct_mutex);
>  		return drm_mmap(filp, vma);
> +	} else if (drm_core_check_feature(dev, DRIVER_GEM_MMAP) &&
> +		   !drm_vma_node_is_allowed(node, filp)) {
> +		mutex_unlock(&dev->struct_mutex);
> +		return -EACCES;
>  	}
>  
>  	obj = container_of(node, struct drm_gem_object, vma_node);
> diff --git a/include/drm/drmP.h b/include/drm/drmP.h
> index 3ecdde6..d51accd 100644
> --- a/include/drm/drmP.h
> +++ b/include/drm/drmP.h
> @@ -152,6 +152,7 @@ int drm_err(const char *func, const char *format, ...);
>  #define DRIVER_GEM         0x1000
>  #define DRIVER_MODESET     0x2000
>  #define DRIVER_PRIME       0x4000
> +#define DRIVER_GEM_MMAP    0x8000
>  
>  #define DRIVER_BUS_PCI 0x1
>  #define DRIVER_BUS_PLATFORM 0x2
> -- 
> 1.8.3.4
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch


More information about the dri-devel mailing list