]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
rust: driver: address soundness issue in `RegistrationOps`
authorDanilo Krummrich <dakr@kernel.org>
Fri, 3 Jan 2025 16:46:03 +0000 (17:46 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 7 Jan 2025 10:31:45 +0000 (11:31 +0100)
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>
Reviewed-by: Gary Guo <gary@garyguo.net>
Link: https://lore.kernel.org/r/20250103164655.96590-4-dakr@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
rust/kernel/driver.rs
rust/kernel/pci.rs
rust/kernel/platform.rs

index c630e65098ed77fa1499c9d4cab69555358b565f..2a16d5e64e6c97d6b80fcf276d41b9459dd46d2f 100644 (file)
@@ -17,23 +17,35 @@ use macros::{pin_data, pinned_drop};
 /// 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 @@ impl<T: RegistrationOps> Registration<T> {
                 // 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 @@ impl<T: RegistrationOps> Registration<T> {
 #[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) };
     }
 }
 
index d5e7f0b1530319b9c8e106901c4bfdcfe3a871b7..4c98b5b9aa1e92d5a363172a5ae54510769a40f1 100644 (file)
@@ -23,10 +23,12 @@ use kernel::prelude::*;
 /// 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 @@ impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
         })
     }
 
-    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()) }
     }
index 03287794f9d01a5b318c2a678ab752b1458ab072..50e6b0421813224f39ce9fdf592a6cfeffe4e150 100644 (file)
@@ -19,10 +19,12 @@ use core::ptr::addr_of_mut;
 /// 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 @@ impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
         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()) };
     }