* [PATCH] rust: DmaFence: Remove static lifetime
@ 2026-09-22 8:36 Philipp Stanner
2026-09-22 8:50 ` Onur Özkan
2026-09-22 10:12 ` Gary Guo
0 siblings, 2 replies; 3+ messages in thread
From: Philipp Stanner @ 2026-09-22 8:36 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, Sumit Semwal,
Christian König
Cc: rust-for-linux, linux-kernel, linux-media, dri-devel, Philipp Stanner
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.
Suggested-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Philipp Stanner <phasta@kernel.org>
---
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
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH] rust: DmaFence: Remove static lifetime
2026-09-22 8:36 [PATCH] rust: DmaFence: Remove static lifetime Philipp Stanner
@ 2026-09-22 8:50 ` Onur Özkan
2026-09-22 10:12 ` Gary Guo
1 sibling, 0 replies; 3+ messages in thread
From: Onur Özkan @ 2026-09-22 8:50 UTC (permalink / raw)
To: Philipp Stanner
Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Sumit Semwal, Christian König,
rust-for-linux, linux-kernel, linux-media, dri-devel,
Onur Özkan
On Tue, 22 Sep 2026 10:36:32 +0200
Philipp Stanner <phasta@kernel.org> 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 <work@onurozkan.dev>
>
> Suggested-by: Danilo Krummrich <dakr@kernel.org>
> Signed-off-by: Philipp Stanner <phasta@kernel.org>
> ---
> 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
>
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH] rust: DmaFence: Remove static lifetime
2026-09-22 8:36 [PATCH] rust: DmaFence: Remove static lifetime Philipp Stanner
2026-09-22 8:50 ` Onur Özkan
@ 2026-09-22 10:12 ` Gary Guo
1 sibling, 0 replies; 3+ messages in thread
From: Gary Guo @ 2026-09-22 10:12 UTC (permalink / raw)
To: Philipp Stanner, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, Sumit Semwal,
Christian König
Cc: rust-for-linux, linux-kernel, linux-media, dri-devel
On Tue Sep 22, 2026 at 9:36 AM BST, Philipp Stanner 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.
>
> Suggested-by: Danilo Krummrich <dakr@kernel.org>
> Signed-off-by: Philipp Stanner <phasta@kernel.org>
> ---
> 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.
This should rather say "the callback registration" must not be forgotten (i.e.
not the `callback` parameter, but the constructed init value).
Best,
Gary
> + 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
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-09-22 10:12 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-22 8:36 [PATCH] rust: DmaFence: Remove static lifetime Philipp Stanner
2026-09-22 8:50 ` Onur Özkan
2026-09-22 10:12 ` Gary Guo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®