Pull Rust updates from Miguel Ojeda:
 "Toolchain and infrastructure:

   - Support 'MITIGATION_{RETHUNK,RETPOLINE,SLS}' (which cleans up
     objtool warnings), teach objtool about 'noreturn' Rust symbols and
     mimic '___ADDRESSABLE()' for 'module_{init,exit}'. With that, we
     should be objtool-warning-free, so enable it to run for all Rust
     object files.

   - KASAN (no 'SW_TAGS'), KCFI and shadow call sanitizer support.

   - Support 'RUSTC_VERSION', including re-config and re-build on
     change.

   - Split helpers file into several files in a folder, to avoid
     conflicts in it. Eventually those files will be moved to the right
     places with the new build system. In addition, remove the need to
     manually export the symbols defined there, reusing existing
     machinery for that.

   - Relax restriction on configurations with Rust + GCC plugins to just
     the RANDSTRUCT plugin.

  'kernel' crate:

   - New 'list' module: doubly-linked linked list for use with reference
     counted values, which is heavily used by the upcoming Rust Binder.

     This includes 'ListArc' (a wrapper around 'Arc' that is guaranteed
     unique for the given ID), 'AtomicTracker' (tracks whether a
     'ListArc' exists using an atomic), 'ListLinks' (the prev/next
     pointers for an item in a linked list), 'List' (the linked list
     itself), 'Iter' (an iterator over a 'List'), 'Cursor' (a cursor
     into a 'List' that allows to remove elements), 'ListArcField' (a
     field exclusively owned by a 'ListArc'), as well as support for
     heterogeneous lists.

   - New 'rbtree' module: red-black tree abstractions used by the
     upcoming Rust Binder.

     This includes 'RBTree' (the red-black tree itself), 'RBTreeNode' (a
     node), 'RBTreeNodeReservation' (a memory reservation for a node),
     'Iter' and 'IterMut' (immutable and mutable iterators), 'Cursor'
     (bidirectional cursor that allows to remove elements), as well as
     an entry API similar to the Rust standard library one.

   - 'init' module: add 'write_[pin_]init' methods and the
     'InPlaceWrite' trait. Add the 'assert_pinned!' macro.

   - 'sync' module: implement the 'InPlaceInit' trait for 'Arc' by
     introducing an associated type in the trait.

   - 'alloc' module: add 'drop_contents' method to 'BoxExt'.

   - 'types' module: implement the 'ForeignOwnable' trait for
     'Pin<Box<T>>' and improve the trait's documentation. In addition,
     add the 'into_raw' method to the 'ARef' type.

   - 'error' module: in preparation for the upcoming Rust support for
     32-bit architectures, like arm, locally allow Clippy lint for
     those.

  Documentation:

   - https://rust.docs.kernel.org has been announced, so link to it.

   - Enable rustdoc's "jump to definition" feature, making its output a
     bit closer to the experience in a cross-referencer.

   - Debian Testing now also provides recent Rust releases (outside of
     the freeze period), so add it to the list.

  MAINTAINERS:

   - Trevor is joining as reviewer of the "RUST" entry.

  And a few other small bits"

* tag 'rust-6.12' of https://github.com/Rust-for-Linux/linux: (54 commits)
  kasan: rust: Add KASAN smoke test via UAF
  kbuild: rust: Enable KASAN support
  rust: kasan: Rust does not support KHWASAN
  kbuild: rust: Define probing macros for rustc
  kasan: simplify and clarify Makefile
  rust: cfi: add support for CFI_CLANG with Rust
  cfi: add CONFIG_CFI_ICALL_NORMALIZE_INTEGERS
  rust: support for shadow call stack sanitizer
  docs: rust: include other expressions in conditional compilation section
  kbuild: rust: replace proc macros dependency on `core.o` with the version text
  kbuild: rust: rebuild if the version text changes
  kbuild: rust: re-run Kconfig if the version text changes
  kbuild: rust: add `CONFIG_RUSTC_VERSION`
  rust: avoid `box_uninit_write` feature
  MAINTAINERS: add Trevor Gross as Rust reviewer
  rust: rbtree: add `RBTree::entry`
  rust: rbtree: add cursor
  rust: rbtree: add mutable iterator
  rust: rbtree: add iterator
  rust: rbtree: add red-black tree implementation backed by the C version
  ...
