firmware_loader: fix soundness issue in request_internal
`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. Reported-by: Gary Guo <gary@garyguo.net> Closes: https://lore.kernel.org/lkml/20240620143611.7995e0bb@eugeo/ Signed-off-by: Danilo Krummrich <dakr@redhat.com> Reviewed-by: Christian Schrefl <chrisi.schrefl@gmail.com> Link: https://lore.kernel.org/r/20240708200724.3203-2-dakr@redhat.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
2c61b8c51d
commit
a23b018c3b
@ -7,10 +7,23 @@
|
|||||||
use crate::{bindings, device::Device, error::Error, error::Result, str::CStr};
|
use crate::{bindings, device::Device, error::Error, error::Result, str::CStr};
|
||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
|
|
||||||
// One of the following: `bindings::request_firmware`, `bindings::firmware_request_nowarn`,
|
/// # Invariants
|
||||||
// `firmware_request_platform`, `bindings::request_firmware_direct`
|
///
|
||||||
type FwFunc =
|
/// One of the following: `bindings::request_firmware`, `bindings::firmware_request_nowarn`,
|
||||||
unsafe extern "C" fn(*mut *const bindings::firmware, *const i8, *mut bindings::device) -> i32;
|
/// `bindings::firmware_request_platform`, `bindings::request_firmware_direct`.
|
||||||
|
struct FwFunc(
|
||||||
|
unsafe extern "C" fn(*mut *const bindings::firmware, *const i8, *mut bindings::device) -> i32,
|
||||||
|
);
|
||||||
|
|
||||||
|
impl FwFunc {
|
||||||
|
fn request() -> Self {
|
||||||
|
Self(bindings::request_firmware)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_nowarn() -> Self {
|
||||||
|
Self(bindings::firmware_request_nowarn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Abstraction around a C `struct firmware`.
|
/// Abstraction around a C `struct firmware`.
|
||||||
///
|
///
|
||||||
@ -48,7 +61,7 @@ impl Firmware {
|
|||||||
|
|
||||||
// SAFETY: `pfw` is a valid pointer to a NULL initialized `bindings::firmware` pointer.
|
// SAFETY: `pfw` is a valid pointer to a NULL initialized `bindings::firmware` pointer.
|
||||||
// `name` and `dev` are valid as by their type invariants.
|
// `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 {
|
if ret != 0 {
|
||||||
return Err(Error::from_errno(ret));
|
return Err(Error::from_errno(ret));
|
||||||
}
|
}
|
||||||
@ -60,13 +73,13 @@ impl Firmware {
|
|||||||
|
|
||||||
/// Send a firmware request and wait for it. See also `bindings::request_firmware`.
|
/// Send a firmware request and wait for it. See also `bindings::request_firmware`.
|
||||||
pub fn request(name: &CStr, dev: &Device) -> Result<Self> {
|
pub fn request(name: &CStr, dev: &Device) -> Result<Self> {
|
||||||
Self::request_internal(name, dev, bindings::request_firmware)
|
Self::request_internal(name, dev, FwFunc::request())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a request for an optional firmware module. See also
|
/// Send a request for an optional firmware module. See also
|
||||||
/// `bindings::firmware_request_nowarn`.
|
/// `bindings::firmware_request_nowarn`.
|
||||||
pub fn request_nowarn(name: &CStr, dev: &Device) -> Result<Self> {
|
pub fn request_nowarn(name: &CStr, dev: &Device) -> Result<Self> {
|
||||||
Self::request_internal(name, dev, bindings::firmware_request_nowarn)
|
Self::request_internal(name, dev, FwFunc::request_nowarn())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_raw(&self) -> *mut bindings::firmware {
|
fn as_raw(&self) -> *mut bindings::firmware {
|
||||||
|
Loading…
Reference in New Issue
Block a user