[PATCH v5 08/16] riscv/cfi: Enable CFI on dynamic binaries

Gabriel Ravier gabravier@gmail.com
Sun Sep 13 22:52:42 GMT 2026


On 6/28/26 9:02 AM, Jesse Huang wrote:
> For dynamic binaries, CFI features are parsed from GNU properties,
> stored in GLRO(dl_riscv_feature_1), and later enabled in RTLD_START.
>
> Co-authored-by: Deepak Gupta <debug@rivosinc.com>
> ---
>   sysdeps/riscv/Makefile                 |  2 +-
>   sysdeps/riscv/dl-cfi.c                 | 72 ++++++++++++++++++++++++++
>   sysdeps/riscv/dl-machine.h             |  2 +
>   sysdeps/riscv/dl-prop.h                |  9 ++++
>   sysdeps/riscv/features-offsets.sym     |  5 ++
>   sysdeps/unix/sysv/linux/riscv/dl-cfi.h | 30 +++++++++++
>   6 files changed, 119 insertions(+), 1 deletion(-)
>   create mode 100644 sysdeps/riscv/features-offsets.sym
>
> [snip]
> diff --git a/sysdeps/riscv/dl-cfi.c b/sysdeps/riscv/dl-cfi.c
> index 216e8f12c0..74aa8b89ce 100644
> --- a/sysdeps/riscv/dl-cfi.c
> +++ b/sysdeps/riscv/dl-cfi.c
> @@ -22,6 +22,54 @@
>   #include <dl-cfi.h>
>   #include <sys/mman.h>
>   
> +static void
> +dl_check_legacy_object (struct link_map *m, unsigned int *feature_1)
> +{
> +  /* Iterate through the dependencies and disable if needed here  */
> +  struct link_map *l = NULL;
> +  unsigned int i;
> +  i = m->l_searchlist.r_nlist;
> +  while (i-- > 0)
> +    {
> +      /* Check each shared object to see if shadow stack and landing pad
> +         are enabled.  */
> +      l = m->l_initfini[i];
> +
> +      if (l->l_init_called)
> +        continue;
> +
> +#ifdef SHARED
> +      /* Skip check for ld.so since it has the features enabled. The
> +         features will be disabled later if they are not enabled in
> +	 executable.  */
> +      if (l == &GL(dl_rtld_map)
> +          || l->l_real == &GL(dl_rtld_map))
> +        continue;
> +#endif /* SHARED  */
> +
> +      *feature_1 &= l->l_riscv_feature_1_and;
> +    }
> +}
> +
> +#ifdef SHARED
> +static void
> +dl_cfi_check_startup (struct link_map *m, unsigned int *feature_1)
> +{
> +  /* FIXME: Add tunables here  */
> +  if (!*feature_1)
> +    return;
> +  dl_check_legacy_object (m, feature_1);
> +
> +  /* Update GL(dl_riscv_feature_1)  */
> +  GL(dl_riscv_feature_1) = *feature_1;
> +}
> +#endif /* SHARED  */
> +
> +static void
> +dl_cfi_check_dlopen (struct link_map *m)
> +{
> +}
> +
>   attribute_hidden void
>   _dl_cfi_setup_features (unsigned int feature_1)
>   {
> @@ -34,3 +82,27 @@ _dl_cfi_setup_features (unsigned int feature_1)
>   #endif /* __riscv_landing_pad  */
>     /* FIXME: Read enabled features from kernel and re-sync  */
>   }
> +
> +/* Enable CFI for l and its dependencies.  */
> +void
> +_dl_cfi_check (struct link_map *l, const char *program)
> +{
> +    /* As this point we have parsed the gnu properties,
> +       for dynamic binary we should verify the dependencies here.  */
> +    /* FIXME: Implement different policy for supporting legacy binaries  */
> +  unsigned int feature_1;
> +#if defined SHARED && defined RTLD_START_ENABLE_RISCV_CFI
> +  if (program)
> +    {
> +      GL(dl_riscv_feature_1) = l->l_riscv_feature_1_and;
> +      feature_1 = l->l_riscv_feature_1_and;
> +    }
> +#endif /* SHARED  */
> +
> +#ifdef SHARED
> +  if (program)
> +    dl_cfi_check_startup (l, &feature_1);
> +  else
> +#endif /* SHARED  */
> +    dl_cfi_check_dlopen (l);
> +}
> diff --git a/sysdeps/riscv/dl-machine.h b/sysdeps/riscv/dl-machine.h
> index b7b9959d58..b64e7e67d8 100644
> --- a/sysdeps/riscv/dl-machine.h
> +++ b/sysdeps/riscv/dl-machine.h
> @@ -121,6 +121,8 @@ elf_machine_dynamic (void)
>   	" _RTLD_PROLOGUE (_dl_start_user) "\
>   	# Stash user entry point in s0.\n\
>   	mv s0, a0\n\
> +	# Setup CFI features\n\
> +	" RTLD_START_ENABLE_RISCV_CFI "\
>   	# Load the adjusted argument count.\n\
>   	" STRINGXP (REG_L) " a1, 0(sp)\n\
>   	# Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env) \n\
> diff --git a/sysdeps/riscv/dl-prop.h b/sysdeps/riscv/dl-prop.h
> index a183d3148a..f6cbf4c59c 100644
> --- a/sysdeps/riscv/dl-prop.h
> +++ b/sysdeps/riscv/dl-prop.h
> @@ -19,14 +19,23 @@
>   #ifndef _DL_PROP_H
>   #define _DL_PROP_H
>   
> +extern void _dl_cfi_check (struct link_map *, const char *)
> +    attribute_hidden;
> +
>   static inline void __attribute__ ((always_inline))
>   _rtld_main_check (struct link_map *m, const char *program)
>   {
> +#if defined(__riscv_landing_pad) || defined(__riscv_shadow_stack)
> +  _dl_cfi_check(m, program);
> +#endif /* __riscv_landing_pad || __riscv_shadow_stack */
>   }
>   
>   static inline void __attribute__ ((always_inline))
>   _dl_open_check (struct link_map *m, int dl_openmode)
>   {
> +#if defined(__riscv_landing_pad) || defined(__riscv_shadow_stack)
> +  _dl_cfi_check(m, NULL);
> +#endif /* __riscv_landing_pad || __riscv_shadow_stack */
>   }


AIUI GNU style dictates a space before the calls to _dl_cfi_check

>   
>   static inline void __attribute__ ((always_inline))
> [snip]




More information about the Libc-alpha mailing list