History

Merge tag 'rust-fixes-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux

Pull Rust fixes from Miguel Ojeda: "Toolchain and infrastructure: - Fix KCFI failures, such as in Rust doctests, by disabling function merging when CFI is enabled. Gary reported the LLVM bug to upstream and it is now fixed in their mainline. - Fix 'objtool' fallthrough warnings under the experimental 'CONFIG_RUST_INLINE_HELPERS' by passing (for the combined Rust and helpers code) the LLVM options needed to preserve the unreachable traps that 'rustc' normally emits. In addition, fix 'objtool' errors when LTO is enabled on top, by also filtering out the LTO flags (for the combined Rust and helpers code) so that the traps are kept in place. - Fix 'objtool' warnings by adding one more 'noreturn' function. - Fix 'make rusttest' target when the 'rustc-dev' component is installed and Rust >= 1.82.0, <= 1.87.0 is used. 'kernel' crate: - 'num' module: fix soundness issue in the 'Bounded' conversion from 'bool' by restricting the conversions to unsigned 'Bounded'. - 'jump_label' module: fix future 'make rusttest' target failures when 'ARCH=' is set to an arch different than the host's. - 'list' module: fix incorrect 'pop_back()' comment" * tag 'rust-fixes-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: rust: kbuild: disambiguate `zerocopy_derive` for `rusttest` rust: num: restrict bool conversion to unsigned Bounded kbuild: rust: keep Rust objects out of Clang LTO with inline helpers kbuild: rust: preserve unreachable traps with inline helpers rust: cfi: disable function merging if CFI is enabled rust: jump_label: skip arch-specific asm in `testlib` builds objtool/rust: add one more `noreturn` Rust function rust: kernel: list: fix incorrect pop_back example comment

Linus Torvalds committed 2 months ago

Commit f59c0742 parents 0fe792f 1b0bab47 files · +53 −14Browse files

Unified · Split

7 files
  1. Makefile +12 −1
  2. rust/Makefile +4 −2
  3. rust/kernel/jump_label.rs +12 −0
  4. rust/kernel/list.rs +1 −1
  5. rust/kernel/num/bounded.rs +21 −9
  6. scripts/Makefile.build +2 −1
  7. tools/objtool/check.c +1 −0
