mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

Dma-fence objects currently suffer from a potential use after free problem where fences exported to userspace and other drivers can outlive the exporting driver, or the associated data structures. The discussion on how to address this concluded that adding reference counting to all the involved objects is not desirable, since it would need to be very wide reaching and could cause unloadable drivers if another entity would be holding onto a signaled fence reference potentially indefinitely. This patch enables the safe access by introducing and documenting a contract between fence exporters and users. It documents a set of contraints and adds helpers which a) drivers with potential to suffer from the use after free must use and b) users of the dma-fence API must use as well. Premise of the design has multiple sides: 1. Drivers (fence exporters) MUST ensure a RCU grace period between signalling a fence and freeing the driver private data associated with it. The grace period does not have to follow the signalling immediately but HAS to happen before data is freed. 2. Users of the dma-fence API marked with such requirement MUST contain the complete access to the data within a single code block guarded by rcu_read_lock() and rcu_read_unlock(). The combination of the two ensures that whoever sees the DMA_FENCE_FLAG_SIGNALED_BIT not set is guaranteed to have access to a valid fence->lock and valid data potentially accessed by the fence->ops virtual functions, until the call to rcu_read_unlock(). 3. Module unload (fence->ops) disappearing is for now explicitly not handled. That would required a more complex protection, possibly needing SRCU instead of RCU to handle callers such as dma_fence_release() and dma_fence_wait_timeout(), where race between dma_fence_enable_sw_signaling, signalling, and dereference of fence->ops->wait() would need a sleeping SRCU context. Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Tvrtko Ursulin <tursulin@ursulin.net> Link: https://lore.kernel.org/r/20250610164226.10817-4-tvrtko.ursulin@igalia.com
119 lines
2.4 KiB
C
119 lines
2.4 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#undef TRACE_SYSTEM
|
|
#define TRACE_SYSTEM dma_fence
|
|
|
|
#if !defined(_TRACE_DMA_FENCE_H) || defined(TRACE_HEADER_MULTI_READ)
|
|
#define _TRACE_DMA_FENCE_H
|
|
|
|
#include <linux/tracepoint.h>
|
|
|
|
struct dma_fence;
|
|
|
|
DECLARE_EVENT_CLASS(dma_fence,
|
|
|
|
TP_PROTO(struct dma_fence *fence),
|
|
|
|
TP_ARGS(fence),
|
|
|
|
TP_STRUCT__entry(
|
|
__string(driver, dma_fence_driver_name(fence))
|
|
__string(timeline, dma_fence_timeline_name(fence))
|
|
__field(unsigned int, context)
|
|
__field(unsigned int, seqno)
|
|
),
|
|
|
|
TP_fast_assign(
|
|
__assign_str(driver);
|
|
__assign_str(timeline);
|
|
__entry->context = fence->context;
|
|
__entry->seqno = fence->seqno;
|
|
),
|
|
|
|
TP_printk("driver=%s timeline=%s context=%u seqno=%u",
|
|
__get_str(driver), __get_str(timeline), __entry->context,
|
|
__entry->seqno)
|
|
);
|
|
|
|
/*
|
|
* Safe only for call sites which are guaranteed to not race with fence
|
|
* signaling,holding the fence->lock and having checked for not signaled, or the
|
|
* signaling path itself.
|
|
*/
|
|
DECLARE_EVENT_CLASS(dma_fence_unsignaled,
|
|
|
|
TP_PROTO(struct dma_fence *fence),
|
|
|
|
TP_ARGS(fence),
|
|
|
|
TP_STRUCT__entry(
|
|
__string(driver, fence->ops->get_driver_name(fence))
|
|
__string(timeline, fence->ops->get_timeline_name(fence))
|
|
__field(unsigned int, context)
|
|
__field(unsigned int, seqno)
|
|
),
|
|
|
|
TP_fast_assign(
|
|
__assign_str(driver);
|
|
__assign_str(timeline);
|
|
__entry->context = fence->context;
|
|
__entry->seqno = fence->seqno;
|
|
),
|
|
|
|
TP_printk("driver=%s timeline=%s context=%u seqno=%u",
|
|
__get_str(driver), __get_str(timeline), __entry->context,
|
|
__entry->seqno)
|
|
);
|
|
|
|
DEFINE_EVENT(dma_fence_unsignaled, dma_fence_emit,
|
|
|
|
TP_PROTO(struct dma_fence *fence),
|
|
|
|
TP_ARGS(fence)
|
|
);
|
|
|
|
DEFINE_EVENT(dma_fence_unsignaled, dma_fence_init,
|
|
|
|
TP_PROTO(struct dma_fence *fence),
|
|
|
|
TP_ARGS(fence)
|
|
);
|
|
|
|
DEFINE_EVENT(dma_fence, dma_fence_destroy,
|
|
|
|
TP_PROTO(struct dma_fence *fence),
|
|
|
|
TP_ARGS(fence)
|
|
);
|
|
|
|
DEFINE_EVENT(dma_fence_unsignaled, dma_fence_enable_signal,
|
|
|
|
TP_PROTO(struct dma_fence *fence),
|
|
|
|
TP_ARGS(fence)
|
|
);
|
|
|
|
DEFINE_EVENT(dma_fence_unsignaled, dma_fence_signaled,
|
|
|
|
TP_PROTO(struct dma_fence *fence),
|
|
|
|
TP_ARGS(fence)
|
|
);
|
|
|
|
DEFINE_EVENT(dma_fence, dma_fence_wait_start,
|
|
|
|
TP_PROTO(struct dma_fence *fence),
|
|
|
|
TP_ARGS(fence)
|
|
);
|
|
|
|
DEFINE_EVENT(dma_fence, dma_fence_wait_end,
|
|
|
|
TP_PROTO(struct dma_fence *fence),
|
|
|
|
TP_ARGS(fence)
|
|
);
|
|
|
|
#endif /* _TRACE_DMA_FENCE_H */
|
|
|
|
/* This part must be outside protection */
|
|
#include <trace/define_trace.h>
|