On Tue, 22 Sep 2026 10:36:32 +0200 Philipp Stanner <[email protected]> wrote:
> A FenceCallbackRegistration can stem from another party than the one > that has created a Fence. Should that party forget the registration > object (for example through a refcount cycle) and then unload the > module, a fence signaling would run into the unloaded module, causing > UAF bugs. > > So far, this has been solved by demanding that the payload data of the > registration object demanding static lifetime. > > It turns out, however, that this is harmful because the static lifetime > bubbles up to all users, ultimately potentially causing a large amount > of driver data to be static, which renders the lifetime obsolete. > > Solve this issue instead through an unsafe requirement which demands > that the user does not forget the registration object. This is also the > solution chosen by ScopedWork. Makes sense. Reviewed-by: Onur Özkan <[email protected]> > > Suggested-by: Danilo Krummrich <[email protected]> > Signed-off-by: Philipp Stanner <[email protected]> > --- > rust/kernel/dma_buf/dma_fence.rs | 16 ++++++++++++---- > 1 file changed, 12 insertions(+), 4 deletions(-) > > diff --git a/rust/kernel/dma_buf/dma_fence.rs > b/rust/kernel/dma_buf/dma_fence.rs > index 18a43e1bb442..c3fa68c4df86 100644 > --- a/rust/kernel/dma_buf/dma_fence.rs > +++ b/rust/kernel/dma_buf/dma_fence.rs > @@ -291,7 +291,7 @@ fn from(e: AllocError) -> Self { > /// } > /// } > /// ``` > -pub trait FenceCallback: Send + 'static { > +pub trait FenceCallback: Send { > /// Called when the fence is signaled. > /// > /// This is called from the fence signaling path, which may be in > interrupt > @@ -310,7 +310,7 @@ pub trait FenceCallback: Send + 'static { > /// When this object is dropped, the callback is automatically removed if it > /// hasn't been called yet. > #[pin_data(PinnedDrop)] > -pub struct FenceCallbackRegistration<T: FenceCallback + 'static> { > +pub struct FenceCallbackRegistration<T: FenceCallback> { > #[pin] > callback_foreign: Opaque<bindings::dma_fence_cb>, > callback: ManuallyDrop<T>, > @@ -326,7 +326,14 @@ impl<T: FenceCallback> FenceCallbackRegistration<T> { > /// On success the callback is pinned in place and will fire when the > fence > /// signals. On `AlreadySignaled` the callback is returned to the caller > so > /// that owned resources can be reclaimed. > - pub fn new<'a>(fence: &'a Fence, callback: T) -> impl PinInit<Self, > CallbackError<T>> + 'a > + /// > + /// # Safety > + /// > + /// `callback` must not be forgotten. > + pub unsafe fn new<'a>( > + fence: &'a Fence, > + callback: T, > + ) -> impl PinInit<Self, CallbackError<T>> + 'a > where > T: 'a, > { > @@ -693,7 +700,8 @@ struct DriverFenceData<'a, T: Send + Sync + > FenceContextOps> { > /// > /// let cb_data = CallbackData { }; > /// let waiting_fence = ARef::from(fence.as_fence()); > -/// let cb_reg = FenceCallbackRegistration::new(&waiting_fence, cb_data); > +/// // SAFETY: `cb_data`'s content is not forgotten. > +/// let cb_reg = unsafe { FenceCallbackRegistration::new(&waiting_fence, > cb_data) }; > /// let cb_reg = KBox::pin_init(cb_reg, GFP_KERNEL)?; > /// > /// // TODO signalling guards > -- > 2.55.0 >
