[PATCH v3 2/23] rust: drm: kms: tie mode-object references to their owners

Mike Lothian <[email protected]>
Newsgroups org.kernel.vger.rust-for-linux,org.freedesktop.lists.dri-devel,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
The plane and encoder constructors accepted a caller-selected output
lifetime longer than the unregistered KMS device borrow.
RawPlaneState::crtc() had the same issue relative to the state borrow.
This allowed safe callers to manufacture dangling references.

Return references with the input/owner lifetime instead. Remove the
unused second lifetime from the CRTC constructor at the same time.

Fixes: 4b14e6e6259b ("rust: drm/kms: Add drm_plane bindings")
Fixes: c07f528ca38e ("rust: drm/kms: Add drm_encoder bindings")
Fixes: 8ba1abe0de4b ("rust: drm/kms: Add RawPlaneState::crtc()")

Assisted-by: Claude:claude-opus-5
Signed-off-by: Mike Lothian <[email protected]>
---
 rust/kernel/drm/kms/crtc.rs    |  2 +-
 rust/kernel/drm/kms/encoder.rs | 24 +++++++++++++++++--
 rust/kernel/drm/kms/plane.rs   | 42 +++++++++++++++++++++++++++++++---
 3 files changed, 62 insertions(+), 6 deletions(-)

diff --git a/rust/kernel/drm/kms/crtc.rs b/rust/kernel/drm/kms/crtc.rs
index b1c68838205e..683d9ee4ec25 100644
--- a/rust/kernel/drm/kms/crtc.rs
+++ b/rust/kernel/drm/kms/crtc.rs
@@ -302,7 +302,7 @@ impl<T: DriverCrtc> UnregisteredCrtc<T> {
     /// construct new [`UnregisteredCrtc`] objects.
     ///
     /// [`KmsDriver::create_objects`]: kernel::drm::kms::KmsDriver::create_objects
-    pub fn new<'a, 'b: 'a, PrimaryData, CursorData>(
+    pub fn new<'a, PrimaryData, CursorData>(
         dev: &'a UnregisteredKmsDevice<'a, T::Driver>,
         primary: &'a UnregisteredPlane<PrimaryData>,
         cursor: Option<&'a UnregisteredPlane<CursorData>>,
diff --git a/rust/kernel/drm/kms/encoder.rs b/rust/kernel/drm/kms/encoder.rs
index aa6f9fbaa5f1..f90d139cdb04 100644
--- a/rust/kernel/drm/kms/encoder.rs
+++ b/rust/kernel/drm/kms/encoder.rs
@@ -273,15 +273,35 @@ impl<T: DriverEncoder> UnregisteredEncoder<T> {
     /// A driver may use this from their [`KmsDriver::create_objects`] callback in order to
     /// construct new [`UnregisteredEncoder`] objects.
     ///
+    /// The returned encoder cannot outlive the device borrow:
+    ///
+    /// ```ignore,compile_fail
+    /// use kernel::{drm::kms::{encoder::{DriverEncoder, Type, UnregisteredEncoder},
+    ///                         UnregisteredKmsDevice},
+    ///              error::Result,
+    ///              str::CStr};
+    ///
+    /// fn reject_leaking_signature<T: DriverEncoder>() {
+    ///     let _: for<'a> fn(
+    ///         &'a UnregisteredKmsDevice<'a, T::Driver>,
+    ///         Type,
+    ///         u32,
+    ///         u32,
+    ///         Option<&CStr>,
+    ///         T::Args,
+    ///     ) -> Result<&'static UnregisteredEncoder<T>> = UnregisteredEncoder::<T>::new;
+    /// }
+    /// ```
+    ///
     /// [`KmsDriver::create_objects`]: kernel::drm::kms::KmsDriver::create_objects
-    pub fn new<'a, 'b: 'a>(
+    pub fn new<'a>(
         dev: &'a UnregisteredKmsDevice<'a, T::Driver>,
         type_: Type,
         possible_crtcs: u32,
         possible_clones: u32,
         name: Option<&CStr>,
         args: T::Args,
-    ) -> Result<&'b Self> {
+    ) -> Result<&'a Self> {
         let this: Pin<KBox<Encoder<T>>> = KBox::try_pin_init(
             try_pin_init!(Encoder {
                 encoder: Opaque::new(bindings::drm_encoder {
diff --git a/rust/kernel/drm/kms/plane.rs b/rust/kernel/drm/kms/plane.rs
index 0c549dece483..f52f9c872de3 100644
--- a/rust/kernel/drm/kms/plane.rs
+++ b/rust/kernel/drm/kms/plane.rs
@@ -255,8 +255,29 @@ impl<T: DriverPlane> UnregisteredPlane<T> {
     /// A driver may use this from their [`KmsDriver::create_objects`] callback in order to
     /// construct new [`UnregisteredPlane`] objects.
     ///
+    /// The returned plane cannot outlive the device borrow:
+    ///
+    /// ```ignore,compile_fail
+    /// use kernel::{drm::kms::{plane::{DriverPlane, Type, UnregisteredPlane},
+    ///                         UnregisteredKmsDevice},
+    ///              error::Result,
+    ///              str::CStr};
+    ///
+    /// fn reject_leaking_signature<T: DriverPlane>() {
+    ///     let _: for<'a> fn(
+    ///         &'a UnregisteredKmsDevice<'a, T::Driver>,
+    ///         u32,
+    ///         &[u32],
+    ///         Option<&[u64]>,
+    ///         Type,
+    ///         Option<&CStr>,
+    ///         T::Args,
+    ///     ) -> Result<&'static UnregisteredPlane<T>> = UnregisteredPlane::<T>::new;
+    /// }
+    /// ```
+    ///
     /// [`KmsDriver::create_objects`]: kernel::drm::kms::KmsDriver::create_objects
-    pub fn new<'a, 'b: 'a>(
+    pub fn new<'a>(
         dev: &'a UnregisteredKmsDevice<'a, T::Driver>,
         possible_crtcs: u32,
         formats: &[u32],
@@ -264,7 +285,7 @@ pub fn new<'a, 'b: 'a>(
         type_: Type,
         name: Option<&CStr>,
         args: T::Args,
-    ) -> Result<&'b Self> {
+    ) -> Result<&'a Self> {
         let this: Pin<KBox<Plane<T>>> = KBox::try_pin_init(
             try_pin_init!(Plane {
                 plane: Opaque::new(bindings::drm_plane {
@@ -597,7 +618,22 @@ fn plane(&self) -> &Self::Plane {
     }
 
     /// Return the current [`OpaqueCrtc`] assigned to this plane, if there is one.
-    fn crtc<'a, 'b: 'a, D>(&'a self) -> Option<&'b OpaqueCrtc<D>>
+    ///
+    /// The returned CRTC reference cannot outlive the plane-state borrow:
+    ///
+    /// ```ignore,compile_fail
+    /// use kernel::drm::kms::{crtc::OpaqueCrtc, plane::RawPlaneState, KmsDriver, ModeObject};
+    ///
+    /// fn reject_leaking_signature<S, D>()
+    /// where
+    ///     S: RawPlaneState,
+    ///     S::Plane: ModeObject<Driver = D>,
+    ///     D: KmsDriver,
+    /// {
+    ///     let _: for<'a> fn(&'a S) -> Option<&'static OpaqueCrtc<D>> = S::crtc::<D>;
+    /// }
+    /// ```
+    fn crtc<D>(&self) -> Option<&OpaqueCrtc<D>>
     where
         Self::Plane: ModeObject<Driver = D>,
         D: KmsDriver,
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.