From: Daniel Almeida <daniel.almeida@collabora.com>
To: Alice Ryhl <aliceryhl@google.com>
Cc: "Mark Brown" <broonie@kernel.org>,
"Liam Girdwood" <lgirdwood@gmail.com>,
"Jean Delvare" <khali@linux-fr.org>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun@kernel.org>, "Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>,
"Alexandre Courbot" <acourbot@nvidia.com>,
linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org
Subject: Re: [PATCH] rust: regulator: do not assume that regulator_get() returns non-null
Date: Tue, 24 Mar 2026 09:42:02 -0300 [thread overview]
Message-ID: <1B177B09-D3AC-4419-A364-4489BF8D6C50@collabora.com> (raw)
In-Reply-To: <20260324-regulator-fix-v1-1-a5244afa3c15@google.com>
> On 24 Mar 2026, at 07:49, Alice Ryhl <aliceryhl@google.com> wrote:
>
> The Rust `Regulator` abstraction uses `NonNull` to wrap the underlying
> `struct regulator` pointer. When `CONFIG_REGULATOR` is disabled, the C
> stub for `regulator_get` returns `NULL`. `from_err_ptr` does not treat
> `NULL` as an error, so it was passed to `NonNull::new_unchecked`,
> causing undefined behavior.
>
> Fix this by using a raw pointer `*mut bindings::regulator` instead of
> `NonNull`. This allows `inner` to be `NULL` when `CONFIG_REGULATOR` is
> disabled, and leverages the C stubs which are designed to handle `NULL`
> or are no-ops.
>
> Fixes: 9b614ceada7c ("rust: regulator: add a bare minimum regulator abstraction")
> Reported-by: Miguel Ojeda <ojeda@kernel.org>
> Closes: https://lore.kernel.org/r/20260322193830.89324-1-ojeda@kernel.org
Sorry, this got buried in all the email I get from the list.
Thanks for picking it up, Alice.
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> ---
> rust/kernel/regulator.rs | 33 ++++++++++++++++++---------------
> 1 file changed, 18 insertions(+), 15 deletions(-)
>
> diff --git a/rust/kernel/regulator.rs b/rust/kernel/regulator.rs
> index 4f7837c7e53a..41e730cedc81 100644
> --- a/rust/kernel/regulator.rs
> +++ b/rust/kernel/regulator.rs
> @@ -23,7 +23,10 @@
> prelude::*,
> };
>
> -use core::{marker::PhantomData, mem::ManuallyDrop, ptr::NonNull};
> +use core::{
> + marker::PhantomData,
> + mem::ManuallyDrop, //
> +};
>
> mod private {
> pub trait Sealed {}
> @@ -229,15 +232,17 @@ pub fn devm_enable_optional(dev: &Device<Bound>, name: &CStr) -> Result {
> ///
> /// # Invariants
> ///
> -/// - `inner` is a non-null wrapper over a pointer to a `struct
> -/// regulator` obtained from [`regulator_get()`].
> +/// - `inner` is a pointer obtained from a successful call to
> +/// [`regulator_get()`]. It is treated as an opaque token that may only be
> +/// accessed using C API methods (e.g., it may be `NULL` if the C API returns
> +/// `NULL`).
> ///
> /// [`regulator_get()`]: https://docs.kernel.org/driver-api/regulator.html#c.regulator_get
> pub struct Regulator<State>
> where
> State: RegulatorState,
> {
> - inner: NonNull<bindings::regulator>,
> + inner: *mut bindings::regulator,
> _phantom: PhantomData<State>,
> }
>
> @@ -249,7 +254,7 @@ pub fn set_voltage(&self, min_voltage: Voltage, max_voltage: Voltage) -> Result
> // SAFETY: Safe as per the type invariants of `Regulator`.
> to_result(unsafe {
> bindings::regulator_set_voltage(
> - self.inner.as_ptr(),
> + self.inner,
> min_voltage.as_microvolts(),
> max_voltage.as_microvolts(),
> )
> @@ -259,7 +264,7 @@ pub fn set_voltage(&self, min_voltage: Voltage, max_voltage: Voltage) -> Result
> /// Gets the current voltage of the regulator.
> pub fn get_voltage(&self) -> Result<Voltage> {
> // SAFETY: Safe as per the type invariants of `Regulator`.
> - let voltage = unsafe { bindings::regulator_get_voltage(self.inner.as_ptr()) };
> + let voltage = unsafe { bindings::regulator_get_voltage(self.inner) };
>
> to_result(voltage).map(|()| Voltage::from_microvolts(voltage))
> }
> @@ -270,10 +275,8 @@ fn get_internal(dev: &Device, name: &CStr) -> Result<Regulator<T>> {
> // received from the C code.
> from_err_ptr(unsafe { bindings::regulator_get(dev.as_raw(), name.as_char_ptr()) })?;
>
> - // SAFETY: We can safely trust `inner` to be a pointer to a valid
> - // regulator if `ERR_PTR` was not returned.
> - let inner = unsafe { NonNull::new_unchecked(inner) };
> -
> + // INVARIANT: `inner` is a pointer obtained from `regulator_get()`, and
> + // the call was successful.
> Ok(Self {
> inner,
> _phantom: PhantomData,
> @@ -282,12 +285,12 @@ fn get_internal(dev: &Device, name: &CStr) -> Result<Regulator<T>> {
>
> fn enable_internal(&self) -> Result {
> // SAFETY: Safe as per the type invariants of `Regulator`.
> - to_result(unsafe { bindings::regulator_enable(self.inner.as_ptr()) })
> + to_result(unsafe { bindings::regulator_enable(self.inner) })
> }
>
> fn disable_internal(&self) -> Result {
> // SAFETY: Safe as per the type invariants of `Regulator`.
> - to_result(unsafe { bindings::regulator_disable(self.inner.as_ptr()) })
> + to_result(unsafe { bindings::regulator_disable(self.inner) })
> }
> }
>
> @@ -349,7 +352,7 @@ impl<T: IsEnabled> Regulator<T> {
> /// Checks if the regulator is enabled.
> pub fn is_enabled(&self) -> bool {
> // SAFETY: Safe as per the type invariants of `Regulator`.
> - unsafe { bindings::regulator_is_enabled(self.inner.as_ptr()) != 0 }
> + unsafe { bindings::regulator_is_enabled(self.inner) != 0 }
> }
> }
>
> @@ -359,11 +362,11 @@ fn drop(&mut self) {
> // SAFETY: By the type invariants, we know that `self` owns a
> // reference on the enabled refcount, so it is safe to relinquish it
> // now.
> - unsafe { bindings::regulator_disable(self.inner.as_ptr()) };
> + unsafe { bindings::regulator_disable(self.inner) };
> }
> // SAFETY: By the type invariants, we know that `self` owns a reference,
> // so it is safe to relinquish it now.
> - unsafe { bindings::regulator_put(self.inner.as_ptr()) };
> + unsafe { bindings::regulator_put(self.inner) };
> }
> }
>
>
> ---
> base-commit: 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
> change-id: 20260324-regulator-fix-167227abcc92
>
> Best regards,
> --
> Alice Ryhl <aliceryhl@google.com>
>
Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
next prev parent reply other threads:[~2026-03-24 12:42 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-24 10:49 Alice Ryhl
2026-03-24 12:42 ` Daniel Almeida [this message]
2026-03-24 13:32 ` Miguel Ojeda
2026-03-24 13:08 ` Mark Brown
2026-03-24 13:39 ` Miguel Ojeda
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=1B177B09-D3AC-4419-A364-4489BF8D6C50@collabora.com \
--to=daniel.almeida@collabora.com \
--cc=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=broonie@kernel.org \
--cc=dakr@kernel.org \
--cc=gary@garyguo.net \
--cc=khali@linux-fr.org \
--cc=lgirdwood@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=ojeda@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
all inboxes | Powered by JetHome®