* [PATCH 1/2] firmware_loader: annotate doctests as `no_run`
@ 2024-07-07 0:38 Danilo Krummrich
2024-07-07 0:38 ` [PATCH 2/2] firmware_loader: fix soundness issue in `request_internal` Danilo Krummrich
0 siblings, 1 reply; 4+ messages in thread
From: Danilo Krummrich @ 2024-07-07 0:38 UTC (permalink / raw)
To: mcgrof, russ.weight, gregkh
Cc: linux-kernel, rust-for-linux, Danilo Krummrich
The doctests of `Firmware` are compile-time only tests, since they
require a proper `Device` and a valid path to a (firmware) blob in order
to do something sane on runtime - we can't satisfy both of those
requirements.
Hence, configure the example as `no_run`.
Unfortunately, the kernel's Rust build system can't consider the
`no_run` attribute yet. Hence, for the meantime, wrap the example code
into a new function and never actually call it.
Fixes: de6582833db0 ("rust: add firmware abstractions")
Signed-off-by: Danilo Krummrich <dakr@redhat.com>
---
rust/kernel/firmware.rs | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/rust/kernel/firmware.rs b/rust/kernel/firmware.rs
index 386c8fb44785..106a928a535e 100644
--- a/rust/kernel/firmware.rs
+++ b/rust/kernel/firmware.rs
@@ -26,14 +26,18 @@
///
/// # Examples
///
-/// ```
+/// ```no_run
/// # use kernel::{c_str, device::Device, firmware::Firmware};
///
+/// # fn no_run() -> Result<(), Error> {
/// # // SAFETY: *NOT* safe, just for the example to get an `ARef<Device>` instance
/// # let dev = unsafe { Device::from_raw(core::ptr::null_mut()) };
///
-/// let fw = Firmware::request(c_str!("path/to/firmware.bin"), &dev).unwrap();
+/// let fw = Firmware::request(c_str!("path/to/firmware.bin"), &dev)?;
/// let blob = fw.data();
+///
+/// # Ok(())
+/// # }
/// ```
pub struct Firmware(NonNull<bindings::firmware>);
base-commit: 997197b58bf6e22b8c6ef88a168d8292fa9acec9
--
2.45.2
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH 2/2] firmware_loader: fix soundness issue in `request_internal` 2024-07-07 0:38 [PATCH 1/2] firmware_loader: annotate doctests as `no_run` Danilo Krummrich @ 2024-07-07 0:38 ` Danilo Krummrich 2024-07-07 20:57 ` Christian Schrefl 0 siblings, 1 reply; 4+ messages in thread From: Danilo Krummrich @ 2024-07-07 0:38 UTC (permalink / raw) To: mcgrof, russ.weight, gregkh Cc: linux-kernel, rust-for-linux, Danilo Krummrich, Gary Guo `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) + } +} + /// 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 { -- 2.45.2 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH 2/2] firmware_loader: fix soundness issue in `request_internal` 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 0 siblings, 1 reply; 4+ messages in thread From: Christian Schrefl @ 2024-07-07 20:57 UTC (permalink / raw) To: Danilo Krummrich, mcgrof, russ.weight, gregkh Cc: linux-kernel, rust-for-linux, Gary Guo, rust-for-linux, linux-kernel 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? 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 ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 2/2] firmware_loader: fix soundness issue in `request_internal` 2024-07-07 20:57 ` Christian Schrefl @ 2024-07-08 11:28 ` Danilo Krummrich 0 siblings, 0 replies; 4+ messages in thread From: Danilo Krummrich @ 2024-07-08 11:28 UTC (permalink / raw) To: Christian Schrefl Cc: mcgrof, russ.weight, gregkh, linux-kernel, rust-for-linux, Gary Guo 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 > ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2024-07-08 11:28 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 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 is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).