[PATCH 1/1] rust: pwm: track the owner module when registering `Chip`

Michal Wilczynski m.wilczynski at samsung.com
Mon Nov 9 03:34:23 PST 2026


Hi,

On 10/28/26 23:28, Priya Bala Govindasamy wrote:
> `UnregisteredChip::register` calls the C function `__pwmchip_add`
> to register a PWM chip with the PWM core.
> `__pwmchip_add` documents that its `owner` argument is supposed to
> be `THIS_MODULE`, but `UnregisteredChip::register` passes
> `core::ptr::null_mut()`. This is acceptable for built-in drivers.
> 
> However, for loadable drivers, registering the chip with a null owner
> prevents the PWM core from taking a reference to the owner module when
> a PWM is requested or its character device is opened.
> This means that the owner module can be unloaded while references to the
> chip remain. This can lead to use-after-free and
> kernel panic.
> 
> Fix this by marking PwmOps as a `#[vtable]` trait so each implementation
> exposes its actual OwnerModule, then pass that to `__pwmchip_add()`.
> 
> Fixes: d8046cd50879 ("rust: pwm: Add complete abstraction layer")
> Reported-by: Dylan Zueck <dzueck at uci.edu>
> Assisted-by: LLM
> Signed-off-by: Priya Bala Govindasamy <pgovind2 at uci.edu>
> ---
>  drivers/pwm/pwm_th1520.rs |  1 +
>  rust/kernel/pwm.rs        | 11 +++++++++--
>  2 files changed, 10 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs
> index 728993998446..6a1f4219d6fa 100644
> --- a/drivers/pwm/pwm_th1520.rs
> +++ b/drivers/pwm/pwm_th1520.rs
> @@ -94,6 +94,7 @@ struct Th1520PwmDriverData {
>      clk: Clk,
>  }
>  
> +#[vtable]
>  impl pwm::PwmOps for Th1520PwmDriverData {
>      type WfHw = Th1520WfHw;
>  
> diff --git a/rust/kernel/pwm.rs b/rust/kernel/pwm.rs
> index 8aa47304bec3..ae7b449d67e4 100644
> --- a/rust/kernel/pwm.rs
> +++ b/rust/kernel/pwm.rs
> @@ -12,6 +12,7 @@
>      device::{self, Bound},
>      devres,
>      error::{self, to_result},
> +    module::this_module,
>      prelude::*,
>      sync::aref::{ARef, AlwaysRefCounted},
>      types::Opaque, //
> @@ -175,6 +176,7 @@ pub struct RoundedWaveform<WfHw> {
>  }
>  
>  /// Trait defining the operations for a PWM driver.
> +#[vtable]
>  pub trait PwmOps: 'static + Send + Sync + Sized {
>      /// The driver-specific hardware representation of a waveform.
>      ///
> @@ -673,9 +675,14 @@ impl<T: PwmOps> UnregisteredChip<'_, T> {
>      pub fn register(self) -> Result<ARef<Chip<T>>> {
>          let c_chip_ptr = self.chip.as_raw();
>  
> -        // SAFETY: `c_chip_ptr` points to a valid chip with its ops initialized.
> +        let owner = this_module::<T::OwnerModule>().as_ptr();
> +
> +        // SAFETY:
> +        // - `c_chip_ptr` points to a valid chip with its ops initialized.
> +        // - `owner` is the module implementing `PwmOps`. It is null for a built-in
> +        //   implementation or a valid module pointer for a loadable implementation.
>          // `__pwmchip_add` is the C function to register the chip with the PWM core.
> -        to_result(unsafe { bindings::__pwmchip_add(c_chip_ptr, core::ptr::null_mut()) })?;
> +        to_result(unsafe { bindings::__pwmchip_add(c_chip_ptr, owner) })?;
>  
>          let registration = Registration {
>              chip: ARef::clone(&self.chip),

I have managed to reproduce this issue and can confirm it's fixing the
problem.

Code wise seems OK.

Reviewed-by: Michal Wilczynski <m.wilczynski at samsung.com>
Tested-by: Michal Wilczynski <m.wilczynski at samsung.com>

Best regards,
-- 
Michal Wilczynski <m.wilczynski at samsung.com>



More information about the linux-riscv mailing list