[RFC PATCH] drm/sched: Make sure drm_sched_fence_ops don't vanish

Boris Brezillon boris.brezillon at collabora.com
Fri Aug 30 10:40:57 UTC 2024


dma_fence objects created by drm_sched might hit other subsystems, which
means the fence object might potentially outlive the drm_sched module
lifetime, and at this point the dma_fence::ops points to a memory region
that no longer exists.

In order to fix that, let's make sure the drm_sched_fence code is always
statically linked, just like dma-fence{-chain}.c does.

Cc: Luben Tuikov <ltuikov89 at gmail.com>
Cc: Matthew Brost <matthew.brost at intel.com>
Cc: "Christian König" <christian.koenig at amd.com>
Cc: Danilo Krummrich <dakr at redhat.com>
Signed-off-by: Boris Brezillon <boris.brezillon at collabora.com>
---
Just like for the other UAF fix, this is an RFC, as I'm not sure that's
how we want it fixed. The other option we have is to retain a module ref
for each initialized fence and release it when the fence is freed.
---
 drivers/gpu/drm/Makefile                |  2 +-
 drivers/gpu/drm/scheduler/Makefile      |  7 ++++++-
 drivers/gpu/drm/scheduler/sched_fence.c | 21 +++++++++------------
 drivers/gpu/drm/scheduler/sched_main.c  |  3 +++
 4 files changed, 19 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 68cc9258ffc4..b97127da58b7 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -158,7 +158,7 @@ obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
 obj-y			+= arm/
 obj-y			+= display/
 obj-$(CONFIG_DRM_TTM)	+= ttm/
-obj-$(CONFIG_DRM_SCHED)	+= scheduler/
+obj-y			+= scheduler/
 obj-$(CONFIG_DRM_RADEON)+= radeon/
 obj-$(CONFIG_DRM_AMDGPU)+= amd/amdgpu/
 obj-$(CONFIG_DRM_AMDGPU)+= amd/amdxcp/
diff --git a/drivers/gpu/drm/scheduler/Makefile b/drivers/gpu/drm/scheduler/Makefile
index 53863621829f..bc18d26f27a1 100644
--- a/drivers/gpu/drm/scheduler/Makefile
+++ b/drivers/gpu/drm/scheduler/Makefile
@@ -20,6 +20,11 @@
 # OTHER DEALINGS IN THE SOFTWARE.
 #
 #
-gpu-sched-y := sched_main.o sched_fence.o sched_entity.o
+
+# sched_fence.c contains dma_fence_ops that can't go away, so make sure it's
+# statically linked when CONFIG_DRM_SCHED=m
+obj-y += $(if $(CONFIG_DRM_SCHED),sched_fence.o,)
+
+gpu-sched-y := sched_main.o sched_entity.o
 
 obj-$(CONFIG_DRM_SCHED) += gpu-sched.o
diff --git a/drivers/gpu/drm/scheduler/sched_fence.c b/drivers/gpu/drm/scheduler/sched_fence.c
index efa2a71d98eb..ac65589476dd 100644
--- a/drivers/gpu/drm/scheduler/sched_fence.c
+++ b/drivers/gpu/drm/scheduler/sched_fence.c
@@ -39,12 +39,7 @@ static int __init drm_sched_fence_slab_init(void)
 
 	return 0;
 }
-
-static void __exit drm_sched_fence_slab_fini(void)
-{
-	rcu_barrier();
-	kmem_cache_destroy(sched_fence_slab);
-}
+subsys_initcall(drm_sched_fence_slab_init);
 
 static void drm_sched_fence_set_parent(struct drm_sched_fence *s_fence,
 				       struct dma_fence *fence)
@@ -74,6 +69,7 @@ void drm_sched_fence_scheduled(struct drm_sched_fence *fence,
 
 	dma_fence_signal(&fence->scheduled);
 }
+EXPORT_SYMBOL(drm_sched_fence_scheduled);
 
 void drm_sched_fence_finished(struct drm_sched_fence *fence, int result)
 {
@@ -81,6 +77,7 @@ void drm_sched_fence_finished(struct drm_sched_fence *fence, int result)
 		dma_fence_set_error(&fence->finished, result);
 	dma_fence_signal(&fence->finished);
 }
+EXPORT_SYMBOL(drm_sched_fence_finished);
 
 static const char *drm_sched_fence_get_driver_name(struct dma_fence *fence)
 {
@@ -118,6 +115,7 @@ void drm_sched_fence_free(struct drm_sched_fence *fence)
 	if (!WARN_ON_ONCE(fence->timeline))
 		kmem_cache_free(sched_fence_slab, fence);
 }
+EXPORT_SYMBOL(drm_sched_fence_free);
 
 /**
  * drm_sched_fence_release_scheduled - callback that fence can be freed
@@ -210,6 +208,9 @@ struct drm_sched_fence *drm_sched_fence_alloc(struct drm_sched_entity *entity,
 {
 	struct drm_sched_fence *fence = NULL;
 
+	if (unlikely(!sched_fence_slab))
+		return NULL;
+
 	fence = kmem_cache_zalloc(sched_fence_slab, GFP_KERNEL);
 	if (fence == NULL)
 		return NULL;
@@ -219,6 +220,7 @@ struct drm_sched_fence *drm_sched_fence_alloc(struct drm_sched_entity *entity,
 
 	return fence;
 }
+EXPORT_SYMBOL(drm_sched_fence_alloc);
 
 void drm_sched_fence_init(struct drm_sched_fence *fence,
 			  struct drm_sched_entity *entity)
@@ -234,9 +236,4 @@ void drm_sched_fence_init(struct drm_sched_fence *fence,
 	dma_fence_init(&fence->finished, &drm_sched_fence_ops_finished,
 		       &fence->lock, entity->fence_context + 1, seq);
 }
-
-module_init(drm_sched_fence_slab_init);
-module_exit(drm_sched_fence_slab_fini);
-
-MODULE_DESCRIPTION("DRM GPU scheduler");
-MODULE_LICENSE("GPL and additional rights");
+EXPORT_SYMBOL(drm_sched_fence_init);
diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c
index 1e31a9c8ce15..eaaf086eab30 100644
--- a/drivers/gpu/drm/scheduler/sched_main.c
+++ b/drivers/gpu/drm/scheduler/sched_main.c
@@ -1467,3 +1467,6 @@ void drm_sched_wqueue_start(struct drm_gpu_scheduler *sched)
 	queue_work(sched->submit_wq, &sched->work_free_job);
 }
 EXPORT_SYMBOL(drm_sched_wqueue_start);
+
+MODULE_DESCRIPTION("DRM GPU scheduler");
+MODULE_LICENSE("GPL and additional rights");
-- 
2.46.0



More information about the dri-devel mailing list