[PATCH v4 0/5] aarch64: support shadow stack in clone3

Yury Khrustalev yury.khrustalev@arm.com
Fri Nov 7 09:35:04 GMT 2025


Kernel extends clone3() interface to allow specifying a shadow stack
when creating a new thread or process [1].

In this patch series we make use of this extended interface on aarch64
when GCS is available. We also suggest a new API to set and query the
size of the shadow stack used for new threads.

Part of the difficulty is versioning of the clone3() syscall in terms of
the struct clone_args as discussed in [2] and that a system can support
HWCAP_GCS without supporting extended struct clone_args. We check this
by doing a dummy clone3 syscall with a specific size of the struct and
looking for the E2BIG errno.

Regarding the new thread_attr_{get,set}shadowstacksize functions, they
are added for all targets supporting thread_attr_{get,set}stacksize()
however the targets that don't currently use shadow stack allocated
by Glibc the default shadows stack size is going to be zero. It is OK
to set a new value for the shadow stack size, but it would have no effect
on such targets since no shadow stack is allocated.

Regression was tested on aarch64 and x86, and no regression has been found.

New pthread_attr_...() functions checked with the build-many-glibcs.py
script for all affected targets.

Corresponding Linux kernel patch is [1] and can be checked out from [3]
(based on v6.18-rc1) which is the same as [4] applied on top of [1].

The plan is to use [4] in the subsequent Glibc patch to support re-using
shadow stack mappings in order to avoid unnecessarily un-mapping shadow
stacks for each new thread.

This change can be tested on the FVP model as described in [5].

Base commit: 58a31b4316

Changes in v4:
 - Added add pthread_attr_{get,set}shadowstacksize to show how we can
   configure size of Glibc-allocated shadow stacks.
 - Added corresponding tests.
 - v3: https://inbox.sourceware.org/libc-alpha/20250916122757.2341920-1-yury.khrustalev@arm.com/

Changes in v3:
 - Added enum to be used for the state determined by the utility function
   __clone3_supports_shadow_stack().
 - Fixed tests: using support function to check if memory was unmapped
   and use seccomp filter instead of unreliable enforced memory limit.
   Also using x-function from support to make code in the tests simpler.
 - Keeping all three (base, token, size) params of the shadow stack in the
   struct pthread for better portability across targets that support shadow
   stack.
 - Tested along with the latest version v21 of the corresponding kernel patch.
 - v2: https://inbox.sourceware.org/libc-alpha/20250707124722.2251501-1-yury.khrustalev@arm.com/

Changes in v2:
 - Instead of relying on kernel version, we fire a dummy clone3 syscall
   with a specific size and check if we get the E2BIG error which would
   indicate that the shadow_stack_token field is not supported in struct
   clone_args.
 - Added tests for cancelled and non-started threads to check that
   shadow stack is de-allocated.
 - v1: https://inbox.sourceware.org/libc-alpha/20250610151320.885131-1-yury.khrustalev@arm.com/

[1]: https://lore.kernel.org/all/20251015-clone3-shadow-stack-v22-0-a8c8da011427@kernel.org/
[2]: https://lore.kernel.org/lkml/aCs65ccRQtJBnZ_5@arm.com/
[3]: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/misc.git/log/?h=arm64-gcs-exit-token
[4]: https://lore.kernel.org/all/20250921-arm64-gcs-exit-token-v1-0-45cf64e648d5@kernel.org/
[5]: https://inbox.sourceware.org/libc-help/aIc3ElNTSQrelCK9@arm.com/

---

