Rust fixes for v6.9

- Soundness: make internal functions generated by the 'module!' macro
    inaccessible, do not implement 'Zeroable' for 'Infallible' and
    require 'Send' for the 'Module' trait.
 
  - Build: avoid errors with "empty" files and workaround 'rustdoc' ICE.
 
  - Kconfig: depend on '!CFI_CLANG' and avoid selecting 'CONSTRUCTORS'.
 
  - Code docs: remove non-existing key from 'module!' macro example.
 
  - Docs: trivial rendering fix in arch table.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEPjU5OPd5QIZ9jqqOGXyLc2htIW0FAmYtL80ACgkQGXyLc2ht
 IW3MvA//SwYchw/ydVO/OrDV/tkH4E7vjFYIUm+AJvOpaBJUMGusFpdn0gtl7bQ8
 x4z09Y96Hn9yweejcsUvLSEyx8JBhTZ+z5/hL5FAw8atBUWnoSCoNdR+CJs/10aE
 3hRt/Zts5LEdy0CuTb3S8GOJkMCa9RE9X0XPu6M8xIq7oU4RlOl2OANy2JDT8QJq
 A8nMESOvBc1SmWimc7gl1rBO9HmRkdSxalRDuAyDv3JCTgynoJFftRVOZfDhJgZ2
 gIX0c9rLTNzxPmykAC0Ck4+WzU6/h3nPoZauUPjssV4KK1UgrSSveWoRBLA/Js+L
 GVOvb6VCthZj77wAYhojc7erjAEzrxHQ2aGlfZhQntzxIs3eagZEFE+y7HwId9LZ
 ybGaATUXz9oj6Vfh/LReM54SKbzBYzdiVO0HwJQE2CQuZjjEn7KxMtl0Vq+SRO+I
 Fa6Cd9qOxFeUv7e8xym5CVGEW2KokJEsroRmINusZJ2dk0LxLNDl9f6IAAKhUuJo
 vGggMBn1FvYJLmMtDGFYacZr3B42Xn0ANd30Lf3uOxvpSDxeghA3A7LoyXdzM2Qu
 twf6nvFOx7h1a68fbmbusnJY8G999t4Inc3htTAoFgYZiQ4UzLBLNEsFtlq4xmz8
 DNjfmFMAOQis2dzBkyVXQzKgRuUqK4UZpQFuBq9EqVT469RMsro=
 =WaUJ
 -----END PGP SIGNATURE-----

Merge tag 'rust-fixes-6.9' of https://github.com/Rust-for-Linux/linux

Pull Rust fixes from Miguel Ojeda:

 - Soundness: make internal functions generated by the 'module!' macro
   inaccessible, do not implement 'Zeroable' for 'Infallible' and
   require 'Send' for the 'Module' trait.

 - Build: avoid errors with "empty" files and workaround 'rustdoc' ICE.

 - Kconfig: depend on '!CFI_CLANG' and avoid selecting 'CONSTRUCTORS'.

 - Code docs: remove non-existing key from 'module!' macro example.

 - Docs: trivial rendering fix in arch table.

* tag 'rust-fixes-6.9' of https://github.com/Rust-for-Linux/linux:
  rust: remove `params` from `module` macro example
  kbuild: rust: force `alloc` extern to allow "empty" Rust files
  kbuild: rust: remove unneeded `@rustc_cfg` to avoid ICE
  rust: kernel: require `Send` for `Module` implementations
  rust: phy: implement `Send` for `Registration`
  rust: make mutually exclusive with CFI_CLANG
  rust: macros: fix soundness issue in `module!` macro
  rust: init: remove impl Zeroable for Infallible
  docs: rust: fix improper rendering in Arch Support page
  rust: don't select CONSTRUCTORS
This commit is contained in:
Linus Torvalds 2024-04-27 12:11:55 -07:00
commit 2c81593889
9 changed files with 132 additions and 94 deletions

View File

