All of lore.kernel.org
 help / color / mirror / Atom feed
From: Danilo Krummrich <dakr@redhat.com>
To: Christian Schrefl <chrisi.schrefl@gmail.com>
Cc: mcgrof@kernel.org, russ.weight@linux.dev,
	gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org,
	rust-for-linux@vger.kernel.org, Gary Guo <gary@garyguo.net>
Subject: Re: [PATCH 2/2] firmware_loader: fix soundness issue in `request_internal`
Date: Mon, 8 Jul 2024 13:28:42 +0200	[thread overview]
Message-ID: <ZovNap1NBusREw_-@pollux> (raw)
In-Reply-To: <dd56a9d9-08fe-4bd4-83e2-dfdc44f8c637@gmail.com>

On Sun, Jul 07, 2024 at 10:57:31PM +0200, Christian Schrefl wrote:
> Greetings.
> 
> On 07.07.24 2:38 AM, Danilo Krummrich wrote:
> > `request_internal` must be called with one of the following function
> > pointers: request_firmware(), firmware_request_nowarn(),
> > firmware_request_platform() or request_firmware_direct().
> > 
> > The previous `FwFunc` alias did not guarantee this, which is unsound.
> > 
> > In order to fix this up, implement `FwFunc` as new type with a
> > corresponding type invariant and unsafe `new` function.
> > 
> > Reported-by: Gary Guo <gary@garyguo.net>
> > Closes: https://lore.kernel.org/lkml/20240620143611.7995e0bb@eugeo/
> > Signed-off-by: Danilo Krummrich <dakr@redhat.com>
> > ---
> >  rust/kernel/firmware.rs | 32 ++++++++++++++++++++++++++------
> >  1 file changed, 26 insertions(+), 6 deletions(-)
> > 
> > diff --git a/rust/kernel/firmware.rs b/rust/kernel/firmware.rs
> > index 106a928a535e..d765ecc85d38 100644
> > --- a/rust/kernel/firmware.rs
> > +++ b/rust/kernel/firmware.rs
> > @@ -7,11 +7,24 @@
> >  use crate::{bindings, device::Device, error::Error, error::Result, str::CStr};
> >  use core::ptr::NonNull;
> >  
> > -// One of the following: `bindings::request_firmware`, `bindings::firmware_request_nowarn`,
> > -// `firmware_request_platform`, `bindings::request_firmware_direct`
> > -type FwFunc =
> > +type RawFwFunc =
> >      unsafe extern "C" fn(*mut *const bindings::firmware, *const i8, *mut bindings::device) -> i32;
> >  
> > +/// # Invariants
> > +///
> > +/// One of the following: `bindings::request_firmware`, `bindings::firmware_request_nowarn`,
> > +/// `firmware_request_platform`, `bindings::request_firmware_direct`
> > +struct FwFunc(RawFwFunc);
> > +
> > +impl FwFunc {
> > +    /// # Safety
> > +    ///
> > +    /// Must be one of the functions listed in the type invariants.
> > +    unsafe fn from_raw(func: RawFwFunc) -> Self {
> > +        Self(func)
> > +    }
> Why not write methods that construct each possible FwFunc?

Thanks, this is a good idea indeed, will send a v2.

> That way the code that needs to know abut this invariant is only inside a single impl block.
> Something like:
> impl FwFunc {
>     fn request_firmware() -> Self {
>         // # Safety
>         // As per the Type Invariant `bindings::request_firmware` is a valid vaule.
>     	FwFunc(bindings::request_firmware)
>     }
> }
> 
> > +}
> > +
> >  /// Abstraction around a C `struct firmware`.
> >  ///
> >  /// This is a simple abstraction around the C firmware API. Just like with the C API, firmware can
> > @@ -48,7 +61,7 @@ fn request_internal(name: &CStr, dev: &Device, func: FwFunc) -> Result<Self> {
> >  
> >          // SAFETY: `pfw` is a valid pointer to a NULL initialized `bindings::firmware` pointer.
> >          // `name` and `dev` are valid as by their type invariants.
> > -        let ret = unsafe { func(pfw as _, name.as_char_ptr(), dev.as_raw()) };
> > +        let ret = unsafe { func.0(pfw as _, name.as_char_ptr(), dev.as_raw()) };
> >          if ret != 0 {
> >              return Err(Error::from_errno(ret));
> >          }
> > @@ -60,13 +73,20 @@ fn request_internal(name: &CStr, dev: &Device, func: FwFunc) -> Result<Self> {
> >  
> >      /// Send a firmware request and wait for it. See also `bindings::request_firmware`.
> >      pub fn request(name: &CStr, dev: &Device) -> Result<Self> {
> > -        Self::request_internal(name, dev, bindings::request_firmware)
> > +        // SAFETY: `bindings::request_firmware` is valid by the safety requirement of `FwFunc`.
> > +        let func = unsafe { FwFunc::from_raw(bindings::request_firmware) };
> > +
> > +        Self::request_internal(name, dev, func)
> >      }
> >  
> >      /// Send a request for an optional firmware module. See also
> >      /// `bindings::firmware_request_nowarn`.
> >      pub fn request_nowarn(name: &CStr, dev: &Device) -> Result<Self> {
> > -        Self::request_internal(name, dev, bindings::firmware_request_nowarn)
> > +        // SAFETY: `bindings::firmware_request_nowarn` is valid by the safety requirement of
> > +        // `FwFunc::new`.
> > +        let func = unsafe { FwFunc::from_raw(bindings::firmware_request_nowarn) };
> > +
> > +        Self::request_internal(name, dev, func)
> >      }
> >  
> >      fn as_raw(&self) -> *mut bindings::firmware {
> 
> Cheers,
> Christian
> 


      reply	other threads:[~2024-07-08 11:28 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-07-07  0:38 [PATCH 1/2] firmware_loader: annotate doctests as `no_run` Danilo Krummrich
2024-07-07  0:38 ` [PATCH 2/2] firmware_loader: fix soundness issue in `request_internal` Danilo Krummrich
2024-07-07 20:57   ` Christian Schrefl
2024-07-08 11:28     ` Danilo Krummrich [this message]

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=ZovNap1NBusREw_-@pollux \
    --to=dakr@redhat.com \
    --cc=chrisi.schrefl@gmail.com \
    --cc=gary@garyguo.net \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mcgrof@kernel.org \
    --cc=russ.weight@linux.dev \
    --cc=rust-for-linux@vger.kernel.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.