[PATCH v5 09/16] riscv/cfi: Introduce tunables for CFI features

Jesse Huang jesse.huang@sifive.com
Wed Sep 16 07:53:52 GMT 2026


Thanks for catching this. It was fixed by the later 11th commit so I
didn't notice it.

On Mon, Sep 14, 2026 at 3:05 AM Gabriel Ravier <gabravier@gmail.com> wrote:
>
> On 6/28/26 9:02 AM, Jesse Huang wrote:
> > dl_riscv_feature_control is a structure whose members represent feature
> > configurations.  It is currently used only by CFI features.
> >
> > Each CFI feature is a 2-bit enum with values [on|off|permissive].  These
> > values decide whether a newly loaded legacy object should be blocked when
> > loaded dynamically, and can be controlled by glibc tunables.
> > ---
> >   manual/tunables.texi                |  22 +++
> >   sysdeps/riscv/Makefile              |   1 +
> >   sysdeps/riscv/cpu-features.c        |  46 ++++++
> >   sysdeps/riscv/cpu-tunables.c        |  50 +++++++
> >   sysdeps/riscv/dl-cfi.c              | 223 ++++++++++++++++++++++++++--
> >   sysdeps/riscv/dl-get-cpu-features.c |  27 ++++
> >   sysdeps/riscv/dl-machine.h          |  19 +++
> >   sysdeps/riscv/dl-procruntime.c      |  17 +++
> >   sysdeps/riscv/dl-tunables.list      |  27 ++++
> >   sysdeps/riscv/feature-control.h     |  42 ++++++
> >   sysdeps/riscv/ldsodefs.h            |   1 +
> >   sysdeps/riscv/libc-start.c          |  31 ++++
> >   sysdeps/riscv/libc-start.h          |  13 +-
> >   13 files changed, 500 insertions(+), 19 deletions(-)
> >   create mode 100644 sysdeps/riscv/cpu-features.c
> >   create mode 100644 sysdeps/riscv/cpu-tunables.c
> >   create mode 100644 sysdeps/riscv/dl-get-cpu-features.c
> >   create mode 100644 sysdeps/riscv/dl-tunables.list
> >   create mode 100644 sysdeps/riscv/feature-control.h
> >   create mode 100644 sysdeps/riscv/libc-start.c
> >
> > [snip]
> >
> > diff --git a/sysdeps/riscv/dl-cfi.c b/sysdeps/riscv/dl-cfi.c
> > index 74aa8b89ce..4723cde096 100644
> > --- a/sysdeps/riscv/dl-cfi.c
> > +++ b/sysdeps/riscv/dl-cfi.c
> > @@ -15,6 +15,7 @@
> >      License along with the GNU C Library; if not, see
> >      <https://www.gnu.org/licenses/>.  */
> >
> > +#include "feature-control.h"
> >   #include <asm-generic/errno-base.h>
> >   #include <unistd.h>
> >   #include <libintl.h>
> > @@ -22,8 +23,39 @@
> >   #include <dl-cfi.h>
> >   #include <sys/mman.h>
> >
> > +struct dl_cfi_info
> > +{
> > +  const char *program;
> > +
> > +  /* Check how lp and ss should be enabled.  */
> > +#ifdef __riscv_landing_pad
> > +  enum dl_riscv_cfi_control enable_lp_type;
> > +#endif
> > +#ifdef __riscv_shadow_stack
> > +  enum dl_riscv_cfi_control enable_ss_type;
> > +#endif
> > +
> > +  /* Previously enabled features.  */
> > +  unsigned int feature_1_enabled;
> > +
> > +  /* Features that should be enabled.  */
> > +  unsigned int enable_feature_1;
> > +
> > +  /* If there are any legacy shared object.  */
> > +  unsigned int feature_1_legacy;
> > +
> > +  /* Which shared object is the first legacy shared object.  */
> > +#ifdef __riscv_landing_pad
> > +  unsigned int feature_1_legacy_lp;
> > +#endif
> > +#ifdef __riscv_shadow_stack
> > +  unsigned int feature_1_legacy_ss;
> > +#endif
> > +};
> > +
> > +
> >   static void
> > -dl_check_legacy_object (struct link_map *m, unsigned int *feature_1)
> > +dl_check_legacy_object (struct link_map *m, struct dl_cfi_info *info)
> >   {
> >     /* Iterate through the dependencies and disable if needed here  */
> >     struct link_map *l = NULL;
> > @@ -42,32 +74,150 @@ dl_check_legacy_object (struct link_map *m, unsigned int *feature_1)
> >         /* 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))
> > +      if (is_rtld_link_map (l)
> > +          || is_rtld_link_map (l->l_real)
> > +          || (info->program != NULL && l == m))
> >           continue;
> >   #endif /* SHARED  */
> >
> > -      *feature_1 &= l->l_riscv_feature_1_and;
> > +      info->enable_feature_1 &= ((l->l_riscv_feature_1_and
> > +                                  & (GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED
> > +                                     | GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS))
> > +                                  | ~(GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED
> > +                                     | GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS));
> > +
> > +      /* Bookkeeping legacy objects  */
> > +#ifdef __riscv_landing_pad
> > +      if ((info->feature_1_legacy & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED) == 0
> > +          && ((info->enable_feature_1 & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED)
> > +              != (info->feature_1_enabled & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED))
> > +         )
> > +        {
> > +          info->feature_1_legacy_lp = i;
> > +          info->feature_1_legacy |= GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED;
> > +        }
> > +#endif
> > +#ifdef __riscv_shadow_stack
> > +      if ((info->feature_1_legacy & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS) == 0
> > +          && ((info->enable_feature_1 & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS)
> > +              != (info->feature_1_enabled & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS))
> > +         )
> > +        {
> > +          info->feature_1_legacy_ss = i;
> > +          info->feature_1_legacy |= GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS;
> > +        }
> > +#endif
> >       }
> > +
> > +  /* Keep bits set if cfi_always_on  */
> > +#ifdef __riscv_landing_pad
> > +  if ((info->feature_1_enabled & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED) != 0
> > +      && info->enable_lp_type == cfi_always_on)
> > +    {
> > +      info->enable_feature_1 |= GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED;
> > +    }
> > +#endif
> > +#ifdef __riscv_shadow_stack
> > +  if ((info->feature_1_enabled & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS) != 0
> > +      && info->enable_ss_type == cfi_always_on)
> > +    {
> > +      info->enable_feature_1 |= GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS;
> > +    }
> > +#endif
> >   }
> >
> >   #ifdef SHARED
> >   static void
> > -dl_cfi_check_startup (struct link_map *m, unsigned int *feature_1)
> > +dl_cfi_check_startup (struct link_map *m, struct dl_cfi_info *info)
> >   {
> > -  /* FIXME: Add tunables here  */
> > -  if (!*feature_1)
> > -    return;
> > -  dl_check_legacy_object (m, feature_1);
> > +# ifdef __riscv_landing_pad
> > +  if (info->enable_lp_type == cfi_always_on)
> > +    info->enable_feature_1 |= GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED;
> > +  else if (info->enable_lp_type == cfi_always_off)
> > +    info->enable_feature_1 &= ~GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED;
> > +  else
> > +    info->enable_feature_1 &= ((m->l_riscv_feature_1_and
> > +                                & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED)
> > +                               | ~GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED);
> > +# endif
> > +# ifdef __riscv_shadow_stack
> > +  if (info->enable_ss_type == cfi_always_on)
> > +    info->enable_feature_1 |= GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS;
> > +  else if (info->enable_ss_type == cfi_always_off)
> > +    info->enable_feature_1 &= ~GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS;
> > +  else
> > +    info->enable_feature_1 &= ((m->l_riscv_feature_1_and
> > +                                & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS)
> > +                               | ~GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS);
> > +# endif
> > +
> > +  if (info->enable_feature_1 != 0)
> > +    dl_check_legacy_object (m, info);
> >
> >     /* Update GL(dl_riscv_feature_1)  */
> > -  GL(dl_riscv_feature_1) = *feature_1;
> > +  if (info->enable_feature_1 ^ info->feature_1_enabled) {
> > +    info->feature_1_enabled = info->enable_feature_1;
> > +    GL(dl_riscv_feature_1) = info->enable_feature_1;
> > +  }
> >   }
> >   #endif /* SHARED  */
> >
> >   static void
> > -dl_cfi_check_dlopen (struct link_map *m)
> > +dl_cfi_check_dlopen (struct link_map *m, struct dl_cfi_info *info)
> >   {
> > +  if (info->enable_feature_1 != 0) {
> > +    dl_check_legacy_object(m, info);
> > +
> > +    if (info->feature_1_legacy == 0)
> > +      return;
> > +  }
> > +
> > +  unsigned int disable_feature_1 = 0;
> > +  unsigned int legacy_obj = 0;
> > +  const char *msg = NULL;
> > +
> > +#ifdef __riscv_landing_pad
> > +  if ((info->feature_1_enabled & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED) != 0
> > +      && (info->feature_1_legacy & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED) != 0)
> > +    {
> > +      if (info->enable_lp_type != cfi_permissive || !SINGLE_THREAD_P)
> > +        {
> > +          legacy_obj = info->feature_1_legacy_lp;
> > +          msg = N_("rebuild shared object with landing pad support");
> > +        }
> > +      else
> > +        disable_feature_1 |= GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED;
> > +    }
> > +#endif
> > +
> > +#ifdef __riscv_shadow_stack
> > +  if ((info->feature_1_enabled & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS) != 0
> > +      && (info->feature_1_legacy & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS) != 0)
> > +    {
> > +      if (info->enable_ss_type != cfi_permissive || !SINGLE_THREAD_P)
> > +        {
> > +          legacy_obj = info->feature_1_legacy_ss;
> > +          msg = N_("rebuild shared object with shadow stack support");
> > +        }
> > +      else
> > +        disable_feature_1 |= GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS;
> > +    }
> > +#endif
> > +
> > +  if (msg != NULL)
> > +    _dl_signal_error (0, m->l_initfini[legacy_obj]->l_name, "dlopen", msg);
> > +
> > +  if (disable_feature_1 != 0)
> > +      // FIXME: Disable CFI here
> > +      int res = -1;
> > +      if (res)
> > +        {
> > +          msg = N_("can't disable CFI feature");
> > +          _dl_signal_error (-res, m->l_initfini[legacy_obj]->l_name,
> > +                            "dlopen", msg);
> > +        }
> > +      GL(dl_riscv_feature_1) &= ~disable_feature_1;
> > +    }
> >   }
>
>
> The braces in the final if statement seem mismatched - As it is, I would
> have to presume this is unlikely to compile.
>
>
> >
> >   attribute_hidden void
> > @@ -89,20 +239,61 @@ _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;
> > +  struct dl_cfi_info info;
> >   #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  */
> >
> > +  unsigned int supported_exts = 0;
> > +  unsigned int always_on_exts = 0;
> > +
> > +#ifdef __riscv_landing_pad
> > +  info.enable_lp_type = GL(dl_riscv_feature_control).lp;
> > +  supported_exts += 1;
> > +  always_on_exts += (info.enable_lp_type == cfi_always_on);
> > +#endif
> > +#ifdef __riscv_shadow_stack
> > +  info.enable_ss_type = GL(dl_riscv_feature_control).ss;
> > +  supported_exts += 1;
> > +  always_on_exts += (info.enable_ss_type == cfi_always_on);
> > +#endif
> > +
> > +  info.feature_1_enabled = GL(dl_riscv_feature_1);
> > +
> > +  /* No legacy check needed if all cfi exts are always on in main  */
> > +  if (program && (supported_exts == always_on_exts))
> > +    return;
> > +
> > +  /* No legacy check needed if all cfi exts are off  */
> > +  if (info.feature_1_enabled == 0)
> > +    return;
> > +
> > +  info.program = program;
> > +
> > +  info.enable_feature_1 = 0;
> > +#ifdef __riscv_landing_pad
> > +  if (info.enable_lp_type != cfi_always_off)
> > +    info.enable_feature_1 |= (info.feature_1_enabled
> > +            & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED);
> > +  info.feature_1_legacy_lp = 0;
> > +#endif
> > +#ifdef __riscv_shadow_stack
> > +  if (info.enable_ss_type != cfi_always_off)
> > +    info.enable_feature_1 |= (info.feature_1_enabled
> > +            & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS);
> > +  info.feature_1_legacy_ss = 0;
> > +#endif
> > +
> > +  info.feature_1_enabled = GL(dl_riscv_feature_1);
> > +  info.feature_1_legacy = 0;
> > +
> >   #ifdef SHARED
> >     if (program)
> > -    dl_cfi_check_startup (l, &feature_1);
> > +    dl_cfi_check_startup (l, &info);
> >     else
> >   #endif /* SHARED  */
> > -    dl_cfi_check_dlopen (l);
> > +    dl_cfi_check_dlopen (l, &info);
> >   }
> >
> > [snip]
>
>


More information about the Libc-alpha mailing list