@ -16,7 +16,7 @@ support corresponds to ``S`` values in the ``MAINTAINERS`` file.
Architecture Level of support Constraints
============= ================ ==============================================
``arm64`` Maintained Little Endian only.
``loongarch`` Maintained -
``loongarch`` Maintained \-
``um`` Maintained ``x86_64`` only.
``x86`` Maintained ``x86_64`` only.
============= ================ ==============================================

View File

@ -1899,11 +1899,11 @@ config RUST
bool "Rust support"
depends on HAVE_RUST
depends on RUST_IS_AVAILABLE
depends on !CFI_CLANG
depends on !MODVERSIONS
depends on !GCC_PLUGINS
depends on !RANDSTRUCT
depends on !DEBUG_INFO_BTF || PAHOLE_HAS_LANG_EXCLUDE
select CONSTRUCTORS
help
Enables Rust support in the kernel.

View File

@ -175,7 +175,6 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $<
mkdir -p $(objtree)/$(obj)/test/doctests/kernel; \
OBJTREE=$(abspath $(objtree)) \
$(RUSTDOC) --test $(rust_flags) \
@$(objtree)/include/generated/rustc_cfg \
-L$(objtree)/$(obj) --extern alloc --extern kernel \
--extern build_error --extern macros \
--extern bindings --extern uapi \

View File