This commit is contained in:
Linus Torvalds
2024-09-25 10:25:40 -07:00
63 changed files with 3881 additions and 405 deletions
+8
View File
@@ -64,3 +64,11 @@ ld-version := $(shell,set -- $(ld-info) && echo $2)
cc-option-bit = $(if-success,$(CC) -Werror $(1) -E -x c /dev/null -o /dev/null,$(1))
m32-flag := $(cc-option-bit,-m32)
m64-flag := $(cc-option-bit,-m64)
# $(rustc-option,<flag>)
# Return y if the Rust compiler supports <flag>, n otherwise
# Calls to this should be guarded so that they are not evaluated if
# CONFIG_RUST_IS_AVAILABLE is not set.
# If you are testing for unstable features, consider testing RUSTC_VERSION
# instead, as features may have different completeness while available.
rustc-option = $(success,trap "rm -rf .tmp_$$" EXIT; mkdir .tmp_$$; $(RUSTC) $(1) --crate-type=rlib /dev/null --out-dir=.tmp_$$ -o .tmp_$$/tmp.rlib)
+7 -2
View File
@@ -273,10 +273,15 @@ rust_common_cmd = \
# would not match each other.
quiet_cmd_rustc_o_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
cmd_rustc_o_rs = $(rust_common_cmd) --emit=obj=$@ $<
cmd_rustc_o_rs = $(rust_common_cmd) --emit=obj=$@ $< $(cmd_objtool)
define rule_rustc_o_rs
$(call cmd_and_fixdep,rustc_o_rs)
$(call cmd,gen_objtooldep)
endef
$(obj)/%.o: $(obj)/%.rs FORCE
+$(call if_changed_dep,rustc_o_rs)
+$(call if_changed_rule,rustc_o_rs)
quiet_cmd_rustc_rsi_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
cmd_rustc_rsi_rs = \
+15
View File
@@ -72,3 +72,18 @@ clang-min-version = $(call test-ge, $(CONFIG_CLANG_VERSION), $1)
# ld-option
# Usage: KBUILD_LDFLAGS += $(call ld-option, -X, -Y)
ld-option = $(call try-run, $(LD) $(KBUILD_LDFLAGS) $(1) -v,$(1),$(2),$(3))
# __rustc-option
# Usage: MY_RUSTFLAGS += $(call __rustc-option,$(RUSTC),$(MY_RUSTFLAGS),-Cinstrument-coverage,-Zinstrument-coverage)
__rustc-option = $(call try-run,\
$(1) $(2) $(3) --crate-type=rlib /dev/null --out-dir=$$TMPOUT -o "$$TMP",$(3),$(4))
# rustc-option
# Usage: rustflags-y += $(call rustc-option,-Cinstrument-coverage,-Zinstrument-coverage)
rustc-option = $(call __rustc-option, $(RUSTC),\
$(KBUILD_RUSTFLAGS),$(1),$(2))
# rustc-option-yn
# Usage: flag := $(call rustc-option-yn,-Cinstrument-coverage)
rustc-option-yn = $(call try-run,\
$(RUSTC) $(KBUILD_RUSTFLAGS) $(1) --crate-type=rlib /dev/null --out-dir=$$TMPOUT -o "$$TMP",y,n)
+41 -16
View File
@@ -12,6 +12,11 @@ endif
KASAN_SHADOW_OFFSET ?= $(CONFIG_KASAN_SHADOW_OFFSET)
cc-param = $(call cc-option, -mllvm -$(1), $(call cc-option, --param $(1)))
rustc-param = $(call rustc-option, -Cllvm-args=-$(1),)
check-args = $(foreach arg,$(2),$(call $(1),$(arg)))
kasan_params :=
ifdef CONFIG_KASAN_STACK
stack_enable := 1
@@ -41,39 +46,59 @@ CFLAGS_KASAN := $(call cc-option, -fsanitize=kernel-address \
$(call cc-option, -fsanitize=kernel-address \
-mllvm -asan-mapping-offset=$(KASAN_SHADOW_OFFSET)))
# Now, add other parameters enabled similarly in both GCC and Clang.
# As some of them are not supported by older compilers, use cc-param.
CFLAGS_KASAN += $(call cc-param,asan-instrumentation-with-call-threshold=$(call_threshold)) \
$(call cc-param,asan-stack=$(stack_enable)) \
$(call cc-param,asan-instrument-allocas=1) \
$(call cc-param,asan-globals=1)
# The minimum supported `rustc` version has a minimum supported LLVM
# version late enough that we can assume support for -asan-mapping-offset.
RUSTFLAGS_KASAN := -Zsanitizer=kernel-address \
-Zsanitizer-recover=kernel-address \
-Cllvm-args=-asan-mapping-offset=$(KASAN_SHADOW_OFFSET)
# Now, add other parameters enabled similarly in GCC, Clang, and rustc.
# As some of them are not supported by older compilers, these will be filtered
# through `cc-param` or `rust-param` as applicable.
kasan_params += asan-instrumentation-with-call-threshold=$(call_threshold) \
asan-stack=$(stack_enable) \
asan-instrument-allocas=1 \
asan-globals=1
# Instrument memcpy/memset/memmove calls by using instrumented __asan_mem*()
# instead. With compilers that don't support this option, compiler-inserted
# memintrinsics won't be checked by KASAN on GENERIC_ENTRY architectures.
CFLAGS_KASAN += $(call cc-param,asan-kernel-mem-intrinsic-prefix=1)
kasan_params += asan-kernel-mem-intrinsic-prefix=1
endif # CONFIG_KASAN_GENERIC
ifdef CONFIG_KASAN_SW_TAGS
CFLAGS_KASAN := -fsanitize=kernel-hwaddress
# This sets flags that will enable SW_TAGS KASAN once enabled in Rust. These
# will not work today, and is guarded against in dependencies for CONFIG_RUST.
RUSTFLAGS_KASAN := -Zsanitizer=kernel-hwaddress \
-Zsanitizer-recover=kernel-hwaddress
ifdef CONFIG_KASAN_INLINE
instrumentation_flags := $(call cc-param,hwasan-mapping-offset=$(KASAN_SHADOW_OFFSET))
kasan_params += hwasan-mapping-offset=$(KASAN_SHADOW_OFFSET)
else
instrumentation_flags := $(call cc-param,hwasan-instrument-with-calls=1)
kasan_params += hwasan-instrument-with-calls=1
endif
CFLAGS_KASAN := -fsanitize=kernel-hwaddress \
$(call cc-param,hwasan-instrument-stack=$(stack_enable)) \
$(call cc-param,hwasan-use-short-granules=0) \
$(call cc-param,hwasan-inline-all-checks=0) \
$(instrumentation_flags)
kasan_params += hwasan-instrument-stack=$(stack_enable) \
hwasan-use-short-granules=0 \
hwasan-inline-all-checks=0
# Instrument memcpy/memset/memmove calls by using instrumented __hwasan_mem*().
ifeq ($(call clang-min-version, 150000)$(call gcc-min-version, 130000),y)
CFLAGS_KASAN += $(call cc-param,hwasan-kernel-mem-intrinsic-prefix=1)
kasan_params += hwasan-kernel-mem-intrinsic-prefix=1
endif
endif # CONFIG_KASAN_SW_TAGS
export CFLAGS_KASAN CFLAGS_KASAN_NOSANITIZE
# Add all as-supported KASAN LLVM parameters requested by the configuration.
CFLAGS_KASAN += $(call check-args, cc-param, $(kasan_params))
ifdef CONFIG_RUST
# Avoid calling `rustc-param` unless Rust is enabled.
RUSTFLAGS_KASAN += $(call check-args, rustc-param, $(kasan_params))
endif # CONFIG_RUST
export CFLAGS_KASAN CFLAGS_KASAN_NOSANITIZE RUSTFLAGS_KASAN
+3
View File
@@ -146,6 +146,9 @@ ifneq ($(CONFIG_KASAN_HW_TAGS),y)
_c_flags += $(if $(patsubst n%,, \
$(KASAN_SANITIZE_$(target-stem).o)$(KASAN_SANITIZE)$(is-kernel-object)), \
$(CFLAGS_KASAN), $(CFLAGS_KASAN_NOSANITIZE))
_rust_flags += $(if $(patsubst n%,, \
$(KASAN_SANITIZE_$(target-stem).o)$(KASAN_SANITIZE)$(is-kernel-object)), \
$(RUSTFLAGS_KASAN))
endif
endif
+79 -39
View File
@@ -20,12 +20,28 @@ enum Value {
Boolean(bool),
Number(i32),
String(String),
Array(Vec<Value>),
Object(Object),
}
type Object = Vec<(String, Value)>;
/// Minimal "almost JSON" generator (e.g. no `null`s, no arrays, no escaping),
fn comma_sep<T>(
seq: &[T],
formatter: &mut Formatter<'_>,
f: impl Fn(&mut Formatter<'_>, &T) -> Result,
) -> Result {
if let [ref rest @ .., ref last] = seq[..] {
for v in rest {
f(formatter, v)?;
formatter.write_str(",")?;
}
f(formatter, last)?;
}
Ok(())
}
/// Minimal "almost JSON" generator (e.g. no `null`s, no escaping),
/// enough for this purpose.
impl Display for Value {
fn fmt(&self, formatter: &mut Formatter<'_>) -> Result {
@@ -33,59 +49,67 @@ impl Display for Value {
Value::Boolean(boolean) => write!(formatter, "{}", boolean),
Value::Number(number) => write!(formatter, "{}", number),
Value::String(string) => write!(formatter, "\"{}\"", string),
Value::Array(values) => {
formatter.write_str("[")?;
comma_sep(&values[..], formatter, |formatter, v| v.fmt(formatter))?;
formatter.write_str("]")
}
Value::Object(object) => {
formatter.write_str("{")?;
if let [ref rest @ .., ref last] = object[..] {
for (key, value) in rest {
write!(formatter, "\"{}\": {},", key, value)?;
}
write!(formatter, "\"{}\": {}", last.0, last.1)?;
}
comma_sep(&object[..], formatter, |formatter, v| {
write!(formatter, "\"{}\": {}", v.0, v.1)
})?;
formatter.write_str("}")
}
}
}
}
impl From<bool> for Value {
fn from(value: bool) -> Self {
Self::Boolean(value)
}
}
impl From<i32> for Value {
fn from(value: i32) -> Self {
Self::Number(value)
}
}
impl From<String> for Value {
fn from(value: String) -> Self {
Self::String(value)
}
}
impl From<&str> for Value {
fn from(value: &str) -> Self {
Self::String(value.to_string())
}
}
impl From<Object> for Value {
fn from(object: Object) -> Self {
Self::Object(object)
}
}
impl<T: Into<Value>, const N: usize> From<[T; N]> for Value {
fn from(i: [T; N]) -> Self {
Self::Array(i.into_iter().map(|v| v.into()).collect())
}
}
struct TargetSpec(Object);
impl TargetSpec {
fn new() -> TargetSpec {
TargetSpec(Vec::new())
}
}
trait Push<T> {
fn push(&mut self, key: &str, value: T);
}
impl Push<bool> for TargetSpec {
fn push(&mut self, key: &str, value: bool) {
self.0.push((key.to_string(), Value::Boolean(value)));
}
}
impl Push<i32> for TargetSpec {
fn push(&mut self, key: &str, value: i32) {
self.0.push((key.to_string(), Value::Number(value)));
}
}
impl Push<String> for TargetSpec {
fn push(&mut self, key: &str, value: String) {
self.0.push((key.to_string(), Value::String(value)));
}
}
impl Push<&str> for TargetSpec {
fn push(&mut self, key: &str, value: &str) {
self.push(key, value.to_string());
}
}
impl Push<Object> for TargetSpec {
fn push(&mut self, key: &str, value: Object) {
self.0.push((key.to_string(), Value::Object(value)));
fn push(&mut self, key: &str, value: impl Into<Value>) {
self.0.push((key.to_string(), value.into()));
}
}
@@ -164,10 +188,26 @@ fn main() {
);
let mut features = "-mmx,+soft-float".to_string();
if cfg.has("MITIGATION_RETPOLINE") {
// The kernel uses `-mretpoline-external-thunk` (for Clang), which Clang maps to the
// target feature of the same name plus the other two target features in
// `clang/lib/Driver/ToolChains/Arch/X86.cpp`. These should be eventually enabled via
// `-Ctarget-feature` when `rustc` starts recognizing them (or via a new dedicated
// flag); see https://github.com/rust-lang/rust/issues/116852.
features += ",+retpoline-external-thunk";
features += ",+retpoline-indirect-branches";
features += ",+retpoline-indirect-calls";
}
if cfg.has("MITIGATION_SLS") {
// The kernel uses `-mharden-sls=all`, which Clang maps to both these target features in
// `clang/lib/Driver/ToolChains/Arch/X86.cpp`. These should be eventually enabled via
// `-Ctarget-feature` when `rustc` starts recognizing them (or via a new dedicated
// flag); see https://github.com/rust-lang/rust/issues/116851.
features += ",+harden-sls-ijmp";
features += ",+harden-sls-ret";
}
ts.push("features", features);
ts.push("llvm-target", "x86_64-linux-gnu");
ts.push("supported-sanitizers", ["kcfi", "kernel-address"]);
ts.push("target-pointer-width", "64");
} else if cfg.has("X86_32") {
// This only works on UML, as i386 otherwise needs regparm support in rustc
+26
View File
@@ -0,0 +1,26 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
#
# Usage: $ ./rustc-version.sh rustc
#
# Print the Rust compiler version in a 6 or 7-digit form.
# Convert the version string x.y.z to a canonical up-to-7-digits form.
#
# Note that this function uses one more digit (compared to other
# instances in other version scripts) to give a bit more space to
# `rustc` since it will reach 1.100.0 in late 2026.
get_canonical_version()
{
IFS=.
set -- $1
echo $((100000 * $1 + 100 * $2 + $3))
}
if output=$("$@" --version 2>/dev/null); then
set -- $output
get_canonical_version $2
else
echo 0
exit 1
fi