[PATCH v4 4/5] aarch64: change __alloc_gcs to use shadow stack size

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


---
 sysdeps/aarch64/__alloc_gcs.c                 | 24 ++++++++-----------
 sysdeps/aarch64/aarch64-gcs.h                 | 11 ++++++++-
 sysdeps/aarch64/libc-shadow-stack.h           |  3 ++-
 sysdeps/unix/sysv/linux/aarch64/makecontext.c |  3 ++-
 4 files changed, 24 insertions(+), 17 deletions(-)

diff --git a/sysdeps/aarch64/__alloc_gcs.c b/sysdeps/aarch64/__alloc_gcs.c
index b98e5fcdba..17491c24c9 100644
--- a/sysdeps/aarch64/__alloc_gcs.c
+++ b/sysdeps/aarch64/__alloc_gcs.c
@@ -32,37 +32,33 @@ map_shadow_stack (void *addr, size_t size, unsigned long flags)
   return (void *) INLINE_SYSCALL_CALL (map_shadow_stack, addr, size, flags);
 }
 
-#define GCS_MAX_SIZE (1UL << 31)
-#define GCS_ALTSTACK_RESERVE 160
-
 void *
-__alloc_gcs (size_t stack_size, struct gcs_record *gcs)
+__alloc_gcs (size_t sh_stack_size, struct gcs_record *rec)
 {
-  size_t size = (stack_size / 2 + GCS_ALTSTACK_RESERVE) & -8UL;
-  if (size > GCS_MAX_SIZE)
-    size = GCS_MAX_SIZE;
+  if (sh_stack_size > GCS_MAX_SHADOW_STACK_SIZE)
+    sh_stack_size = GCS_MAX_SHADOW_STACK_SIZE;
 
   unsigned long flags = SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN;
-  void *base = map_shadow_stack (NULL, size, flags);
+  void *base = map_shadow_stack (NULL, sh_stack_size, flags);
   if (base == MAP_FAILED)
     return NULL;
 
-  uint64_t *gcsp = (uint64_t *) ((char *) base + size);
+  uint64_t *gcsp = (uint64_t *) ((char *) base + sh_stack_size);
   /* Skip end of GCS token.  */
   gcsp--;
   /* Verify GCS cap token.  */
   gcsp--;
   if (((uint64_t)gcsp & 0xfffffffffffff000) + 1 != *gcsp)
     {
-      __munmap (base, size);
+      __munmap (base, sh_stack_size);
       return NULL;
     }
 
-  if (gcs != NULL)
+  if (rec != NULL)
     {
-      gcs->gcs_base = base;
-      gcs->gcs_token = gcsp;
-      gcs->gcs_size = size;
+      rec->gcs_base = base;
+      rec->gcs_token = gcsp;
+      rec->gcs_size = sh_stack_size;
     }
 
   /* Return the target GCS pointer for context switch.  */
diff --git a/sysdeps/aarch64/aarch64-gcs.h b/sysdeps/aarch64/aarch64-gcs.h
index 8e253ed32f..148532ba77 100644
--- a/sysdeps/aarch64/aarch64-gcs.h
+++ b/sysdeps/aarch64/aarch64-gcs.h
@@ -23,6 +23,9 @@
 #include <stddef.h>
 #include <stdbool.h>
 
+#define GCS_MAX_SHADOW_STACK_SIZE (1UL << 31)
+#define GCS_ALTSTACK_RESERVE 160
+
 struct gcs_record
 {
   void *gcs_base;
@@ -30,7 +33,13 @@ struct gcs_record
   size_t gcs_size;
 };
 
-void *__alloc_gcs (size_t, struct gcs_record *) attribute_hidden;
+/* Allocate shadow stack of the given size SH_STACK_SIZE and write shadow
+   stack data in REC on success.  Return shadow stack pointer or NULL if
+   unsuccessful in which case REC is not updated.  The size of actually
+   allocated shadow stack may be reduced if the requested size exceeds
+   GCS_MAX_SHADOW_STACK_SIZE.  */
+void *__alloc_gcs (size_t sh_stack_size, struct gcs_record *rec)
+  attribute_hidden;
 
 static inline bool
 has_gcs (void)
diff --git a/sysdeps/aarch64/libc-shadow-stack.h b/sysdeps/aarch64/libc-shadow-stack.h
index 10e6792796..b8aac4b4d6 100644
--- a/sysdeps/aarch64/libc-shadow-stack.h
+++ b/sysdeps/aarch64/libc-shadow-stack.h
@@ -81,8 +81,9 @@ thread_alloc_shadow_stack (struct pthread *pd, size_t stacksize)
     }
   if (atomic_load_relaxed (&clone3_has_shadow_stack) == clone3_sh_stack_off)
     return 0;
+  size_t shadow_stack_size = (stacksize / 2 + GCS_ALTSTACK_RESERVE) & -8UL;
   struct gcs_record gcs;
-  if (__alloc_gcs (stacksize, &gcs) != NULL)
+  if (__alloc_gcs (shadow_stack_size, &gcs) != NULL)
     {
       pd->shadow_stack_base = gcs.gcs_base;
       pd->shadow_stack_token = gcs.gcs_token;
diff --git a/sysdeps/unix/sysv/linux/aarch64/makecontext.c b/sysdeps/unix/sysv/linux/aarch64/makecontext.c
index 4485723cfb..c9bb407e57 100644
--- a/sysdeps/unix/sysv/linux/aarch64/makecontext.c
+++ b/sysdeps/unix/sysv/linux/aarch64/makecontext.c
@@ -36,7 +36,8 @@ static struct _aarch64_ctx *extension (void *p)
 static void *
 alloc_makecontext_gcs (size_t stack_size)
 {
-  void *gcsp = __alloc_gcs (stack_size, NULL);
+  size_t shadow_stack_size = (stack_size / 2 + GCS_ALTSTACK_RESERVE) & -8UL;
+  void *gcsp = __alloc_gcs (shadow_stack_size, NULL);
   if (gcsp == NULL)
     /* ENOSYS, bad size or OOM.  */
     abort ();
-- 
2.47.3



More information about the Libc-alpha mailing list