From: Danilo Krummrich <dakr@kernel.org>
To: lossin@kernel.org, gary@garyguo.net, ojeda@kernel.org,
boqun@kernel.org, bjorn3_gh@protonmail.com,
a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu,
daniel.almeida@collabora.com, tamird@kernel.org,
acourbot@nvidia.com, work@onurozkan.dev, lyude@redhat.com,
deborah.brouwer@collabora.com
Cc: rust-for-linux@vger.kernel.org, driver-core@lists.linux.dev,
Danilo Krummrich <dakr@kernel.org>,
stable@vger.kernel.org, Sashiko <sashiko-bot@kernel.org>
Subject: [PATCH 2/2] rust: revocable: fix race between concurrent revokers
Date: Thu, 18 Jun 2026 21:32:59 +0200 [thread overview]
Message-ID: <20260618193951.601239-3-dakr@kernel.org> (raw)
In-Reply-To: <20260618193951.601239-1-dakr@kernel.org>
There is a potential race condition when two paths try to revoke a
Revocable concurrently.
It can happen with e.g. Devres, where the driver core's
devres_release_all() calls Revocable::revoke() via the devres callback,
while Devres::drop() calls revoke_nosync() on another CPU.
The revoker that does not claim the is_available swap returns
immediately, but the revoker that did may still be executing
drop_in_place() on the inner data. This can cause a use-after-free when
the other revoker's caller proceeds to drop adjacent resources that
drop_in_place() still references (e.g., Devres<DmaMappedSgt> racing with
SGTable freeing the backing sg_table and pages).
Fix this by adding a Completion to Revocable. The revoker that claims
the swap signals the Completion after drop_in_place() finishes, and any
concurrent revoker waits for it before returning. This ensures the
wrapped object is fully torn down before either path continues.
If needed, a revoke_no_wait() variant that does not wait for concurrent
revocations to complete can be added in the future.
Cc: stable@vger.kernel.org
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/dri-devel/20260612202841.2577C1F000E9@smtp.kernel.org/
Suggested-by: Gary Guo <gary@garyguo.net>
Fixes: 05aa6fb1c21d ("rust: scatterlist: Add abstraction for sg_table")
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
rust/kernel/revocable.rs | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/rust/kernel/revocable.rs b/rust/kernel/revocable.rs
index 0f4ae673256d..6d9d6ecccba1 100644
--- a/rust/kernel/revocable.rs
+++ b/rust/kernel/revocable.rs
@@ -7,7 +7,15 @@
use pin_init::Wrapper;
-use crate::{bindings, prelude::*, sync::rcu, types::Opaque};
+use crate::{
+ bindings,
+ prelude::*,
+ sync::{
+ rcu,
+ Completion, //
+ },
+ types::Opaque,
+};
use core::{
marker::PhantomData,
ops::Deref,
@@ -67,6 +75,8 @@
pub struct Revocable<T> {
is_available: AtomicBool,
#[pin]
+ revocation: Completion,
+ #[pin]
data: Opaque<T>,
}
@@ -85,6 +95,7 @@ impl<T> Revocable<T> {
pub fn new<E>(data: impl PinInit<T, E>) -> impl PinInit<Self, E> {
try_pin_init!(Self {
is_available: AtomicBool::new(true),
+ revocation <- Completion::new().map_err(|e| match e {}),
data <- Opaque::pin_init(data),
}? E)
}
@@ -168,6 +179,10 @@ unsafe fn revoke_internal<const SYNC: bool>(&self) -> bool {
// SAFETY: We know `self.data` is valid because only one CPU can succeed the
// `compare_exchange` above that takes `is_available` from `true` to `false`.
unsafe { drop_in_place(self.data.get()) };
+
+ self.revocation.complete_all();
+ } else {
+ self.revocation.wait_for_completion();
}
revoke
@@ -179,7 +194,8 @@ unsafe fn revoke_internal<const SYNC: bool>(&self) -> bool {
/// expecting that there are no concurrent users of the object.
///
/// Returns `true` if `&self` has been revoked with this call, `false` if it was revoked
- /// already.
+ /// already. In the latter case, this function waits for the concurrent revocation to complete
+ /// before returning.
///
/// # Safety
///
@@ -200,7 +216,8 @@ pub unsafe fn revoke_nosync(&self) -> bool {
/// function waits for the concurrent access to complete before dropping the wrapped object.
///
/// Returns `true` if `&self` has been revoked with this call, `false` if it was revoked
- /// already.
+ /// already. In the latter case, this function waits for the concurrent revocation to complete
+ /// before returning, ensuring the wrapped object has been fully dropped.
pub fn revoke(&self) -> bool {
// SAFETY: By passing `true` we ask `revoke_internal` to wait for the grace period to
// finish.
--
2.54.0
next prev parent reply other threads:[~2026-06-18 19:40 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-18 19:32 [PATCH 0/2] rust: revocable: fix potential race between concurrent revokers Danilo Krummrich
2026-06-18 19:32 ` [PATCH 1/2] pin-init: add PinInit::map_err() for error type conversion Danilo Krummrich
2026-06-18 19:32 ` Danilo Krummrich [this message]
2026-06-18 21:35 ` [PATCH 2/2] rust: revocable: fix race between concurrent revokers Boqun Feng
2026-06-18 22:24 ` Danilo Krummrich
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260618193951.601239-3-dakr@kernel.org \
--to=dakr@kernel.org \
--cc=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=deborah.brouwer@collabora.com \
--cc=driver-core@lists.linux.dev \
--cc=gary@garyguo.net \
--cc=lossin@kernel.org \
--cc=lyude@redhat.com \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=sashiko-bot@kernel.org \
--cc=stable@vger.kernel.org \
--cc=tamird@kernel.org \
--cc=tmgross@umich.edu \
--cc=work@onurozkan.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox