From: sashiko-bot@kernel.org
To: "Danilo Krummrich" <dakr@kernel.org>
Cc: ojeda@kernel.org, linux-pci@vger.kernel.org
Subject: Re: [PATCH] rust: irq: make Registration compatible with lifetime-bound drivers
Date: Fri, 03 Jul 2026 21:19:01 +0000 [thread overview]
Message-ID: <20260703211901.A777F1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260703210936.1128698-1-dakr@kernel.org>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [Medium] The doctests for `Registration` and `ThreadedRegistration` demonstrate wrapping the `unsafe` constructors in safe functions, violating soundness requirements.
- [Low] Missing `// INVARIANT:` comments when constructing structs with `# Invariants` documentation.
Pre-existing issues:
- [High] Creating a Rust reference to `Registration` or `ThreadedRegistration` before its `request` field is fully initialized causes Undefined Behavior during IRQ registration.
- [Low] Missing `#[inline]` annotations on small/forwarding functions.
--
commit 8e263235d0a19c8fc9b9f8c688ce7dc1f63f4165
Author: Danilo Krummrich <dakr@kernel.org>
rust: irq: make Registration compatible with lifetime-bound drivers
This commit adapts the IRQ registration to support Higher-Ranked Lifetime
Types (HRT) device drivers by removing the static bound from IRQ handlers.
It replaces Devres indirection with direct request_irq() and free_irq()
calls during initialization and drop, tying the registration directly to
the device binding scope.
> diff --git a/rust/kernel/irq/request.rs b/rust/kernel/irq/request.rs
> --- a/rust/kernel/irq/request.rs
> +++ b/rust/kernel/irq/request.rs
[ ... ]
> @@ -163,12 +126,21 @@ pub fn irq(&self) -> u32 {
> /// //
> /// // This runs in process context and assumes `request` was previously acquired from a device.
> /// fn register_irq(
> -/// handler: impl PinInit<Data, Error>,
> /// request: IrqRequest<'_>,
> -/// ) -> Result<Arc<Registration<Data>>> {
> -/// let registration = Registration::new(request, Flags::SHARED, c"my_device", handler);
> +/// ) -> Result<Pin<KBox<Registration<'_, Data>>>> {
> +/// // SAFETY: The returned Registration is not leaked.
> +/// let registration = unsafe {
> +/// Registration::new(
> +/// request,
> +/// Flags::SHARED,
> +/// c"my_device",
> +/// try_pin_init!(Data {
> +/// completion <- Completion::new(),
> +/// }? Error),
> +/// )
> +/// };
[Severity: Medium]
Is it safe to expose this leak-sensitive object from a safe function?
The Registration::new() constructor is unsafe because callers must not
leak the returned registration to guarantee proper drop semantics.
Since register_irq() is a safe function returning a Pin<KBox<...>>,
could a safe caller leak the registration and potentially trigger a
use-after-free after the driver unbinds?
Should this example function be marked unsafe fn?
[ ... ]
> @@ -194,43 +165,44 @@ pub struct Registration<T: Handler> {
[ ... ]
> + pub unsafe fn new(
[ ... ]
> + try_pin_init!(&this in Self {
> + handler <- handler,
> + request: {
> + // SAFETY:
> + // - The callbacks are valid for use with request_irq.
> + // - If this succeeds, the slot is guaranteed to be valid until the destructor of
> + // Self runs, which will deregister the callbacks before the memory location
> + // becomes invalid.
> + // - When request_irq is called, everything that handle_irq_callback will touch
> + // has already been initialized, so it's safe for the callback to be called
> + // immediately.
> + to_result(unsafe {
> + bindings::request_irq(
> + request.irq,
> + Some(handle_irq_callback::<T>),
> + flags.into_inner(),
> + name.as_char_ptr(),
> + this.as_ptr().cast::<c_void>(),
> + )
> + })?;
> + request
> + },
[Severity: Low]
This isn't a bug, but shouldn't there be an // INVARIANT: comment inside
this initialization block to explain why the invariants for Registration
are satisfied?
[Severity: High]
This is a pre-existing issue, but does this pattern trigger undefined
behavior if the interrupt fires immediately?
During try_pin_init!, bindings::request_irq() is called while the request
field is still being initialized. If the IRQ handler is invoked before
request_irq() returns:
handle_irq_callback()
let ptr = ptr.cast_const().cast::<Registration<'_, T>>();
let registration = unsafe { &*ptr };
Could this create a Rust reference to the Registration struct while the
request field is not fully initialized?
Could the request_irq call be moved into a _: { ... } block to ensure
the struct is fully initialized before the interrupt can fire?
[ ... ]
> @@ -241,19 +213,24 @@ pub fn handler(&self) -> &T {
> }
>
> /// Wait for pending IRQ handlers on other CPUs.
> - ///
> - /// This will attempt to access the inner [`Devres`] container.
> - pub fn try_synchronize(&self) -> Result {
> - let inner = self.inner.try_access().ok_or(ENODEV)?;
> - inner.synchronize();
> - Ok(())
> + pub fn synchronize(&self) {
> + // SAFETY: `self.request.irq` is a valid registered IRQ number (type invariant).
> + unsafe { bindings::synchronize_irq(self.request.irq) };
> }
[Severity: Low]
This is a pre-existing issue and not a bug, but should this forwarding
function (and the small accessor IrqRequest::irq() in the same file) be
annotated with #[inline] according to the Rust subsystem guidelines?
[ ... ]
> @@ -375,13 +336,21 @@ fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn {
> /// // This is executing in process context and assumes that `request` was
> /// // previously acquired from a device.
> /// fn register_threaded_irq(
> -/// handler: impl PinInit<Data, Error>,
> /// request: IrqRequest<'_>,
> -/// ) -> Result<Arc<ThreadedRegistration<Data>>> {
[ ... ]
> +/// ) -> Result<Pin<KBox<ThreadedRegistration<'_, Data>>>> {
> +/// // SAFETY: The returned Registration is not leaked.
> +/// let registration = unsafe {
> +/// ThreadedRegistration::new(
[Severity: Medium]
Is it safe to expose this leak-sensitive object from a safe function?
Similar to register_irq(), the ThreadedRegistration::new() constructor
is unsafe to guarantee proper drop semantics. Does returning a Pin<KBox>
from a safe function allow a caller to trivially leak the registration?
[ ... ]
> @@ -411,44 +380,45 @@ pub struct ThreadedRegistration<T: ThreadedHandler> {
[ ... ]
> + pub unsafe fn new(
[ ... ]
> + try_pin_init!(&this in Self {
> + handler <- handler,
> + request: {
> + // SAFETY:
> + // - The callbacks are valid for use with request_threaded_irq.
[ ... ]
> + to_result(unsafe {
> + bindings::request_threaded_irq(
> + request.irq,
> + Some(handle_threaded_irq_callback::<T>),
> + Some(thread_fn_callback::<T>),
> + flags.into_inner(),
> + name.as_char_ptr(),
> + this.as_ptr().cast::<c_void>(),
> + )
> + })?;
> + request
> + },
[Severity: Low]
This isn't a bug, but shouldn't there be an // INVARIANT: comment here
explaining why the invariants are satisfied?
[Severity: High]
This is a pre-existing issue, but does this pattern also trigger undefined
behavior if the interrupt fires immediately, similar to Registration::new()?
Could this request_threaded_irq call be moved into a _: { ... } block
to avoid creating a reference to an uninitialized request field?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260703210936.1128698-1-dakr@kernel.org?part=1
next prev parent reply other threads:[~2026-07-03 21:19 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-03 21:09 [PATCH] rust: irq: make Registration compatible with lifetime-bound drivers Danilo Krummrich
2026-07-03 21:19 ` sashiko-bot [this message]
2026-07-07 13:40 ` Daniel Almeida
2026-07-07 13:54 ` Alice Ryhl
2026-07-07 14:12 ` 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=20260703211901.A777F1F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=dakr@kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=ojeda@kernel.org \
--cc=sashiko-reviews@lists.linux.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.