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 Architecture Level of support Constraints
============= ================ ============================================== ============= ================ ==============================================
``arm64`` Maintained Little Endian only. ``arm64`` Maintained Little Endian only.
``loongarch`` Maintained - ``loongarch`` Maintained \-
``um`` Maintained ``x86_64`` only. ``um`` Maintained ``x86_64`` only.
``x86`` Maintained ``x86_64`` only. ``x86`` Maintained ``x86_64`` only.
============= ================ ============================================== ============= ================ ==============================================

View File

@ -1899,11 +1899,11 @@ config RUST
bool "Rust support" bool "Rust support"
depends on HAVE_RUST depends on HAVE_RUST
depends on RUST_IS_AVAILABLE depends on RUST_IS_AVAILABLE
depends on !CFI_CLANG
depends on !MODVERSIONS depends on !MODVERSIONS
depends on !GCC_PLUGINS depends on !GCC_PLUGINS
depends on !RANDSTRUCT depends on !RANDSTRUCT
depends on !DEBUG_INFO_BTF || PAHOLE_HAS_LANG_EXCLUDE depends on !DEBUG_INFO_BTF || PAHOLE_HAS_LANG_EXCLUDE
select CONSTRUCTORS
help help
Enables Rust support in the kernel. 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; \ mkdir -p $(objtree)/$(obj)/test/doctests/kernel; \
OBJTREE=$(abspath $(objtree)) \ OBJTREE=$(abspath $(objtree)) \
$(RUSTDOC) --test $(rust_flags) \ $(RUSTDOC) --test $(rust_flags) \
@$(objtree)/include/generated/rustc_cfg \
-L$(objtree)/$(obj) --extern alloc --extern kernel \ -L$(objtree)/$(obj) --extern alloc --extern kernel \
--extern build_error --extern macros \ --extern build_error --extern macros \
--extern bindings --extern uapi \ --extern bindings --extern uapi \

View File

