diff options
author | Dave Airlie <airlied@redhat.com> | 2014-01-14 04:55:36 +0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2014-01-14 04:55:36 +0400 |
commit | faf096ffba2b1a4066e6d6dcd1243cc5f3d1fb23 (patch) | |
tree | 4793c625d9eaae10f453b8c4d32543de86875402 | |
parent | a095c60bd06f204c98527aafd5fda6ef42b53eb5 (diff) | |
parent | 94844cf06568d9592f985e4bd0b9d759a56043c6 (diff) | |
download | linux-faf096ffba2b1a4066e6d6dcd1243cc5f3d1fb23.tar.xz |
Merge tag 'vmwgfx-next-2014-01-13' of git://people.freedesktop.org/~thomash/linux into drm-next
Anyway, nothing big here, Three more code cleanup patches from Rashika
Kheria, and one TTM/vmwgfx patch from me that tightens security around TTM
objects enough for them to opened using prime objects from render nodes:
Previously any client could access a shared buffer using the "name", also
without actually opening it. Now a reference is required, and for render nodes
such a reference is intended to only be obtainable using a prime fd.
vmwgfx-next 2014-01-13 pull request
* tag 'vmwgfx-next-2014-01-13' of git://people.freedesktop.org/~thomash/linux:
drivers: gpu: Mark functions as static in vmwgfx_fence.c
drivers: gpu: Mark functions as static in vmwgfx_buffer.c
drivers: gpu: Mark functions as static in vmwgfx_kms.c
drm/ttm: ttm object security fixes for render nodes
-rw-r--r-- | drivers/gpu/drm/ttm/ttm_object.c | 90 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 3 | ||||
-rw-r--r-- | include/drm/ttm/ttm_object.h | 18 |
6 files changed, 87 insertions, 53 deletions
diff --git a/drivers/gpu/drm/ttm/ttm_object.c b/drivers/gpu/drm/ttm/ttm_object.c index 6fe7b92a82d1..37079859afc8 100644 --- a/drivers/gpu/drm/ttm/ttm_object.c +++ b/drivers/gpu/drm/ttm/ttm_object.c @@ -68,7 +68,7 @@ struct ttm_object_file { struct ttm_object_device *tdev; - rwlock_t lock; + spinlock_t lock; struct list_head ref_list; struct drm_open_hash ref_hash[TTM_REF_NUM]; struct kref refcount; @@ -118,6 +118,7 @@ struct ttm_object_device { */ struct ttm_ref_object { + struct rcu_head rcu_head; struct drm_hash_item hash; struct list_head head; struct kref kref; @@ -210,10 +211,9 @@ static void ttm_release_base(struct kref *kref) * call_rcu() or ttm_base_object_kfree(). */ - if (base->refcount_release) { - ttm_object_file_unref(&base->tfile); + ttm_object_file_unref(&base->tfile); + if (base->refcount_release) base->refcount_release(&base); - } } void ttm_base_object_unref(struct ttm_base_object **p_base) @@ -229,32 +229,46 @@ EXPORT_SYMBOL(ttm_base_object_unref); struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, uint32_t key) { - struct ttm_object_device *tdev = tfile->tdev; - struct ttm_base_object *uninitialized_var(base); + struct ttm_base_object *base = NULL; struct drm_hash_item *hash; + struct drm_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE]; int ret; rcu_read_lock(); - ret = drm_ht_find_item_rcu(&tdev->object_hash, key, &hash); + ret = drm_ht_find_item_rcu(ht, key, &hash); if (likely(ret == 0)) { - base = drm_hash_entry(hash, struct ttm_base_object, hash); - ret = kref_get_unless_zero(&base->refcount) ? 0 : -EINVAL; + base = drm_hash_entry(hash, struct ttm_ref_object, hash)->obj; + if (!kref_get_unless_zero(&base->refcount)) + base = NULL; } rcu_read_unlock(); - if (unlikely(ret != 0)) - return NULL; + return base; +} +EXPORT_SYMBOL(ttm_base_object_lookup); - if (tfile != base->tfile && !base->shareable) { - pr_err("Attempted access of non-shareable object\n"); - ttm_base_object_unref(&base); - return NULL; +struct ttm_base_object * +ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key) +{ + struct ttm_base_object *base = NULL; + struct drm_hash_item *hash; + struct drm_open_hash *ht = &tdev->object_hash; + int ret; + + rcu_read_lock(); + ret = drm_ht_find_item_rcu(ht, key, &hash); + + if (likely(ret == 0)) { + base = drm_hash_entry(hash, struct ttm_base_object, hash); + if (!kref_get_unless_zero(&base->refcount)) + base = NULL; } + rcu_read_unlock(); return base; } -EXPORT_SYMBOL(ttm_base_object_lookup); +EXPORT_SYMBOL(ttm_base_object_lookup_for_ref); int ttm_ref_object_add(struct ttm_object_file *tfile, struct ttm_base_object *base, @@ -266,21 +280,25 @@ int ttm_ref_object_add(struct ttm_object_file *tfile, struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob; int ret = -EINVAL; + if (base->tfile != tfile && !base->shareable) + return -EPERM; + if (existed != NULL) *existed = true; while (ret == -EINVAL) { - read_lock(&tfile->lock); - ret = drm_ht_find_item(ht, base->hash.key, &hash); + rcu_read_lock(); + ret = drm_ht_find_item_rcu(ht, base->hash.key, &hash); if (ret == 0) { ref = drm_hash_entry(hash, struct ttm_ref_object, hash); - kref_get(&ref->kref); - read_unlock(&tfile->lock); - break; + if (!kref_get_unless_zero(&ref->kref)) { + rcu_read_unlock(); + break; + } } - read_unlock(&tfile->lock); + rcu_read_unlock(); ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref), false, false); if (unlikely(ret != 0)) @@ -297,19 +315,19 @@ int ttm_ref_object_add(struct ttm_object_file *tfile, ref->ref_type = ref_type; kref_init(&ref->kref); - write_lock(&tfile->lock); - ret = drm_ht_insert_item(ht, &ref->hash); + spin_lock(&tfile->lock); + ret = drm_ht_insert_item_rcu(ht, &ref->hash); if (likely(ret == 0)) { list_add_tail(&ref->head, &tfile->ref_list); kref_get(&base->refcount); - write_unlock(&tfile->lock); + spin_unlock(&tfile->lock); if (existed != NULL) *existed = false; break; } - write_unlock(&tfile->lock); + spin_unlock(&tfile->lock); BUG_ON(ret != -EINVAL); ttm_mem_global_free(mem_glob, sizeof(*ref)); @@ -330,17 +348,17 @@ static void ttm_ref_object_release(struct kref *kref) struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob; ht = &tfile->ref_hash[ref->ref_type]; - (void)drm_ht_remove_item(ht, &ref->hash); + (void)drm_ht_remove_item_rcu(ht, &ref->hash); list_del(&ref->head); - write_unlock(&tfile->lock); + spin_unlock(&tfile->lock); if (ref->ref_type != TTM_REF_USAGE && base->ref_obj_release) base->ref_obj_release(base, ref->ref_type); ttm_base_object_unref(&ref->obj); ttm_mem_global_free(mem_glob, sizeof(*ref)); - kfree(ref); - write_lock(&tfile->lock); + kfree_rcu(ref, rcu_head); + spin_lock(&tfile->lock); } int ttm_ref_object_base_unref(struct ttm_object_file *tfile, @@ -351,15 +369,15 @@ int ttm_ref_object_base_unref(struct ttm_object_file *tfile, struct drm_hash_item *hash; int ret; - write_lock(&tfile->lock); + spin_lock(&tfile->lock); ret = drm_ht_find_item(ht, key, &hash); if (unlikely(ret != 0)) { - write_unlock(&tfile->lock); + spin_unlock(&tfile->lock); return -EINVAL; } ref = drm_hash_entry(hash, struct ttm_ref_object, hash); kref_put(&ref->kref, ttm_ref_object_release); - write_unlock(&tfile->lock); + spin_unlock(&tfile->lock); return 0; } EXPORT_SYMBOL(ttm_ref_object_base_unref); @@ -372,7 +390,7 @@ void ttm_object_file_release(struct ttm_object_file **p_tfile) struct ttm_object_file *tfile = *p_tfile; *p_tfile = NULL; - write_lock(&tfile->lock); + spin_lock(&tfile->lock); /* * Since we release the lock within the loop, we have to @@ -388,7 +406,7 @@ void ttm_object_file_release(struct ttm_object_file **p_tfile) for (i = 0; i < TTM_REF_NUM; ++i) drm_ht_remove(&tfile->ref_hash[i]); - write_unlock(&tfile->lock); + spin_unlock(&tfile->lock); ttm_object_file_unref(&tfile); } EXPORT_SYMBOL(ttm_object_file_release); @@ -404,7 +422,7 @@ struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev, if (unlikely(tfile == NULL)) return NULL; - rwlock_init(&tfile->lock); + spin_lock_init(&tfile->lock); tfile->tdev = tdev; kref_init(&tfile->refcount); INIT_LIST_HEAD(&tfile->ref_list); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c index 0489c6152482..2d61a2d86bd7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c @@ -517,7 +517,7 @@ static struct ttm_backend_func vmw_ttm_func = { .destroy = vmw_ttm_destroy, }; -struct ttm_tt *vmw_ttm_tt_create(struct ttm_bo_device *bdev, +static struct ttm_tt *vmw_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size, uint32_t page_flags, struct page *dummy_read_page) { @@ -546,12 +546,12 @@ out_no_init: return NULL; } -int vmw_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags) +static int vmw_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags) { return 0; } -int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, +static int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, struct ttm_mem_type_manager *man) { switch (type) { @@ -589,7 +589,7 @@ int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, return 0; } -void vmw_evict_flags(struct ttm_buffer_object *bo, +static void vmw_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *placement) { *placement = vmw_sys_placement; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index c62d20e8a6f1..436b013b4231 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c @@ -271,7 +271,7 @@ void vmw_fence_obj_unreference(struct vmw_fence_obj **fence_p) spin_unlock_irq(&fman->lock); } -void vmw_fences_perform_actions(struct vmw_fence_manager *fman, +static void vmw_fences_perform_actions(struct vmw_fence_manager *fman, struct list_head *list) { struct vmw_fence_action *action, *next_action; @@ -897,7 +897,7 @@ static void vmw_event_fence_action_cleanup(struct vmw_fence_action *action) * Note that the action callbacks may be executed before this function * returns. */ -void vmw_fence_obj_add_action(struct vmw_fence_obj *fence, +static void vmw_fence_obj_add_action(struct vmw_fence_obj *fence, struct vmw_fence_action *action) { struct vmw_fence_manager *fman = fence->fman; @@ -993,7 +993,7 @@ struct vmw_event_fence_pending { struct drm_vmw_event_fence event; }; -int vmw_event_fence_action_create(struct drm_file *file_priv, +static int vmw_event_fence_action_create(struct drm_file *file_priv, struct vmw_fence_obj *fence, uint32_t flags, uint64_t user_data, @@ -1080,7 +1080,8 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data, */ if (arg->handle) { struct ttm_base_object *base = - ttm_base_object_lookup(vmw_fp->tfile, arg->handle); + ttm_base_object_lookup_for_ref(dev_priv->tdev, + arg->handle); if (unlikely(base == NULL)) { DRM_ERROR("Fence event invalid fence object handle " diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 9f307e0f3603..019e2dbb46c8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -40,7 +40,7 @@ struct vmw_clip_rect { * Clip @num_rects number of @rects against @clip storing the * results in @out_rects and the number of passed rects in @out_num. */ -void vmw_clip_cliprects(struct drm_clip_rect *rects, +static void vmw_clip_cliprects(struct drm_clip_rect *rects, int num_rects, struct vmw_clip_rect clip, SVGASignedRect *out_rects, @@ -423,7 +423,7 @@ struct vmw_framebuffer_surface { struct drm_master *master; }; -void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer) +static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer) { struct vmw_framebuffer_surface *vfbs = vmw_framebuffer_to_vfbs(framebuffer); @@ -589,7 +589,7 @@ out_free_tmp: return ret; } -int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, +static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, struct drm_file *file_priv, unsigned flags, unsigned color, struct drm_clip_rect *clips, @@ -761,7 +761,7 @@ struct vmw_framebuffer_dmabuf { struct vmw_dma_buffer *buffer; }; -void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer) +static void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer) { struct vmw_framebuffer_dmabuf *vfbd = vmw_framebuffer_to_vfbd(framebuffer); @@ -947,7 +947,7 @@ static int do_dmabuf_dirty_sou(struct drm_file *file_priv, return ret; } -int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, +static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, struct drm_file *file_priv, unsigned flags, unsigned color, struct drm_clip_rect *clips, @@ -1677,7 +1677,7 @@ void vmw_disable_vblank(struct drm_device *dev, int crtc) * Small shared kms functions. */ -int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num, +static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num, struct drm_vmw_rect *rects) { struct drm_device *dev = dev_priv->dev; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 7de2ea8bd553..0fc93398bba2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -843,6 +843,7 @@ out_unlock: int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct vmw_private *dev_priv = vmw_priv(dev); union drm_vmw_surface_reference_arg *arg = (union drm_vmw_surface_reference_arg *)data; struct drm_vmw_surface_arg *req = &arg->req; @@ -854,7 +855,7 @@ int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, struct ttm_base_object *base; int ret = -EINVAL; - base = ttm_base_object_lookup(tfile, req->sid); + base = ttm_base_object_lookup_for_ref(dev_priv->tdev, req->sid); if (unlikely(base == NULL)) { DRM_ERROR("Could not find surface to reference.\n"); return -EINVAL; diff --git a/include/drm/ttm/ttm_object.h b/include/drm/ttm/ttm_object.h index 58b029894eb3..0097cc03034e 100644 --- a/include/drm/ttm/ttm_object.h +++ b/include/drm/ttm/ttm_object.h @@ -190,14 +190,26 @@ extern int ttm_base_object_init(struct ttm_object_file *tfile, * @key: Hash key * * Looks up a struct ttm_base_object with the key @key. - * Also verifies that the object is visible to the application, by - * comparing the @tfile argument and checking the object shareable flag. */ extern struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, uint32_t key); /** + * ttm_base_object_lookup_for_ref + * + * @tdev: Pointer to a struct ttm_object_device. + * @key: Hash key + * + * Looks up a struct ttm_base_object with the key @key. + * This function should only be used when the struct tfile associated with the + * caller doesn't yet have a reference to the base object. + */ + +extern struct ttm_base_object * +ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key); + +/** * ttm_base_object_unref * * @p_base: Pointer to a pointer referencing a struct ttm_base_object. @@ -218,6 +230,8 @@ extern void ttm_base_object_unref(struct ttm_base_object **p_base); * @existed: Upon completion, indicates that an identical reference object * already existed, and the refcount was upped on that object instead. * + * Checks that the base object is shareable and adds a ref object to it. + * * Adding a ref object to a base object is basically like referencing the * base object, but a user-space application holds the reference. When the * file corresponding to @tfile is closed, all its reference objects are |