public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Danilo Krummrich <dakr@kernel.org>
To: gregkh@linuxfoundation.org, rafael@kernel.org, ojeda@kernel.org,
	alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net,
	bjorn3_gh@protonmail.com, benno.lossin@proton.me,
	a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu,
	bhelgaas@google.com, fujita.tomonori@gmail.com
Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org,
	linux-pci@vger.kernel.org, Danilo Krummrich <dakr@kernel.org>
Subject: [PATCH 3/3] rust: driver: address soundness issue in `RegistrationOps`
Date: Fri,  3 Jan 2025 17:46:03 +0100	[thread overview]
Message-ID: <20250103164655.96590-4-dakr@kernel.org> (raw)
In-Reply-To: <20250103164655.96590-1-dakr@kernel.org>

The `RegistrationOps` trait holds some obligations to the caller and
implementers. While being documented, the trait and the corresponding
functions haven't been marked as unsafe.

Hence, markt the trait and functions unsafe and add the corresponding
safety comments.

This patch does not include any fuctional changes.

Reported-by: Gary Guo <gary@garyguo.net>
Closes: https://lore.kernel.org/rust-for-linux/20241224195821.3b43302b.gary@garyguo.net/
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/driver.rs   | 25 ++++++++++++++++++++-----
 rust/kernel/pci.rs      |  8 +++++---
 rust/kernel/platform.rs |  8 +++++---
 3 files changed, 30 insertions(+), 11 deletions(-)

diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs
index c630e65098ed..2a16d5e64e6c 100644
--- a/rust/kernel/driver.rs
+++ b/rust/kernel/driver.rs
@@ -17,23 +17,35 @@
 /// For instance, the PCI subsystem would set `RegType` to `bindings::pci_driver` and call
 /// `bindings::__pci_register_driver` from `RegistrationOps::register` and
 /// `bindings::pci_unregister_driver` from `RegistrationOps::unregister`.
-pub trait RegistrationOps {
+///
+/// # Safety
+///
+/// A call to [`RegistrationOps::unregister`] for a given instance of `RegType` is only valid if a
+/// preceding call to [`RegistrationOps::register`] has been successful.
+pub unsafe trait RegistrationOps {
     /// The type that holds information about the registration. This is typically a struct defined
     /// by the C portion of the kernel.
     type RegType: Default;
 
     /// Registers a driver.
     ///
+    /// # Safety
+    ///
     /// On success, `reg` must remain pinned and valid until the matching call to
     /// [`RegistrationOps::unregister`].
-    fn register(
+    unsafe fn register(
         reg: &Opaque<Self::RegType>,
         name: &'static CStr,
         module: &'static ThisModule,
     ) -> Result;
 
     /// Unregisters a driver previously registered with [`RegistrationOps::register`].
-    fn unregister(reg: &Opaque<Self::RegType>);
+    ///
+    /// # Safety
+    ///
+    /// Must only be called after a preceding successful call to [`RegistrationOps::register`] for
+    /// the same `reg`.
+    unsafe fn unregister(reg: &Opaque<Self::RegType>);
 }
 
 /// A [`Registration`] is a generic type that represents the registration of some driver type (e.g.
@@ -68,7 +80,8 @@ pub fn new(name: &'static CStr, module: &'static ThisModule) -> impl PinInit<Sel
                 // just been initialised above, so it's also valid for read.
                 let drv = unsafe { &*(ptr as *const Opaque<T::RegType>) };
 
-                T::register(drv, name, module)
+                // SAFETY: `drv` is guaranteed to be pinned until `T::unregister`.
+                unsafe { T::register(drv, name, module) }
             }),
         })
     }
@@ -77,7 +90,9 @@ pub fn new(name: &'static CStr, module: &'static ThisModule) -> impl PinInit<Sel
 #[pinned_drop]
 impl<T: RegistrationOps> PinnedDrop for Registration<T> {
     fn drop(self: Pin<&mut Self>) {
-        T::unregister(&self.reg);
+        // SAFETY: The existence of `self` guarantees that `self.reg` has previously been
+        // successfully registered with `T::register`
+        unsafe { T::unregister(&self.reg) };
     }
 }
 
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index d5e7f0b15303..4c98b5b9aa1e 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -23,10 +23,12 @@
 /// An adapter for the registration of PCI drivers.
 pub struct Adapter<T: Driver>(T);
 
-impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
+// SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if
+// a preceding call to `register` has been successful.
+unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
     type RegType = bindings::pci_driver;
 
-    fn register(
+    unsafe fn register(
         pdrv: &Opaque<Self::RegType>,
         name: &'static CStr,
         module: &'static ThisModule,
@@ -45,7 +47,7 @@ fn register(
         })
     }
 
-    fn unregister(pdrv: &Opaque<Self::RegType>) {
+    unsafe fn unregister(pdrv: &Opaque<Self::RegType>) {
         // SAFETY: `pdrv` is guaranteed to be a valid `RegType`.
         unsafe { bindings::pci_unregister_driver(pdrv.get()) }
     }
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
index 03287794f9d0..50e6b0421813 100644
--- a/rust/kernel/platform.rs
+++ b/rust/kernel/platform.rs
@@ -19,10 +19,12 @@
 /// An adapter for the registration of platform drivers.
 pub struct Adapter<T: Driver>(T);
 
-impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
+// SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if
+// a preceding call to `register` has been successful.
+unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
     type RegType = bindings::platform_driver;
 
-    fn register(
+    unsafe fn register(
         pdrv: &Opaque<Self::RegType>,
         name: &'static CStr,
         module: &'static ThisModule,
@@ -44,7 +46,7 @@ fn register(
         to_result(unsafe { bindings::__platform_driver_register(pdrv.get(), module.0) })
     }
 
-    fn unregister(pdrv: &Opaque<Self::RegType>) {
+    unsafe fn unregister(pdrv: &Opaque<Self::RegType>) {
         // SAFETY: `pdrv` is guaranteed to be a valid `RegType`.
         unsafe { bindings::platform_driver_unregister(pdrv.get()) };
     }
-- 
2.47.1


  parent reply	other threads:[~2025-01-03 16:47 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-01-03 16:46 [PATCH 0/3] Fixes for Rust Device / Driver abstractions Danilo Krummrich
2025-01-03 16:46 ` [PATCH 1/3] rust: pci: do not depend on CONFIG_PCI_MSI Danilo Krummrich
2025-01-07 10:31   ` Greg KH
2025-01-07 10:41     ` Danilo Krummrich
2025-01-03 16:46 ` [PATCH 2/3] rust: io: move module entry to its correct location Danilo Krummrich
2025-01-03 16:46 ` Danilo Krummrich [this message]
2025-01-05 19:07   ` [PATCH 3/3] rust: driver: address soundness issue in `RegistrationOps` Gary Guo

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=20250103164655.96590-4-dakr@kernel.org \
    --to=dakr@kernel.org \
    --cc=a.hindborg@kernel.org \
    --cc=alex.gaynor@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=benno.lossin@proton.me \
    --cc=bhelgaas@google.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=fujita.tomonori@gmail.com \
    --cc=gary@garyguo.net \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=ojeda@kernel.org \
    --cc=rafael@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=tmgross@umich.edu \
    /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