Yury Khrustalev (5):
  clone: Add clone_arg field for shadow stack
  nptl: Add libc allocated shadow stack for new threads
  aarch64: GCS: add clone3 tests for shadow stack
  aarch64: change __alloc_gcs to use shadow stack size
  nptl: add pthread_attr_{get,set}shadowstacksize

 nptl/Makefile                                 |   3 +
 nptl/Versions                                 |   2 +
 nptl/descr.h                                  |   7 ++
 nptl/pthread_attr_getshadowstacksize.c        |  44 +++++++
 nptl/pthread_attr_setshadowstacksize.c        |  43 +++++++
 nptl/pthread_create.c                         |  34 ++++++
 nptl/tst-pthread-attr-shadow-stack.c          |  54 +++++++++
 sysdeps/aarch64/__alloc_gcs.c                 |  24 ++--
 sysdeps/aarch64/aarch64-gcs.h                 |  11 +-
 sysdeps/aarch64/libc-shadow-stack.h           | 103 ++++++++++++++++
 sysdeps/generic/libc-shadow-stack.h           |  28 +++++
 sysdeps/nptl/internaltypes.h                  |   3 +
 sysdeps/nptl/pthread.h                        |  11 ++
 sysdeps/nptl/pthreadP.h                       |  16 +++
 sysdeps/unix/sysv/linux/aarch64/Makefile      |  21 ++++
 sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   2 +
 sysdeps/unix/sysv/linux/aarch64/makecontext.c |   4 +-
 .../linux/aarch64/tst-gcs-clone3-cancel.c     |  84 +++++++++++++
 .../sysv/linux/aarch64/tst-gcs-clone3-nomem.c | 111 ++++++++++++++++++
 .../unix/sysv/linux/aarch64/tst-gcs-clone3.c  |  89 ++++++++++++++
 .../sysv/linux/aarch64/tst-gcs-pthread-attr.c |  85 ++++++++++++++
 sysdeps/unix/sysv/linux/alpha/libc.abilist    |   2 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   2 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   2 +
 sysdeps/unix/sysv/linux/clone-internal.c      |   7 +-
 sysdeps/unix/sysv/linux/clone3.h              |   2 +
 sysdeps/unix/sysv/linux/csky/libc.abilist     |   2 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist     |   2 +
 sysdeps/unix/sysv/linux/i386/libc.abilist     |   2 +
 .../sysv/linux/loongarch/lp64/libc.abilist    |   2 +
 .../sysv/linux/m68k/coldfire/libc.abilist     |   2 +
 .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   2 +
 .../sysv/linux/microblaze/be/libc.abilist     |   2 +
 .../sysv/linux/microblaze/le/libc.abilist     |   2 +
 .../sysv/linux/mips/mips32/fpu/libc.abilist   |   2 +
 .../sysv/linux/mips/mips32/nofpu/libc.abilist |   2 +
 .../sysv/linux/mips/mips64/n32/libc.abilist   |   2 +
 .../sysv/linux/mips/mips64/n64/libc.abilist   |   2 +
 sysdeps/unix/sysv/linux/or1k/libc.abilist     |   2 +
 .../linux/powerpc/powerpc32/fpu/libc.abilist  |   2 +
 .../powerpc/powerpc32/nofpu/libc.abilist      |   2 +
 .../linux/powerpc/powerpc64/be/libc.abilist   |   2 +
 .../linux/powerpc/powerpc64/le/libc.abilist   |   2 +
 .../unix/sysv/linux/riscv/rv32/libc.abilist   |   2 +
 .../unix/sysv/linux/riscv/rv64/libc.abilist   |   2 +
 .../unix/sysv/linux/s390/s390-32/libc.abilist |   2 +
 .../unix/sysv/linux/s390/s390-64/libc.abilist |   2 +
 sysdeps/unix/sysv/linux/sh/be/libc.abilist    |   2 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   2 +
 .../sysv/linux/sparc/sparc32/libc.abilist     |   2 +
 .../sysv/linux/sparc/sparc64/libc.abilist     |   2 +
 sysdeps/unix/sysv/linux/spawni.c              |   1 +
 .../unix/sysv/linux/x86_64/64/libc.abilist    |   2 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |   2 +
 54 files changed, 831 insertions(+), 18 deletions(-)
 create mode 100644 nptl/pthread_attr_getshadowstacksize.c
 create mode 100644 nptl/pthread_attr_setshadowstacksize.c
 create mode 100644 nptl/tst-pthread-attr-shadow-stack.c
 create mode 100644 sysdeps/aarch64/libc-shadow-stack.h
 create mode 100644 sysdeps/generic/libc-shadow-stack.h
 create mode 100644 sysdeps/unix/sysv/linux/aarch64/tst-gcs-clone3-cancel.c
 create mode 100644 sysdeps/unix/sysv/linux/aarch64/tst-gcs-clone3-nomem.c
 create mode 100644 sysdeps/unix/sysv/linux/aarch64/tst-gcs-clone3.c
 create mode 100644 sysdeps/unix/sysv/linux/aarch64/tst-gcs-pthread-attr.c

-- 
2.47.3



More information about the Libc-alpha mailing list