diff options
author | David Herrmann <dh.herrmann@gmail.com> | 2013-08-25 12:28:58 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2013-08-26 21:54:56 -0400 |
commit | ca481c9b2a3ae3598453535b8f0369f1f875d52f (patch) | |
tree | 31b84f86251db898aa8fc8a1dfa14c3bd9a0ae97 /drivers/gpu/drm/drm_gem.c | |
parent | 88d7ebe59341dc3b82e662b80809694e3c6b3766 (diff) |
drm/gem: implement vma access management
We implement automatic vma mmap() access management for all drivers using
gem_mmap. We use the vma manager to add each open-file that creates a
gem-handle to the vma-node of the underlying gem object. Once the handle
is destroyed, we drop the open-file again.
This allows us to use drm_vma_node_is_allowed() on _any_ gem object to see
whether an open-file is granted access. In drm_gem_mmap() we use this to
verify that unprivileged users cannot guess gem offsets and map arbitrary
buffers.
Note that this manages access for _all_ gem users (also TTM+GEM), but the
actual access checks are only done for drm_gem_mmap(). TTM drivers use the
TTM mmap helpers, which need to do that separately.
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_gem.c')
-rw-r--r-- | drivers/gpu/drm/drm_gem.c | 17 |
1 files changed, 17 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index d6122ae6bf86..b2d59b2d3acc 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c | |||
@@ -298,6 +298,7 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle) | |||
298 | spin_unlock(&filp->table_lock); | 298 | spin_unlock(&filp->table_lock); |
299 | 299 | ||
300 | drm_gem_remove_prime_handles(obj, filp); | 300 | drm_gem_remove_prime_handles(obj, filp); |
301 | drm_vma_node_revoke(&obj->vma_node, filp->filp); | ||
301 | 302 | ||
302 | if (dev->driver->gem_close_object) | 303 | if (dev->driver->gem_close_object) |
303 | dev->driver->gem_close_object(obj, filp); | 304 | dev->driver->gem_close_object(obj, filp); |
@@ -357,6 +358,11 @@ drm_gem_handle_create_tail(struct drm_file *file_priv, | |||
357 | } | 358 | } |
358 | *handlep = ret; | 359 | *handlep = ret; |
359 | 360 | ||
361 | ret = drm_vma_node_allow(&obj->vma_node, file_priv->filp); | ||
362 | if (ret) { | ||
363 | drm_gem_handle_delete(file_priv, *handlep); | ||
364 | return ret; | ||
365 | } | ||
360 | 366 | ||
361 | if (dev->driver->gem_open_object) { | 367 | if (dev->driver->gem_open_object) { |
362 | ret = dev->driver->gem_open_object(obj, file_priv); | 368 | ret = dev->driver->gem_open_object(obj, file_priv); |
@@ -701,6 +707,7 @@ drm_gem_object_release_handle(int id, void *ptr, void *data) | |||
701 | struct drm_device *dev = obj->dev; | 707 | struct drm_device *dev = obj->dev; |
702 | 708 | ||
703 | drm_gem_remove_prime_handles(obj, file_priv); | 709 | drm_gem_remove_prime_handles(obj, file_priv); |
710 | drm_vma_node_revoke(&obj->vma_node, file_priv->filp); | ||
704 | 711 | ||
705 | if (dev->driver->gem_close_object) | 712 | if (dev->driver->gem_close_object) |
706 | dev->driver->gem_close_object(obj, file_priv); | 713 | dev->driver->gem_close_object(obj, file_priv); |
@@ -793,6 +800,10 @@ EXPORT_SYMBOL(drm_gem_vm_close); | |||
793 | * the GEM object is not looked up based on its fake offset. To implement the | 800 | * the GEM object is not looked up based on its fake offset. To implement the |
794 | * DRM mmap operation, drivers should use the drm_gem_mmap() function. | 801 | * DRM mmap operation, drivers should use the drm_gem_mmap() function. |
795 | * | 802 | * |
803 | * drm_gem_mmap_obj() assumes the user is granted access to the buffer while | ||
804 | * drm_gem_mmap() prevents unprivileged users from mapping random objects. So | ||
805 | * callers must verify access restrictions before calling this helper. | ||
806 | * | ||
796 | * NOTE: This function has to be protected with dev->struct_mutex | 807 | * NOTE: This function has to be protected with dev->struct_mutex |
797 | * | 808 | * |
798 | * Return 0 or success or -EINVAL if the object size is smaller than the VMA | 809 | * Return 0 or success or -EINVAL if the object size is smaller than the VMA |
@@ -841,6 +852,9 @@ EXPORT_SYMBOL(drm_gem_mmap_obj); | |||
841 | * Look up the GEM object based on the offset passed in (vma->vm_pgoff will | 852 | * Look up the GEM object based on the offset passed in (vma->vm_pgoff will |
842 | * contain the fake offset we created when the GTT map ioctl was called on | 853 | * contain the fake offset we created when the GTT map ioctl was called on |
843 | * the object) and map it with a call to drm_gem_mmap_obj(). | 854 | * the object) and map it with a call to drm_gem_mmap_obj(). |
855 | * | ||
856 | * If the caller is not granted access to the buffer object, the mmap will fail | ||
857 | * with EACCES. Please see the vma manager for more information. | ||
844 | */ | 858 | */ |
845 | int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) | 859 | int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) |
846 | { | 860 | { |
@@ -861,6 +875,9 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) | |||
861 | if (!node) { | 875 | if (!node) { |
862 | mutex_unlock(&dev->struct_mutex); | 876 | mutex_unlock(&dev->struct_mutex); |
863 | return drm_mmap(filp, vma); | 877 | return drm_mmap(filp, vma); |
878 | } else if (!drm_vma_node_is_allowed(node, filp)) { | ||
879 | mutex_unlock(&dev->struct_mutex); | ||
880 | return -EACCES; | ||
864 | } | 881 | } |
865 | 882 | ||
866 | obj = container_of(node, struct drm_gem_object, vma_node); | 883 | obj = container_of(node, struct drm_gem_object, vma_node); |