Skip to content

Commit 9b73bde

Browse files
ichernevrobclark
authored andcommitted
drm/msm: Fix use-after-free in msm_gem with carveout
When using gem with vram carveout the page allocation is managed via drm_mm. The necessary drm_mm_node is allocated in add_vma, but it is referenced in msm_gem_object as well. It is freed before the drm_mm_node has been deallocated leading to use-after-free on every single vram allocation. Currently put_iova is called before put_pages in both msm_gem_free_object and msm_gem_purge: put_iova -> del_vma -> kfree(vma) // vma holds drm_mm_node /* later */ put_pages -> put_pages_vram -> drm_mm_remove_node( msm_obj->vram_node) // vram_node is a ref to // drm_mm_node; in _msm_gem_new It looks like del_vma does nothing else other than freeing the vma object and removing it from it's list, so delaying the deletion should be harmless. This patch splits put_iova in put_iova_spaces and put_iova_vmas, so the vma can be freed after the mm_node has been deallocated with the mm. Note: The breaking commit separated the vma allocation from within msm_gem_object to outside, so the vram_node reference became outside the msm_gem_object allocation, and freeing order was therefore overlooked. Fixes: 4b85f7f ("drm/msm: support for an arbitrary number of address spaces") Signed-off-by: Iskren Chernev <[email protected]> Signed-off-by: Rob Clark <[email protected]>
1 parent c58eb1b commit 9b73bde

File tree

1 file changed

+22
-5
lines changed

1 file changed

+22
-5
lines changed

drivers/gpu/drm/msm/msm_gem.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -358,18 +358,31 @@ static void del_vma(struct msm_gem_vma *vma)
358358

359359
/* Called with msm_obj locked */
360360
static void
361-
put_iova(struct drm_gem_object *obj)
361+
put_iova_spaces(struct drm_gem_object *obj)
362362
{
363363
struct msm_gem_object *msm_obj = to_msm_bo(obj);
364-
struct msm_gem_vma *vma, *tmp;
364+
struct msm_gem_vma *vma;
365365

366366
WARN_ON(!msm_gem_is_locked(obj));
367367

368-
list_for_each_entry_safe(vma, tmp, &msm_obj->vmas, list) {
368+
list_for_each_entry(vma, &msm_obj->vmas, list) {
369369
if (vma->aspace) {
370370
msm_gem_purge_vma(vma->aspace, vma);
371371
msm_gem_close_vma(vma->aspace, vma);
372372
}
373+
}
374+
}
375+
376+
/* Called with msm_obj locked */
377+
static void
378+
put_iova_vmas(struct drm_gem_object *obj)
379+
{
380+
struct msm_gem_object *msm_obj = to_msm_bo(obj);
381+
struct msm_gem_vma *vma, *tmp;
382+
383+
WARN_ON(!msm_gem_is_locked(obj));
384+
385+
list_for_each_entry_safe(vma, tmp, &msm_obj->vmas, list) {
373386
del_vma(vma);
374387
}
375388
}
@@ -697,12 +710,14 @@ void msm_gem_purge(struct drm_gem_object *obj)
697710
WARN_ON(!is_purgeable(msm_obj));
698711
WARN_ON(obj->import_attach);
699712

700-
put_iova(obj);
713+
put_iova_spaces(obj);
701714

702715
msm_gem_vunmap(obj);
703716

704717
put_pages(obj);
705718

719+
put_iova_vmas(obj);
720+
706721
msm_obj->madv = __MSM_MADV_PURGED;
707722

708723
drm_vma_node_unmap(&obj->vma_node, dev->anon_inode->i_mapping);
@@ -964,7 +979,7 @@ void msm_gem_free_object(struct drm_gem_object *obj)
964979
/* object should not be on active list: */
965980
WARN_ON(is_active(msm_obj));
966981

967-
put_iova(obj);
982+
put_iova_spaces(obj);
968983

969984
if (obj->import_attach) {
970985
WARN_ON(msm_obj->vaddr);
@@ -987,6 +1002,8 @@ void msm_gem_free_object(struct drm_gem_object *obj)
9871002
msm_gem_unlock(obj);
9881003
}
9891004

1005+
put_iova_vmas(obj);
1006+
9901007
drm_gem_object_release(obj);
9911008

9921009
kfree(msm_obj);

0 commit comments

Comments
 (0)