@ -1292,8 +1292,15 @@ impl_zeroable! {
i8, i16, i32, i64, i128, isize,
f32, f64,
// SAFETY: These are ZSTs, there is nothing to zero.
{<T: ?Sized>} PhantomData<T>, core::marker::PhantomPinned, Infallible, (),
// Note: do not add uninhabited types (such as `!` or `core::convert::Infallible`) to this list;
// creating an instance of an uninhabited type is immediate undefined behavior. For more on
// uninhabited/empty types, consult The Rustonomicon:
// <https://doc.rust-lang.org/stable/nomicon/exotic-sizes.html#empty-types>. The Rust Reference
// also has information on undefined behavior:
// <https://doc.rust-lang.org/stable/reference/behavior-considered-undefined.html>.
//
// SAFETY: These are inhabited ZSTs; there is nothing to zero and a valid value exists.
{<T: ?Sized>} PhantomData<T>, core::marker::PhantomPinned, (),
// SAFETY: Type is allowed to take any value, including all zeros.
{<T>} MaybeUninit<T>,

View File

@ -65,7 +65,7 @@ const __LOG_PREFIX: &[u8] = b"rust_kernel\0";
/// The top level entrypoint to implementing a kernel module.
///
/// For any teardown or cleanup operations, your type may implement [`Drop`].
pub trait Module: Sized + Sync {
pub trait Module: Sized + Sync + Send {
/// Called at module initialization time.
///
/// Use this method to perform whatever setup or registration your module

View File

@ -640,6 +640,10 @@ pub struct Registration {
drivers: Pin<&'static mut [DriverVTable]>,
}
// SAFETY: The only action allowed in a `Registration` instance is dropping it, which is safe to do
// from any thread because `phy_drivers_unregister` can be called from any thread context.
unsafe impl Send for Registration {}
impl Registration {
/// Registers a PHY driver.
pub fn register(

View File

@ -35,18 +35,6 @@ use proc_macro::TokenStream;
/// author: "Rust for Linux Contributors",
/// description: "My very own kernel module!",
/// license: "GPL",
/// params: {
/// my_i32: i32 {
/// default: 42,
/// permissions: 0o000,
/// description: "Example of i32",
/// },
/// writeable_i32: i32 {
/// default: 42,
/// permissions: 0o644,
/// description: "Example of i32",
/// },
/// },
/// }
///
/// struct MyModule;

View File

@ -199,17 +199,6 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
/// Used by the printing macros, e.g. [`info!`].
const __LOG_PREFIX: &[u8] = b\"{name}\\0\";
/// The \"Rust loadable module\" mark.
//
// This may be best done another way later on, e.g. as a new modinfo
// key or a new section. For the moment, keep it simple.
#[cfg(MODULE)]
#[doc(hidden)]
#[used]
static __IS_RUST_MODULE: () = ();
static mut __MOD: Option<{type_}> = None;
// SAFETY: `__this_module` is constructed by the kernel at load time and will not be
// freed until the module is unloaded.
#[cfg(MODULE)]
@ -221,6 +210,22 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
kernel::ThisModule::from_ptr(core::ptr::null_mut())
}};
// Double nested modules, since then nobody can access the public items inside.
mod __module_init {{
mod __module_init {{
use super::super::{type_};
/// The \"Rust loadable module\" mark.
//
// This may be best done another way later on, e.g. as a new modinfo
// key or a new section. For the moment, keep it simple.
#[cfg(MODULE)]
#[doc(hidden)]
#[used]
static __IS_RUST_MODULE: () = ();
static mut __MOD: Option<{type_}> = None;
// Loadable modules need to export the `{{init,cleanup}}_module` identifiers.
/// # Safety
///
@ -231,14 +236,23 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
#[no_mangle]
#[link_section = \".init.text\"]
pub unsafe extern \"C\" fn init_module() -> core::ffi::c_int {{
__init()
// SAFETY: This function is inaccessible to the outside due to the double
// module wrapping it. It is called exactly once by the C side via its
// unique name.
unsafe {{ __init() }}
}}
#[cfg(MODULE)]
#[doc(hidden)]
#[no_mangle]
pub extern \"C\" fn cleanup_module() {{
__exit()
// SAFETY:
// - This function is inaccessible to the outside due to the double
// module wrapping it. It is called exactly once by the C side via its
// unique name,
// - furthermore it is only called after `init_module` has returned `0`
// (which delegates to `__init`).
unsafe {{ __exit() }}
}}
// Built-in modules are initialized through an initcall pointer
@ -264,19 +278,35 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
#[doc(hidden)]
#[no_mangle]
pub extern \"C\" fn __{name}_init() -> core::ffi::c_int {{
__init()
// SAFETY: This function is inaccessible to the outside due to the double
// module wrapping it. It is called exactly once by the C side via its
// placement above in the initcall section.
unsafe {{ __init() }}
}}
#[cfg(not(MODULE))]
#[doc(hidden)]
#[no_mangle]
pub extern \"C\" fn __{name}_exit() {{
__exit()
// SAFETY:
// - This function is inaccessible to the outside due to the double
// module wrapping it. It is called exactly once by the C side via its
// unique name,
// - furthermore it is only called after `__{name}_init` has returned `0`
// (which delegates to `__init`).
unsafe {{ __exit() }}
}}
fn __init() -> core::ffi::c_int {{
match <{type_} as kernel::Module>::init(&THIS_MODULE) {{
/// # Safety
///
/// This function must only be called once.
unsafe fn __init() -> core::ffi::c_int {{
match <{type_} as kernel::Module>::init(&super::super::THIS_MODULE) {{
Ok(m) => {{
// SAFETY: No data race, since `__MOD` can only be accessed by this
// module and there only `__init` and `__exit` access it. These
// functions are only called once and `__exit` cannot be called
// before or during `__init`.
unsafe {{
__MOD = Some(m);
}}
@ -288,7 +318,15 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
}}
}}
fn __exit() {{
/// # Safety
///
/// This function must
/// - only be called once,
/// - be called after `__init` has been called and returned `0`.
unsafe fn __exit() {{
// SAFETY: No data race, since `__MOD` can only be accessed by this module
// and there only `__init` and `__exit` access it. These functions are only
// called once and `__init` was already called.
unsafe {{
// Invokes `drop()` on `__MOD`, which should be used for cleanup.
__MOD = None;
@ -296,6 +334,8 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
}}
{modinfo}
}}
}}
",
type_ = info.type_,
name = info.name,

View File

@ -273,7 +273,7 @@ rust_common_cmd = \
-Zallow-features=$(rust_allowed_features) \
-Zcrate-attr=no_std \
-Zcrate-attr='feature($(rust_allowed_features))' \
--extern alloc --extern kernel \
-Zunstable-options --extern force:alloc --extern kernel \
--crate-type rlib -L $(objtree)/rust/ \
--crate-name $(basename $(notdir $@)) \
--sysroot=/dev/null \