[PATCH v6] rust: support for shadow call stack sanitizer

Ard Biesheuvel ardb at kernel.org
Wed Aug 28 10:38:20 PDT 2024


On Wed, 28 Aug 2024 at 16:42, Alice Ryhl <aliceryhl at google.com> wrote:
>
> On Wed, Aug 28, 2024 at 3:48 PM Ard Biesheuvel <ardb at kernel.org> wrote:
> >
> > On Mon, 26 Aug 2024 at 16:23, Alice Ryhl <aliceryhl at google.com> wrote:
> > >
> > > This patch adds all of the flags that are needed to support the shadow
> > > call stack (SCS) sanitizer with Rust, and updates Kconfig to allow only
> > > configurations that work.
> > >
> > > The -Zfixed-x18 flag is required to use SCS on arm64, and requires rustc
> > > version 1.80.0 or greater. This restriction is reflected in Kconfig.
> > >
> > > When CONFIG_DYNAMIC_SCS is enabled, the build will be configured to
> > > include unwind tables in the build artifacts. Dynamic SCS uses the
> > > unwind tables at boot to find all places that need to be patched. The
> > > -Cforce-unwind-tables=y flag ensures that unwind tables are available
> > > for Rust code.
> > >
> > > In non-dynamic mode, the -Zsanitizer=shadow-call-stack flag is what
> > > enables the SCS sanitizer. Using this flag requires rustc version 1.82.0
> > > or greater on the targets used by Rust in the kernel. This restriction
> > > is reflected in Kconfig.
> > >
> > > It is possible to avoid the requirement of rustc 1.80.0 by using
> > > -Ctarget-feature=+reserve-x18 instead of -Zfixed-x18. However, this flag
> > > emits a warning during the build, so this patch does not add support for
> > > using it and instead requires 1.80.0 or greater.
> > >
> > > The dependency is placed on `select HAVE_RUST` to avoid a situation
> > > where enabling Rust silently turns off the sanitizer. Instead, turning
> > > on the sanitizer results in Rust being disabled. We generally do not
> > > want changes to CONFIG_RUST to result in any mitigations being changed
> > > or turned off.
> > >
> > > At the time of writing, rustc 1.82.0 only exists via the nightly release
> > > channel. There is a chance that the -Zsanitizer=shadow-call-stack flag
> > > will end up needing 1.83.0 instead, but I think it is small.
> > >
> > > Signed-off-by: Alice Ryhl <aliceryhl at google.com>
> > > ---
> > > Link: https://lore.kernel.org/rust-for-linux/20240808221138.873750-1-ojeda@kernel.org/ [1]
> > > ---
> > > Changes in v6:
> > > - Move Kconfig requirements into arch/*/Kconfig.
> > > - List non-dynamic SCS as supported on 1.82. This reflects newly added
> > >   things in rustc.
> > > - Link to v5: https://lore.kernel.org/r/20240806-shadow-call-stack-v5-1-26dccb829154@google.com
> > >
> > > Changes in v5:
> > > - Rebase series on v6.11-rc2.
> > > - The first patch is no longer included as it was merged in v6.11-rc2.
> > > - The commit message is rewritten from scratch.
> > > - Link to v4: https://lore.kernel.org/r/20240729-shadow-call-stack-v4-0-2a664b082ea4@google.com
> > >
> > > Changes in v4:
> > > - Move `depends on` to CONFIG_RUST.
> > > - Rewrite commit messages to include more context.
> > > - Link to v3: https://lore.kernel.org/r/20240704-shadow-call-stack-v3-0-d11c7a6ebe30@google.com
> > >
> > > Changes in v3:
> > > - Use -Zfixed-x18.
> > > - Add logic to reject unsupported rustc versions.
> > > - Also include a fix to be backported.
> > > - Link to v2: https://lore.kernel.org/rust-for-linux/20240305-shadow-call-stack-v2-1-c7b4a3f4d616@google.com/
> > >
> > > Changes in v2:
> > > - Add -Cforce-unwind-tables flag.
> > > - Link to v1: https://lore.kernel.org/rust-for-linux/20240304-shadow-call-stack-v1-1-f055eaf40a2c@google.com/
> > > ---
> > >  Makefile            | 1 +
> > >  arch/arm64/Kconfig  | 7 ++++++-
> > >  arch/arm64/Makefile | 3 +++
> > >  arch/riscv/Kconfig  | 7 ++++++-
> > >  init/Kconfig        | 1 -
> > >  5 files changed, 16 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/Makefile b/Makefile
> > > index 44c02a6f60a1..eb01a26d8354 100644
> > > --- a/Makefile
> > > +++ b/Makefile
> > > @@ -927,6 +927,7 @@ ifdef CONFIG_SHADOW_CALL_STACK
> > >  ifndef CONFIG_DYNAMIC_SCS
> > >  CC_FLAGS_SCS   := -fsanitize=shadow-call-stack
> > >  KBUILD_CFLAGS  += $(CC_FLAGS_SCS)
> > > +KBUILD_RUSTFLAGS += -Zsanitizer=shadow-call-stack
> > >  endif
> > >  export CC_FLAGS_SCS
> > >  endif
> > > diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> > > index a2f8ff354ca6..28c4a3035331 100644
> > > --- a/arch/arm64/Kconfig
> > > +++ b/arch/arm64/Kconfig
> > > @@ -231,7 +231,7 @@ config ARM64
> > >         select HAVE_FUNCTION_ARG_ACCESS_API
> > >         select MMU_GATHER_RCU_TABLE_FREE
> > >         select HAVE_RSEQ
> > > -       select HAVE_RUST if CPU_LITTLE_ENDIAN
> > > +       select HAVE_RUST if RUSTC_SUPPORTS_ARM64
> > >         select HAVE_STACKPROTECTOR
> > >         select HAVE_SYSCALL_TRACEPOINTS
> > >         select HAVE_KPROBES
> > > @@ -265,6 +265,11 @@ config ARM64
> > >         help
> > >           ARM 64-bit (AArch64) Linux support.
> > >
> > > +config RUSTC_SUPPORTS_ARM64
> >
> > Nit: could we choose a better name here? ARCH_HAVE_RUST perhaps?
>
> This is the name suggested by Will Deacon in the previous version. I'm
> happy to change it if you prefer, but I'm wondering if that name is
> too close to HAVE_RUST? Perhaps ARCH_SUPPORTS_RUST? Ultimately I think
> that the current name is okay.
>

Fair enough. Let's leave it as-is.

> > > +       def_bool y
> > > +       depends on CPU_LITTLE_ENDIAN
> > > +       depends on !SHADOW_CALL_STACK || RUSTC_VERSION >= 108200 || RUSTC_VERSION >= 108000 && UNWIND_PATCH_PAC_INTO_SCS
> > > +
> >
> > This is a bit opaque, so I'd prefer to have a comment here, explaining
> > that rustc 1.82 supports emitting the instrumentation statically, but
> > 1.80 is needed to get the X18 reservation, which the DWARF based
> > patching logic relies on.
>
> Hmm. I tried a few different wordings and ended on this:
>
> config RUSTC_SUPPORTS_ARM64
>        def_bool y
>        depends on CPU_LITTLE_ENDIAN
>        # Shadow call stack is only supported on some versions of rustc.
>        #
>        # When using the UNWIND_PATCH_PAC_INTO_SCS option, rustc version 1.80+ is
>        # required due to use of the -Zfixed-x18 flag.
>        #
>        # Otherwise, rustc version 1.82+ is required due to use of the
>        # -Zsanitizer=shadow-call-stack flag.
>        depends on !SHADOW_CALL_STACK || RUSTC_VERSION >= 108200 ||
> RUSTC_VERSION >= 108000 && UNWIND_PATCH_PAC_INTO_SCS
>
> This wording avoids getting into the weeds of how SCS works. Do you
> prefer something that gets into more detail than this?
>

This looks fine to me.

> > >  config CLANG_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS
> > >         def_bool CC_IS_CLANG
> > >         # https://github.com/ClangBuiltLinux/linux/issues/1507
> > > diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
> > > index f6bc3da1ef11..b058c4803efb 100644
> > > --- a/arch/arm64/Makefile
> > > +++ b/arch/arm64/Makefile
> > > @@ -57,9 +57,11 @@ KBUILD_AFLAGS        += $(call cc-option,-mabi=lp64)
> > >  ifneq ($(CONFIG_UNWIND_TABLES),y)
> > >  KBUILD_CFLAGS  += -fno-asynchronous-unwind-tables -fno-unwind-tables
> > >  KBUILD_AFLAGS  += -fno-asynchronous-unwind-tables -fno-unwind-tables
> > > +KBUILD_RUSTFLAGS += -Cforce-unwind-tables=n
> > >  else
> > >  KBUILD_CFLAGS  += -fasynchronous-unwind-tables
> > >  KBUILD_AFLAGS  += -fasynchronous-unwind-tables
> > > +KBUILD_RUSTFLAGS += -Cforce-unwind-tables=y -Zuse-sync-unwind=n
> > >  endif
> > >
> > >  ifeq ($(CONFIG_STACKPROTECTOR_PER_TASK),y)
> > > @@ -114,6 +116,7 @@ endif
> > >
> > >  ifeq ($(CONFIG_SHADOW_CALL_STACK), y)
> > >  KBUILD_CFLAGS  += -ffixed-x18
> > > +KBUILD_RUSTFLAGS += -Zfixed-x18
> > >  endif
> > >
> > >  ifeq ($(CONFIG_CPU_BIG_ENDIAN), y)
> > > diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> > > index 0f3cd7c3a436..476e38ed9c00 100644
> > > --- a/arch/riscv/Kconfig
> > > +++ b/arch/riscv/Kconfig
> > > @@ -172,7 +172,7 @@ config RISCV
> > >         select HAVE_REGS_AND_STACK_ACCESS_API
> > >         select HAVE_RETHOOK if !XIP_KERNEL
> > >         select HAVE_RSEQ
> > > -       select HAVE_RUST if 64BIT
> > > +       select HAVE_RUST if RUSTC_SUPPORTS_RISCV
> > >         select HAVE_SAMPLE_FTRACE_DIRECT
> > >         select HAVE_SAMPLE_FTRACE_DIRECT_MULTI
> > >         select HAVE_STACKPROTECTOR
> > > @@ -202,6 +202,11 @@ config RISCV
> > >         select UACCESS_MEMCPY if !MMU
> > >         select ZONE_DMA32 if 64BIT
> > >
> > > +config RUSTC_SUPPORTS_RISCV
> > > +       def_bool y
> > > +       depends on 64BIT
> > > +       depends on !SHADOW_CALL_STACK || RUSTC_VERSION >= 108200
> > > +
> >
> > Same nit as above. Also, if this enables shadow call stack on RISC-V
> > too, please mention it in the commit log more clearly, as it only
> > mentions arm64 by name.
>
> Same question as above. I came up with:
>
> config RUSTC_SUPPORTS_RISCV
>        def_bool y
>        depends on 64BIT
>        # Shadow call stack requires rustc version 1.82+ due to use of the
>        # -Zsanitizer=shadow-call-stack flag.
>        depends on !SHADOW_CALL_STACK || RUSTC_VERSION >= 108200
>

Fine too.

> > >  config CLANG_SUPPORTS_DYNAMIC_FTRACE
> > >         def_bool CC_IS_CLANG
> > >         # https://github.com/ClangBuiltLinux/linux/issues/1817
> > > diff --git a/init/Kconfig b/init/Kconfig
> > > index fe76c5d0a72e..e095e94eb9db 100644
> > > --- a/init/Kconfig
> > > +++ b/init/Kconfig
> > > @@ -1909,7 +1909,6 @@ config RUST
> > >         depends on !MODVERSIONS
> > >         depends on !GCC_PLUGINS
> > >         depends on !RANDSTRUCT
> > > -       depends on !SHADOW_CALL_STACK
> > >         depends on !DEBUG_INFO_BTF || PAHOLE_HAS_LANG_EXCLUDE
> > >         help
> > >           Enables Rust support in the kernel.
> > >
> > > ---
> > > base-commit: 5953fd808fca8116a91678ee5fac00fc198ad93d
> > > change-id: 20240304-shadow-call-stack-9c197a4361d9
> > >
> >
> > With the comments addressed (or refuted)
> >
> > Reviewed-by: Ard Biesheuvel <ardb at kernel.org>
>
> Thanks for the review!
>
> Alice
>



More information about the linux-arm-kernel mailing list