[PATCH v3 2/3] scs: add support for dynamic shadow call stacks

Ard Biesheuvel ardb at kernel.org
Mon Jun 13 23:20:13 PDT 2022


On Mon, 13 Jun 2022 at 15:40, Ard Biesheuvel <ardb at kernel.org> wrote:
>
> In order to allow arches to use code patching to conditionally emit the
> shadow stack pushes and pops, rather than always taking the performance
> hit even on CPUs that implement alternatives such as stack pointer
> authentication on arm64, add a Kconfig symbol that can be set by the
> arch to omit the SCS codegen itself, without otherwise affecting how
> support code for SCS and compiler options (for register reservation, for
> instance) are emitted.
>
> Also, add a static key and some plumbing to omit the allocation of
> shadow call stack for dynamic SCS configurations if SCS is disabled at
> runtime.
>
> Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
> Reviewed-by: Nick Desaulniers <ndesaulniers at google.com>
> Reviewed-by: Kees Cook <keescook at chromium.org>

This patch needs the following hunk applied on top to fix a build
error reported by the bots:

--- a/include/linux/scs.h
+++ b/include/linux/scs.h
@@ -57,6 +57,8 @@ DECLARE_STATIC_KEY_TRUE(dynamic_scs_enabled);

 static inline bool scs_is_dynamic(void)
 {
+       if (!IS_ENABLED(CONFIG_DYNAMIC_SCS))
+               return false;
        return static_branch_likely(&dynamic_scs_enabled);
 }


> ---
>  Makefile            |  2 ++
>  arch/Kconfig        |  7 +++++++
>  include/linux/scs.h | 16 ++++++++++++++++
>  kernel/scs.c        | 14 ++++++++++++--
>  4 files changed, 37 insertions(+), 2 deletions(-)
>
> diff --git a/Makefile b/Makefile
> index c43d825a3c4c..806b1dea1218 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -883,8 +883,10 @@ LDFLAGS_vmlinux += --gc-sections
>  endif
>
>  ifdef CONFIG_SHADOW_CALL_STACK
> +ifndef CONFIG_DYNAMIC_SCS
>  CC_FLAGS_SCS   := -fsanitize=shadow-call-stack
>  KBUILD_CFLAGS  += $(CC_FLAGS_SCS)
> +endif
>  export CC_FLAGS_SCS
>  endif
>
> diff --git a/arch/Kconfig b/arch/Kconfig
> index fcf9a41a4ef5..a6048d78f05d 100644
> --- a/arch/Kconfig
> +++ b/arch/Kconfig
> @@ -636,6 +636,13 @@ config SHADOW_CALL_STACK
>           reading and writing arbitrary memory may be able to locate them
>           and hijack control flow by modifying the stacks.
>
> +config DYNAMIC_SCS
> +       bool
> +       help
> +         Set by the arch code if it relies on code patching to insert the
> +         shadow call stack push and pop instructions rather than on the
> +         compiler.
> +
>  config LTO
>         bool
>         help
> diff --git a/include/linux/scs.h b/include/linux/scs.h
> index 18122d9e17ff..c62134d89c7b 100644
> --- a/include/linux/scs.h
> +++ b/include/linux/scs.h
> @@ -53,6 +53,20 @@ static inline bool task_scs_end_corrupted(struct task_struct *tsk)
>         return sz >= SCS_SIZE - 1 || READ_ONCE_NOCHECK(*magic) != SCS_END_MAGIC;
>  }
>
> +DECLARE_STATIC_KEY_TRUE(dynamic_scs_enabled);
> +
> +static inline bool scs_is_dynamic(void)
> +{
> +       return static_branch_likely(&dynamic_scs_enabled);
> +}
> +
> +static inline bool scs_is_enabled(void)
> +{
> +       if (!IS_ENABLED(CONFIG_DYNAMIC_SCS))
> +               return true;
> +       return scs_is_dynamic();
> +}
> +
>  #else /* CONFIG_SHADOW_CALL_STACK */
>
>  static inline void *scs_alloc(int node) { return NULL; }
> @@ -62,6 +76,8 @@ static inline void scs_task_reset(struct task_struct *tsk) {}
>  static inline int scs_prepare(struct task_struct *tsk, int node) { return 0; }
>  static inline void scs_release(struct task_struct *tsk) {}
>  static inline bool task_scs_end_corrupted(struct task_struct *tsk) { return false; }
> +static inline bool scs_is_enabled(void) { return false; }
> +static inline bool scs_is_dynamic(void) { return false; }
>
>  #endif /* CONFIG_SHADOW_CALL_STACK */
>
> diff --git a/kernel/scs.c b/kernel/scs.c
> index b7e1b096d906..8826794d2645 100644
> --- a/kernel/scs.c
> +++ b/kernel/scs.c
> @@ -12,6 +12,10 @@
>  #include <linux/vmalloc.h>
>  #include <linux/vmstat.h>
>
> +#ifdef CONFIG_DYNAMIC_SCS
> +DEFINE_STATIC_KEY_TRUE(dynamic_scs_enabled);
> +#endif
> +
>  static void __scs_account(void *s, int account)
>  {
>         struct page *scs_page = vmalloc_to_page(s);
> @@ -101,14 +105,20 @@ static int scs_cleanup(unsigned int cpu)
>
>  void __init scs_init(void)
>  {
> +       if (!scs_is_enabled())
> +               return;
>         cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "scs:scs_cache", NULL,
>                           scs_cleanup);
>  }
>
>  int scs_prepare(struct task_struct *tsk, int node)
>  {
> -       void *s = scs_alloc(node);
> +       void *s;
>
> +       if (!scs_is_enabled())
> +               return 0;
> +
> +       s = scs_alloc(node);
>         if (!s)
>                 return -ENOMEM;
>
> @@ -148,7 +158,7 @@ void scs_release(struct task_struct *tsk)
>  {
>         void *s = task_scs(tsk);
>
> -       if (!s)
> +       if (!scs_is_enabled() || !s)
>                 return;
>
>         WARN(task_scs_end_corrupted(tsk),
> --
> 2.30.2
>



More information about the linux-arm-kernel mailing list