For static binaries, CFI are enabled inside ARCH_SETUP_TLS, with a macro
to enable the shadow stack to prevent underflowing the shadow stack on
return, and with a function _dl_cfi_setup_features to enable landing
pad.
It scans backward of the program header to find the PT_GNU_PROPERTY note
first, then enable CFI features corresponding to the feature bits.
Co-authored-by: Deepak Gupta <debug@rivosinc.com>
---
sysdeps/riscv/Makefile | 1 +
sysdeps/riscv/dl-cfi.c | 36 +++++++++++
sysdeps/riscv/dl-machine.h | 6 ++
sysdeps/riscv/dl-prop.h | 65 +++++++++++++++++++
sysdeps/riscv/libc-start.h | 88 ++++++++++++++++++++++++++
sysdeps/unix/sysv/linux/riscv/dl-cfi.h | 20 ++++++
6 files changed, 216 insertions(+)
create mode 100644 sysdeps/riscv/dl-cfi.c
create mode 100644 sysdeps/riscv/dl-prop.h
create mode 100644 sysdeps/riscv/libc-start.h
create mode 100644 sysdeps/unix/sysv/linux/riscv/dl-cfi.h
@@ -18,6 +18,7 @@ endif
# Enable RISC-V CFI
ifeq (yes,$(riscv-enable-cfi))
+sysdep-dl-routines += dl-cfi
CFLAGS-.o += -fcf-protection=full
CFLAGS-.os += -fcf-protection=full
CFLAGS-.op += -fcf-protection=full
new file mode 100644
@@ -0,0 +1,36 @@
+/* RISC-V CFI extensions (zicfilp/zicfiss) functions.
+ Copyright (C) 2026 Free Software Foundation, Inc.
+
+ 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 <asm-generic/errno-base.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <ldsodefs.h>
+#include <dl-cfi.h>
+#include <sys/mman.h>
+
+attribute_hidden void
+_dl_cfi_setup_features (unsigned int feature_1)
+{
+ /* Since prctl could fail to enable some features
+ use prctl to get enabled features again and sync it back. */
+#ifdef __riscv_landing_pad
+ if (feature_1 & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED)
+ INTERNAL_SYSCALL_CALL (prctl, PR_SET_INDIR_BR_LP_STATUS,
+ PR_INDIR_BR_LP_ENABLE, 0, 0, 0);
+#endif /* __riscv_landing_pad */
+ /* FIXME: Read enabled features from kernel and re-sync */
+}
@@ -28,6 +28,12 @@
#include <dl-irel.h>
#include <dl-static-tls.h>
#include <dl-machine-rel.h>
+#if defined(__riscv_landing_pad) || defined(__riscv_shadow_stack)
+# include <dl-cfi.h>
+extern void _dl_cfi_setup_features (unsigned int features);
+#else
+# define RTLD_START_ENABLE_RISCV_CFI
+#endif
/* This is a marker to remind us to add real expansion to setup the label
for the function signature label scheme in the future */
#ifdef __riscv_landing_pad_unlabeled
new file mode 100644
@@ -0,0 +1,65 @@
+/* Support for GNU properties. RISC-V version.
+ Copyright (C) 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 _DL_PROP_H
+#define _DL_PROP_H
+
+static inline void __attribute__ ((always_inline))
+_rtld_main_check (struct link_map *m, const char *program)
+{
+}
+
+static inline void __attribute__ ((always_inline))
+_dl_open_check (struct link_map *m, int dl_openmode)
+{
+}
+
+static inline void __attribute__ ((always_inline))
+_dl_process_pt_note (struct link_map *l, int fd, const ElfW(Phdr) *ph)
+{
+}
+
+static inline int
+_dl_process_gnu_property (struct link_map *l, int fd, uint32_t type,
+ uint32_t datasz, void *data)
+{
+ /* FIXME: Detect cpu features after we have it implemented in glibc */
+
+ if (type == GNU_PROPERTY_RISCV_FEATURE_1_AND)
+ {
+ /* Stop if the property note is ill-formed. */
+ if (datasz != 4)
+ return -1;
+
+#if defined(__riscv_landing_pad) || defined(__riscv_shadow_stack)
+ unsigned int feature_1 = *(unsigned int *) data;
+#endif
+#ifdef __riscv_landing_pad
+ if (feature_1 & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED)
+ l->l_riscv_feature_1_and |= GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED;
+#endif
+#ifdef __riscv_shadow_stack
+ if (feature_1 & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS)
+ l->l_riscv_feature_1_and |= GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS;
+#endif
+ }
+ /* Continue. */
+ return 1;
+}
+
+#endif /* _DL_PROP_H */
new file mode 100644
@@ -0,0 +1,88 @@
+/* RISC-V libc main startup.
+ Copyright (C) 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 SHARED
+# define ARCH_SETUP_IREL() apply_irel ()
+# define ARCH_APPLY_IREL()
+
+# if defined(__riscv_landing_pad) || defined(__riscv_shadow_stack)
+/* Get shadow stack features enabled in the static executable. */
+# include <asm/prctl.h>
+# include <sys/prctl.h>
+extern void _dl_cfi_setup_features (unsigned int);
+
+static inline unsigned int
+get_cfi_feature (void)
+{
+ unsigned int cfi_feature = 0;
+ /* FIXME: check if cfi feature is supported by CPU */
+ struct link_map *main_map = _dl_get_dl_main_map ();
+
+ /* Scan program headers backward to check PT_GNU_PROPERTY early for
+ feature bits on static executable. */
+ const ElfW(Phdr) *phdr = GL(dl_phdr);
+ const ElfW(Phdr) *ph;
+ for (ph = phdr + GL(dl_phnum); ph != phdr; ph--)
+ if (ph[-1].p_type == PT_GNU_PROPERTY)
+ {
+ _dl_process_pt_gnu_property (main_map, -1, &ph[-1]);
+ /* Enable landing pad and shstk only if they are enabled on a static
+ executable. */
+ /* FIXME: change to &= to mask off other features after cpu_feature
+ is implemented */
+ cfi_feature = (main_map->l_riscv_feature_1_and
+ & (GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED
+ | GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS));
+
+ GL(dl_riscv_feature_1) = cfi_feature;
+ return cfi_feature;
+ }
+ GL(dl_riscv_feature_1) = 0;
+ return 0;
+}
+
+/* The function using this macro to enable shadow stack must not return
+ to avoid shadow stack underflow. */
+# ifdef __riscv_shadow_stack
+# define ENABLE_RISCV_SHADOW_STACK \
+ do \
+ { \
+ if (feature & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS) \
+ { \
+ INTERNAL_SYSCALL_CALL (prctl, PR_SET_SHADOW_STACK_STATUS, \
+ PR_SHADOW_STACK_ENABLE, 0, 0, 0); \
+ } \
+ } \
+ while (0)
+# else
+# define ENABLE_RISCV_SHADOW_STACK
+# endif
+
+# define ARCH_SETUP_TLS() \
+ { \
+ __libc_setup_tls (); \
+ \
+ unsigned int feature = get_cfi_feature (); \
+ ENABLE_RISCV_SHADOW_STACK; \
+ /* Landing pad will be enabled in _dl_cfi_setup_features */ \
+ _dl_cfi_setup_features(feature); \
+ }
+# else
+# define ARCH_SETUP_TLS() __libc_setup_tls ()
+# endif /* __riscv_landing_pad || __riscv_shadow_stack */
+#endif /* !SHARED */
new file mode 100644
@@ -0,0 +1,20 @@
+/* Linux/RISC-V CFI initializers function.
+ Copyright (C) 2026 Free Software Foundation, Inc.
+
+ 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/>. */
+
+/* FIXME: Should be remove after they are included in the kernel header */
+#include <asm/prctl.h>
+#include <sys/prctl.h>