Skip to content

Commit 3f1a25e

Browse files
author
Danilo Krummrich
committed
rust: driver: address soundness issue in RegistrationOps
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 <[email protected]> Closes: https://lore.kernel.org/rust-for-linux/[email protected]/ Signed-off-by: Danilo Krummrich <[email protected]>
1 parent 5a1f97e commit 3f1a25e

File tree

3 files changed

+30
-11
lines changed

3 files changed

+30
-11
lines changed

rust/kernel/driver.rs

+20-5
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,35 @@ use macros::{pin_data, pinned_drop};
1717
/// For instance, the PCI subsystem would set `RegType` to `bindings::pci_driver` and call
1818
/// `bindings::__pci_register_driver` from `RegistrationOps::register` and
1919
/// `bindings::pci_unregister_driver` from `RegistrationOps::unregister`.
20-
pub trait RegistrationOps {
20+
///
21+
/// # Safety
22+
///
23+
/// A call to [`RegistrationOps::unregister`] for a given instance of `RegType` is only valid if a
24+
/// preceding call to [`RegistrationOps::register`] has been successful.
25+
pub unsafe trait RegistrationOps {
2126
/// The type that holds information about the registration. This is typically a struct defined
2227
/// by the C portion of the kernel.
2328
type RegType: Default;
2429

2530
/// Registers a driver.
2631
///
32+
/// # Safety
33+
///
2734
/// On success, `reg` must remain pinned and valid until the matching call to
2835
/// [`RegistrationOps::unregister`].
29-
fn register(
36+
unsafe fn register(
3037
reg: &Opaque<Self::RegType>,
3138
name: &'static CStr,
3239
module: &'static ThisModule,
3340
) -> Result;
3441

3542
/// Unregisters a driver previously registered with [`RegistrationOps::register`].
36-
fn unregister(reg: &Opaque<Self::RegType>);
43+
///
44+
/// # Safety
45+
///
46+
/// Must only be called after a preceding successful call to [`RegistrationOps::register`] for
47+
/// the same `reg`.
48+
unsafe fn unregister(reg: &Opaque<Self::RegType>);
3749
}
3850

3951
/// 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> {
6880
// just been initialised above, so it's also valid for read.
6981
let drv = unsafe { &*(ptr as *const Opaque<T::RegType>) };
7082

71-
T::register(drv, name, module)
83+
// SAFETY: `drv` is guaranteed to be pinned until `T::unregister`.
84+
unsafe { T::register(drv, name, module) }
7285
}),
7386
})
7487
}
@@ -77,7 +90,9 @@ impl<T: RegistrationOps> Registration<T> {
7790
#[pinned_drop]
7891
impl<T: RegistrationOps> PinnedDrop for Registration<T> {
7992
fn drop(self: Pin<&mut Self>) {
80-
T::unregister(&self.reg);
93+
// SAFETY: The existence of `self` guarantees that `self.reg` has previously been
94+
// successfully registered with `T::register`
95+
unsafe { T::unregister(&self.reg) };
8196
}
8297
}
8398

rust/kernel/pci.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ use kernel::prelude::*;
2323
/// An adapter for the registration of PCI drivers.
2424
pub struct Adapter<T: Driver>(T);
2525

26-
impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
26+
// SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if
27+
// a preceding call to `register` has been successful.
28+
unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
2729
type RegType = bindings::pci_driver;
2830

29-
fn register(
31+
unsafe fn register(
3032
pdrv: &Opaque<Self::RegType>,
3133
name: &'static CStr,
3234
module: &'static ThisModule,
@@ -45,7 +47,7 @@ impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
4547
})
4648
}
4749

48-
fn unregister(pdrv: &Opaque<Self::RegType>) {
50+
unsafe fn unregister(pdrv: &Opaque<Self::RegType>) {
4951
// SAFETY: `pdrv` is guaranteed to be a valid `RegType`.
5052
unsafe { bindings::pci_unregister_driver(pdrv.get()) }
5153
}

rust/kernel/platform.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ use core::ptr::addr_of_mut;
1919
/// An adapter for the registration of platform drivers.
2020
pub struct Adapter<T: Driver>(T);
2121

22-
impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
22+
// SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if
23+
// a preceding call to `register` has been successful.
24+
unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
2325
type RegType = bindings::platform_driver;
2426

25-
fn register(
27+
unsafe fn register(
2628
pdrv: &Opaque<Self::RegType>,
2729
name: &'static CStr,
2830
module: &'static ThisModule,
@@ -44,7 +46,7 @@ impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
4446
to_result(unsafe { bindings::__platform_driver_register(pdrv.get(), module.0) })
4547
}
4648

47-
fn unregister(pdrv: &Opaque<Self::RegType>) {
49+
unsafe fn unregister(pdrv: &Opaque<Self::RegType>) {
4850
// SAFETY: `pdrv` is guaranteed to be a valid `RegType`.
4951
unsafe { bindings::platform_driver_unregister(pdrv.get()) };
5052
}

0 commit comments

Comments
 (0)