Makefile+12−1
@@ -1083,6 +1083,16 @@ endif · 1082 unmodified lines
1083export CC_FLAGS_SCS1083export CC_FLAGS_SCS
1084endif1084endif
1085 1085
1086ifdef CONFIG_RUST_INLINE_HELPERS
1087# `rustc` normally emits traps for unreachable paths during code generation.
1088# With inline helpers, Clang performs code generation from the linked bitcode
1089# instead, so request the same behavior explicitly. Otherwise `objtool` may
1090# follow an impossible Rust path into the next function.
1091CC_FLAGS_RUST_INLINE_HELPERS := -mllvm -trap-unreachable \
1092 -mllvm -no-trap-after-noreturn
1093export CC_FLAGS_RUST_INLINE_HELPERS
1094endif
1095
1086ifdef CONFIG_LTO_CLANG1096ifdef CONFIG_LTO_CLANG
1087ifdef CONFIG_LTO_CLANG_FULL1097ifdef CONFIG_LTO_CLANG_FULL
1088CC_FLAGS_LTO := -flto1098CC_FLAGS_LTO := -flto
@@ -1118,7 +1128,8 @@ endif · 29 unmodified lines
1118ifdef CONFIG_RUST1128ifdef CONFIG_RUST
1119 # Always pass -Zsanitizer-cfi-normalize-integers as CONFIG_RUST selects1129 # Always pass -Zsanitizer-cfi-normalize-integers as CONFIG_RUST selects
1120 # CONFIG_CFI_ICALL_NORMALIZE_INTEGERS.1130 # CONFIG_CFI_ICALL_NORMALIZE_INTEGERS.
1121 RUSTC_FLAGS_CFI := -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers1131 # Disable function merging as LLVM incorrectly merges functions with different KCFI types.
1132 RUSTC_FLAGS_CFI := -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers -Zmerge-functions=disabled
1122 KBUILD_RUSTFLAGS += $(RUSTC_FLAGS_CFI)1133 KBUILD_RUSTFLAGS += $(RUSTC_FLAGS_CFI)
1123 export RUSTC_FLAGS_CFI1134 export RUSTC_FLAGS_CFI
1124endif1135endif
rust/Makefile+4−2
@@ -354,7 +354,8 @@ rusttestlib-pin_init: $(src)/pin-init/src/lib.rs rusttestlib-macros \ · 353 unmodified lines
354rusttestlib-kernel: private rustc_target_flags = --extern ffi \354rusttestlib-kernel: private rustc_target_flags = --extern ffi \
355 --extern build_error --extern macros --extern pin_init \355 --extern build_error --extern macros --extern pin_init \
356 --extern bindings --extern uapi \356 --extern bindings --extern uapi \
357 --extern zerocopy=$(objtree)/$(obj)/test/libzerocopy.rlib --extern zerocopy_derive357 --extern zerocopy=$(objtree)/$(obj)/test/libzerocopy.rlib \
358 --extern zerocopy_derive=$(objtree)/$(obj)/test/$(libzerocopy_derive_name)
358rusttestlib-kernel: $(src)/kernel/lib.rs rusttestlib-bindings rusttestlib-uapi \359rusttestlib-kernel: $(src)/kernel/lib.rs rusttestlib-bindings rusttestlib-uapi \
359 rusttestlib-build_error rusttestlib-pin_init $(obj)/$(libmacros_name) \360 rusttestlib-build_error rusttestlib-pin_init $(obj)/$(libmacros_name) \
360 $(obj)/bindings.o rusttestlib-zerocopy rusttestlib-zerocopy_derive FORCE361 $(obj)/bindings.o rusttestlib-zerocopy rusttestlib-zerocopy_derive FORCE
@@ -656,7 +657,8 @@ quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L · 295 unmodified lines
656 -Zunstable-options \657 -Zunstable-options \
657 $(if $(link_helper),;$(LLVM_LINK) --internalize --suppress-warnings $(patsubst %.o,%.bc,$@) \658 $(if $(link_helper),;$(LLVM_LINK) --internalize --suppress-warnings $(patsubst %.o,%.bc,$@) \
658 $(obj)/helpers/helpers$(if $(part-of-module),_module).bc -o $(patsubst %.o,%.m.bc,$@); \659 $(obj)/helpers/helpers$(if $(part-of-module),_module).bc -o $(patsubst %.o,%.m.bc,$@); \
659 $(CC) $(CLANG_FLAGS) $(KBUILD_CFLAGS) -Wno-override-module -c $(patsubst %.o,%.m.bc,$@) -o $@ \660 $(CC) $(CLANG_FLAGS) $(filter-out $(CC_FLAGS_LTO),$(KBUILD_CFLAGS)) \
661 $(CC_FLAGS_RUST_INLINE_HELPERS) -Wno-override-module -c $(patsubst %.o,%.m.bc,$@) -o $@ \
660 $(cmd_ld_single)) \662 $(cmd_ld_single)) \
661 $(if $(rustc_objcopy),;$(OBJCOPY) $(rustc_objcopy) $@) \663 $(if $(rustc_objcopy),;$(OBJCOPY) $(rustc_objcopy) $@) \
662 $(cmd_objtool)664 $(cmd_objtool)
rust/kernel/jump_label.rs+12−0
@@ -44,6 +44,7 @@ const _: &str = include!(concat!( · 43 unmodified lines
44 44
45#[macro_export]45#[macro_export]
46#[doc(hidden)]46#[doc(hidden)]
47#[cfg(not(testlib))]
47#[cfg(CONFIG_JUMP_LABEL)]48#[cfg(CONFIG_JUMP_LABEL)]
48macro_rules! arch_static_branch {49macro_rules! arch_static_branch {
49 ($key:path, $keytyp:ty, $field:ident, $branch:expr) => {'my_label: {50 ($key:path, $keytyp:ty, $field:ident, $branch:expr) => {'my_label: {
@@ -61,6 +62,17 @@ macro_rules! arch_static_branch { · 11 unmodified lines
61 }};62 }};
62}63}
63 64
65#[macro_export]
66#[doc(hidden)]
67#[cfg(testlib)]
68#[cfg(CONFIG_JUMP_LABEL)]
69macro_rules! arch_static_branch {
70 ($key:path, $keytyp:ty, $field:ident, $branch:expr) => {
71 // The asm falls through until patched, which never happens on the host.
72 false
73 };
74}
75
64#[cfg(CONFIG_JUMP_LABEL)]76#[cfg(CONFIG_JUMP_LABEL)]
65pub use arch_static_branch;77pub use arch_static_branch;
66 78
rust/kernel/list.rs+1−1
@@ -249,7 +249,7 @@ pub use self::arc_field::{ · 248 unmodified lines
249/// assert_eq!(list.iter().count(), 3);249/// assert_eq!(list.iter().count(), 3);
250/// }250/// }
251///251///
252/// // Pop the items from the list using `pop_front()` and verify the content.252/// // Pop the items from the list using `pop_back()` and verify the content.
253/// {253/// {
254/// assert_eq!(list.pop_back().ok_or(EINVAL)?.value.foo(), ("a", 15));254/// assert_eq!(list.pop_back().ok_or(EINVAL)?.value.foo(), ("a", 15));
255/// assert_eq!(list.pop_back().ok_or(EINVAL)?.value.foo(), ("a", 32));255/// assert_eq!(list.pop_back().ok_or(EINVAL)?.value.foo(), ("a", 32));
rust/kernel/num/bounded.rs+21−9
@@ -13,7 +13,10 @@ use core::{ · 12 unmodified lines
13};13};
14 14
15use kernel::{15use kernel::{
16 num::Integer,16 num::{
17 Integer,
18 Unsigned, //
19 },
17 prelude::*, //20 prelude::*, //
18};21};
19 22
@@ -174,13 +177,16 @@ fn fits_within<T: Integer>(value: T, num_bits: u32) -> bool { · 154 unmodified lines
174/// // `u8` (regardless of the passed value).177/// // `u8` (regardless of the passed value).
175/// // let _ = Bounded::<u32, 6>::from(10u8);178/// // let _ = Bounded::<u32, 6>::from(10u8);
176///179///
177/// // Booleans can be converted into single-bit `Bounded`s.180/// // Booleans can be converted into unsigned `Bounded`s.
178///181///
179/// let v = Bounded::<u64, 1>::from(false);182/// let v = Bounded::<u64, 1>::from(false);
180/// assert_eq!(v.get(), 0);183/// assert_eq!(v.get(), 0);
181///184///
182/// let v = Bounded::<u64, 1>::from(true);185/// let v = Bounded::<u64, 1>::from(true);
183/// assert_eq!(v.get(), 1);186/// assert_eq!(v.get(), 1);
187///
188/// // This does not build because `i8` is signed.
189/// // let _ = Bounded::<i8, 2>::from(true);
184/// ```190/// ```
185///191///
186/// Infallible conversions from a [`Bounded`] to a primitive integer are also supported, and192/// Infallible conversions from a [`Bounded`] to a primitive integer are also supported, and
@@ -203,12 +209,16 @@ fn fits_within<T: Integer>(value: T, num_bits: u32) -> bool { · 16 unmodified lines
203/// let _v = Bounded::<u32, 10>::new::<10>();209/// let _v = Bounded::<u32, 10>::new::<10>();
204/// // assert_eq!(u8::from(_v), 10);210/// // assert_eq!(u8::from(_v), 10);
205///211///
206/// // Single-bit `Bounded`s can be converted into a boolean.212/// // Unsigned single-bit `Bounded`s can be converted into a boolean.
207/// let v = Bounded::<u8, 1>::new::<1>();213/// let v = Bounded::<u8, 1>::new::<1>();
208/// assert_eq!(bool::from(v), true);214/// assert_eq!(bool::from(v), true);
209///215///
210/// let v = Bounded::<u8, 1>::new::<0>();216/// let v = Bounded::<u8, 1>::new::<0>();
211/// assert_eq!(bool::from(v), false);217/// assert_eq!(bool::from(v), false);
218///
219/// // This does not build because `i8` is signed.
220/// // let v = Bounded::<i8, 1>::new::<-1>();
221/// // let _ = bool::from(v);
212/// ```222/// ```
213///223///
214/// Fallible conversions from any primitive integer to any [`Bounded`] are also supported using the224/// Fallible conversions from any primitive integer to any [`Bounded`] are also supported using the
@@ -1109,31 +1119,33 @@ impl_into_primitive!( · 894 unmodified lines
1109 i8 i16 i32 i64 isize1119 i8 i16 i32 i64 isize
1110);1120);
1111 1121
1112// Single-bit `Bounded`s can be converted from/to a boolean.1122// Unsigned single-bit `Bounded`s can be converted to a boolean.
1113 1123
1114impl<T> From<Bounded<T, 1>> for bool1124impl<T> From<Bounded<T, 1>> for bool
1115where1125where
1116 T: Integer + Zeroable,1126 T: Integer<Signedness = Unsigned> + Zeroable,
1117{1127{
1118 fn from(value: Bounded<T, 1>) -> Self {1128 fn from(value: Bounded<T, 1>) -> Self {
1119 value.get() != Zeroable::zeroed()1129 value.get() != Zeroable::zeroed()
1120 }1130 }
1121}1131}
1122 1132
1133// Booleans can be converted to unsigned `Bounded`s.
1134
1123impl<T, const N: u32> From<bool> for Bounded<T, N>1135impl<T, const N: u32> From<bool> for Bounded<T, N>
1124where1136where
1125 T: Integer + From<bool>,1137 T: Integer<Signedness = Unsigned> + From<bool>,
1126{1138{
1127 fn from(value: bool) -> Self {1139 fn from(value: bool) -> Self {
1128 // SAFETY: A boolean can be represented using a single bit, and thus fits within any1140 // SAFETY: A boolean is represented by `0` or `1`, so it fits within any valid unsigned
1129 // integer type for any `N` > 0.1141 // `Bounded` width.
1130 unsafe { Self::__new(T::from(value)) }1142 unsafe { Self::__new(T::from(value)) }
1131 }1143 }
1132}1144}
1133 1145
1134impl<T> Bounded<T, 1>1146impl<T> Bounded<T, 1>
1135where1147where
1136 T: Integer + Zeroable,1148 T: Integer<Signedness = Unsigned> + Zeroable,
1137{1149{
1138 /// Converts this [`Bounded`] into a [`bool`].1150 /// Converts this [`Bounded`] into a [`bool`].
1139 ///1151 ///
scripts/Makefile.build+2−1
@@ -347,7 +347,8 @@ quiet_cmd_rustc_o_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ · 346 unmodified lines
347 cmd_rustc_o_rs = $(rust_common_cmd) --emit=$(if $(CONFIG_RUST_INLINE_HELPERS),llvm-bc=$(patsubst %.o,%.bc,$@),obj=$@) $< \347 cmd_rustc_o_rs = $(rust_common_cmd) --emit=$(if $(CONFIG_RUST_INLINE_HELPERS),llvm-bc=$(patsubst %.o,%.bc,$@),obj=$@) $< \
348 $(if $(CONFIG_RUST_INLINE_HELPERS),;$(LLVM_LINK) --internalize --suppress-warnings $(patsubst %.o,%.bc,$@) \348 $(if $(CONFIG_RUST_INLINE_HELPERS),;$(LLVM_LINK) --internalize --suppress-warnings $(patsubst %.o,%.bc,$@) \
349 $(objtree)/rust/helpers/helpers$(if $(part-of-module),_module).bc -o $(patsubst %.o,%.m.bc,$@); \349 $(objtree)/rust/helpers/helpers$(if $(part-of-module),_module).bc -o $(patsubst %.o,%.m.bc,$@); \
350 $(CC) $(CLANG_FLAGS) $(KBUILD_CFLAGS) -Wno-override-module -c $(patsubst %.o,%.m.bc,$@) -o $@ \350 $(CC) $(CLANG_FLAGS) $(filter-out $(CC_FLAGS_LTO),$(KBUILD_CFLAGS)) \
351 $(CC_FLAGS_RUST_INLINE_HELPERS) -Wno-override-module -c $(patsubst %.o,%.m.bc,$@) -o $@ \
351 $(cmd_ld_single)) \352 $(cmd_ld_single)) \
352 $(cmd_objtool)353 $(cmd_objtool)
353 354
tools/objtool/check.c+1−0
@@ -196,6 +196,7 @@ static bool is_rust_noreturn(const struct symbol *func) · 195 unmodified lines
196 return str_ends_with(func->name, "_4core3num20from_str_radix_panic") ||196 return str_ends_with(func->name, "_4core3num20from_str_radix_panic") ||
197 str_ends_with(func->name, "_4core3num22from_ascii_radix_panic") ||197 str_ends_with(func->name, "_4core3num22from_ascii_radix_panic") ||
198 str_ends_with(func->name, "_4core3num28from_ascii_bytes_radix_panic") ||198 str_ends_with(func->name, "_4core3num28from_ascii_bytes_radix_panic") ||
199 str_ends_with(func->name, "_4core3str16slice_error_fail") ||
199 str_ends_with(func->name, "_4core5sliceSp15copy_from_slice17len_mismatch_fail") ||200 str_ends_with(func->name, "_4core5sliceSp15copy_from_slice17len_mismatch_fail") ||
200 str_ends_with(func->name, "_4core6option13expect_failed") ||201 str_ends_with(func->name, "_4core6option13expect_failed") ||
201 str_ends_with(func->name, "_4core6option13unwrap_failed") ||202 str_ends_with(func->name, "_4core6option13unwrap_failed") ||