diff options
author | Danilo Krummrich <dakr@kernel.org> | 2025-06-26 22:00:41 +0200 |
---|---|---|
committer | Danilo Krummrich <dakr@kernel.org> | 2025-06-28 18:08:50 +0200 |
commit | f5d3ef25d238901a76fe0277787afa44f7714739 (patch) | |
tree | 9c57a14c2cddb8d78f710f8d26e6896398650486 /samples/rust/rust_driver_pci.rs | |
parent | 46ae8fd7386abf809355d1857abac5cf2d7c3f62 (diff) |
rust: devres: get rid of Devres' inner Arc
So far Devres uses an inner memory allocation and reference count, i.e.
an inner Arc, in order to ensure that the devres callback can't run into
a use-after-free in case where the Devres object is dropped while the
devres callback runs concurrently.
Instead, use a completion in order to avoid a potential UAF: In
Devres::drop(), if we detect that we can't remove the devres action
anymore, we wait for the completion that is completed from the devres
callback. If, in turn, we were able to successfully remove the devres
action, we can just go ahead.
This, again, allows us to get rid of the internal Arc, and instead let
Devres consume an `impl PinInit<T, E>` in order to return an
`impl PinInit<Devres<T>, E>`, which enables us to get away with less
memory allocations.
Additionally, having the resulting explicit synchronization in
Devres::drop() prevents potential subtle undesired side effects of the
devres callback dropping the final Arc reference asynchronously within
the devres callback.
Reviewed-by: Benno Lossin <lossin@kernel.org>
Reviewed-by: Boqun Feng <boqun.feng@gmail.com>
Link: https://lore.kernel.org/r/20250626200054.243480-4-dakr@kernel.org
[ Move '# Invariants' below '# Examples'. - Danilo ]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Diffstat (limited to 'samples/rust/rust_driver_pci.rs')
-rw-r--r-- | samples/rust/rust_driver_pci.rs | 19 |
1 files changed, 10 insertions, 9 deletions
diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs index 15147e4401b2..5c35f1414172 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -25,8 +25,10 @@ impl TestIndex { const NO_EVENTFD: Self = Self(0); } +#[pin_data(PinnedDrop)] struct SampleDriver { pdev: ARef<pci::Device>, + #[pin] bar: Devres<Bar0>, } @@ -73,13 +75,11 @@ impl pci::Driver for SampleDriver { pdev.enable_device_mem()?; pdev.set_master(); - let bar = pdev.iomap_region_sized::<{ Regs::END }>(0, c_str!("rust_driver_pci"))?; - - let drvdata = KBox::new( - Self { + let drvdata = KBox::pin_init( + try_pin_init!(Self { pdev: pdev.into(), - bar, - }, + bar <- pdev.iomap_region_sized::<{ Regs::END }>(0, c_str!("rust_driver_pci")), + }), GFP_KERNEL, )?; @@ -90,12 +90,13 @@ impl pci::Driver for SampleDriver { Self::testdev(info, bar)? ); - Ok(drvdata.into()) + Ok(drvdata) } } -impl Drop for SampleDriver { - fn drop(&mut self) { +#[pinned_drop] +impl PinnedDrop for SampleDriver { + fn drop(self: Pin<&mut Self>) { dev_dbg!(self.pdev.as_ref(), "Remove Rust PCI driver sample.\n"); } } |