@ -1292,8 +1292,15 @@ impl_zeroable! {
i8, i16, i32, i64, i128, isize, i8, i16, i32, i64, i128, isize,
f32, f64, f32, f64,
// SAFETY: These are ZSTs, there is nothing to zero. // Note: do not add uninhabited types (such as `!` or `core::convert::Infallible`) to this list;
{<T: ?Sized>} PhantomData<T>, core::marker::PhantomPinned, Infallible, (), // 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. // SAFETY: Type is allowed to take any value, including all zeros.
{<T>} MaybeUninit<T>, {<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. /// The top level entrypoint to implementing a kernel module.
/// ///
/// For any teardown or cleanup operations, your type may implement [`Drop`]. /// 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. /// Called at module initialization time.
/// ///
/// Use this method to perform whatever setup or registration your module /// 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]>, 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 { impl Registration {
/// Registers a PHY driver. /// Registers a PHY driver.
pub fn register( pub fn register(

View File

@ -35,18 +35,6 @@ use proc_macro::TokenStream;
/// author: "Rust for Linux Contributors", /// author: "Rust for Linux Contributors",
/// description: "My very own kernel module!", /// description: "My very own kernel module!",
/// license: "GPL", /// 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; /// struct MyModule;

View File

@ -199,17 +199,6 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
/// Used by the printing macros, e.g. [`info!`]. /// Used by the printing macros, e.g. [`info!`].
const __LOG_PREFIX: &[u8] = b\"{name}\\0\"; 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 // SAFETY: `__this_module` is constructed by the kernel at load time and will not be
// freed until the module is unloaded. // freed until the module is unloaded.
#[cfg(MODULE)] #[cfg(MODULE)]
@ -221,81 +210,132 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
kernel::ThisModule::from_ptr(core::ptr::null_mut()) kernel::ThisModule::from_ptr(core::ptr::null_mut())
}}; }};
// Loadable modules need to export the `{{init,cleanup}}_module` identifiers. // Double nested modules, since then nobody can access the public items inside.
/// # Safety mod __module_init {{
/// mod __module_init {{
/// This function must not be called after module initialization, because it may be use super::super::{type_};
/// freed after that completes.
#[cfg(MODULE)]
#[doc(hidden)]
#[no_mangle]
#[link_section = \".init.text\"]
pub unsafe extern \"C\" fn init_module() -> core::ffi::c_int {{
__init()
}}
#[cfg(MODULE)] /// The \"Rust loadable module\" mark.
#[doc(hidden)] //
#[no_mangle] // This may be best done another way later on, e.g. as a new modinfo
pub extern \"C\" fn cleanup_module() {{ // key or a new section. For the moment, keep it simple.
__exit() #[cfg(MODULE)]
}} #[doc(hidden)]
#[used]
static __IS_RUST_MODULE: () = ();
// Built-in modules are initialized through an initcall pointer static mut __MOD: Option<{type_}> = None;
// and the identifiers need to be unique.
#[cfg(not(MODULE))]
#[cfg(not(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS))]
#[doc(hidden)]
#[link_section = \"{initcall_section}\"]
#[used]
pub static __{name}_initcall: extern \"C\" fn() -> core::ffi::c_int = __{name}_init;
#[cfg(not(MODULE))] // Loadable modules need to export the `{{init,cleanup}}_module` identifiers.
#[cfg(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS)] /// # Safety
core::arch::global_asm!( ///
r#\".section \"{initcall_section}\", \"a\" /// This function must not be called after module initialization, because it may be
__{name}_initcall: /// freed after that completes.
.long __{name}_init - . #[cfg(MODULE)]
.previous #[doc(hidden)]
\"# #[no_mangle]
); #[link_section = \".init.text\"]
pub unsafe extern \"C\" fn init_module() -> core::ffi::c_int {{
// 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(not(MODULE))] #[cfg(MODULE)]
#[doc(hidden)] #[doc(hidden)]
#[no_mangle] #[no_mangle]
pub extern \"C\" fn __{name}_init() -> core::ffi::c_int {{ pub extern \"C\" fn cleanup_module() {{
__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,
// - furthermore it is only called after `init_module` has returned `0`
// (which delegates to `__init`).
unsafe {{ __exit() }}
}}
#[cfg(not(MODULE))] // Built-in modules are initialized through an initcall pointer
#[doc(hidden)] // and the identifiers need to be unique.
#[no_mangle] #[cfg(not(MODULE))]
pub extern \"C\" fn __{name}_exit() {{ #[cfg(not(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS))]
__exit() #[doc(hidden)]
}} #[link_section = \"{initcall_section}\"]
#[used]
pub static __{name}_initcall: extern \"C\" fn() -> core::ffi::c_int = __{name}_init;
fn __init() -> core::ffi::c_int {{ #[cfg(not(MODULE))]
match <{type_} as kernel::Module>::init(&THIS_MODULE) {{ #[cfg(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS)]
Ok(m) => {{ core::arch::global_asm!(
unsafe {{ r#\".section \"{initcall_section}\", \"a\"
__MOD = Some(m); __{name}_initcall:
.long __{name}_init - .
.previous
\"#
);
#[cfg(not(MODULE))]
#[doc(hidden)]
#[no_mangle]
pub extern \"C\" fn __{name}_init() -> core::ffi::c_int {{
// 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() {{
// 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() }}
}}
/// # 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);
}}
return 0;
}}
Err(e) => {{
return e.to_errno();
}}
}} }}
return 0;
}} }}
Err(e) => {{
return e.to_errno(); /// # 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;
}}
}} }}
{modinfo}
}} }}
}} }}
fn __exit() {{
unsafe {{
// Invokes `drop()` on `__MOD`, which should be used for cleanup.
__MOD = None;
}}
}}
{modinfo}
", ",
type_ = info.type_, type_ = info.type_,
name = info.name, name = info.name,

View File

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