[v4,14/17] riscv/cfi: Add __allocate_shadow_stack for mapping new shadow stack

Message ID 20260526061703.2188042-15-jesse.huang@sifive.com (mailing list archive)
State New
Headers
Series Support RISC-V Control Flow Integrifty (CFI) |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent
linaro-tcwg-bot/tcwg_glibc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_glibc_check--master-arm success Test passed

Commit Message

Jesse Huang May 26, 2026, 6:17 a.m. UTC
  Co-authored-by: Valentin Haudiquet <valentin.haudiquet@canonical.com>
Co-authored-by: Jerry Zhang Jian <jerry.zhangjian@sifive.com>
---
 sysdeps/unix/sysv/linux/riscv/Makefile        |  1 +
 .../sysv/linux/riscv/allocate-shadow-stack.c  | 59 +++++++++++++++++++
 .../sysv/linux/riscv/allocate-shadow-stack.h  | 31 ++++++++++
 sysdeps/unix/sysv/linux/riscv/bits/mman.h     | 30 ++++++++++
 sysdeps/unix/sysv/linux/riscv/sysdep.h        |  2 +
 5 files changed, 123 insertions(+)
 create mode 100644 sysdeps/unix/sysv/linux/riscv/allocate-shadow-stack.c
 create mode 100644 sysdeps/unix/sysv/linux/riscv/allocate-shadow-stack.h
 create mode 100644 sysdeps/unix/sysv/linux/riscv/bits/mman.h
  

Patch

diff --git a/sysdeps/unix/sysv/linux/riscv/Makefile b/sysdeps/unix/sysv/linux/riscv/Makefile
index 04abf226ad..e6b1a02c59 100644
--- a/sysdeps/unix/sysv/linux/riscv/Makefile
+++ b/sysdeps/unix/sysv/linux/riscv/Makefile
@@ -5,6 +5,7 @@  sysdep_headers += \
   # sysdep_headers
 
 sysdep_routines += \
+  allocate-shadow-stack \
   flush-icache \
   hwprobe \
   # sysdep_routines
diff --git a/sysdeps/unix/sysv/linux/riscv/allocate-shadow-stack.c b/sysdeps/unix/sysv/linux/riscv/allocate-shadow-stack.c
new file mode 100644
index 0000000000..e64ddb2c56
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/riscv/allocate-shadow-stack.c
@@ -0,0 +1,59 @@ 
+/* Helper function to allocate shadow stack.
+   Copyright (C) 2023-2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+#include <stdint.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <libc-pointer-arith.h>
+#include <allocate-shadow-stack.h>
+
+#ifndef SHADOW_STACK_SET_TOKEN
+# define SHADOW_STACK_SET_TOKEN 0
+#endif
+
+/* NB: This can be treated as a syscall by caller.  */
+
+long int
+__allocate_shadow_stack (size_t stack_size,
+			 shadow_stack_size_t *child_stack)
+{
+#ifdef __NR_map_shadow_stack
+  size_t shadow_stack_size
+    = stack_size >> STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT;
+  /* Align shadow stack to 8 bytes.  */
+  shadow_stack_size = ALIGN_UP (shadow_stack_size, 8);
+  /* Since sigaltstack shares shadow stack with the current context in
+     the thread, add extra 20 stack frames in shadow stack for signal
+     handlers.  */
+  shadow_stack_size += 20 * 8;
+  void *shadow_stack = (void *)INLINE_SYSCALL_CALL
+    (map_shadow_stack, NULL, shadow_stack_size, SHADOW_STACK_SET_TOKEN);
+  /* Report the map_shadow_stack error.  */
+  if (shadow_stack < 0)
+    return -errno;
+
+  /* Save the shadow stack base and size on child stack.  */
+  child_stack[0] = (uintptr_t) shadow_stack;
+  child_stack[1] = shadow_stack_size;
+
+  return 0;
+#else
+  return -ENOSYS;
+#endif
+}
diff --git a/sysdeps/unix/sysv/linux/riscv/allocate-shadow-stack.h b/sysdeps/unix/sysv/linux/riscv/allocate-shadow-stack.h
new file mode 100644
index 0000000000..4e361c8566
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/riscv/allocate-shadow-stack.h
@@ -0,0 +1,31 @@ 
+/* Helper function to allocate shadow stack.
+   Copyright (C) 2023-2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sys/ucontext.h>
+
+#ifdef __riscv_shadow_stack
+/* When shadow stack is enabled, derive the storage type from ucontext.  */
+typedef __typeof (((ucontext_t *) 0)->__saved.__ssp) \
+        shadow_stack_size_t;
+#else
+/* Without shadow stack support, use an unsigned long placeholder type.  */
+typedef unsigned long int shadow_stack_size_t;
+#endif
+
+extern long int __allocate_shadow_stack (size_t, shadow_stack_size_t *)
+  attribute_hidden;
diff --git a/sysdeps/unix/sysv/linux/riscv/bits/mman.h b/sysdeps/unix/sysv/linux/riscv/bits/mman.h
new file mode 100644
index 0000000000..46f50be71c
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/riscv/bits/mman.h
@@ -0,0 +1,30 @@ 
+/* Definitions for POSIX memory map interface.  Linux/risc-v version.
+   Copyright (C) 1997-2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _SYS_MMAN_H
+# error "Never use <bits/mman.h> directly; include <sys/mman.h> instead."
+#endif
+
+#if defined __USE_MISC && defined __riscv_shadow_stack
+# define SHADOW_STACK_SET_TOKEN 0x1
+#endif
+
+#include <bits/mman-map-flags-generic.h>
+
+/* Include generic Linux declarations.  */
+#include <bits/mman-linux.h>
diff --git a/sysdeps/unix/sysv/linux/riscv/sysdep.h b/sysdeps/unix/sysv/linux/riscv/sysdep.h
index 761a833609..75b1cc4fda 100644
--- a/sysdeps/unix/sysv/linux/riscv/sysdep.h
+++ b/sysdeps/unix/sysv/linux/riscv/sysdep.h
@@ -206,6 +206,8 @@  GNU_PROPERTY (FEATURE_1_AND, __VALUE_FOR_FEATURE_1_AND)
 
 #else /* !__ASSEMBLER__ */
 
+# define STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT 5
+
 # if __WORDSIZE == 64
 #  define VDSO_NAME	"LINUX_4.15"
 #  define VDSO_HASH	182943605