[PATCH v5 09/16] riscv/cfi: Introduce tunables for CFI features
Gabriel Ravier
gabravier@gmail.com
Sun Sep 13 19:05:25 GMT 2026
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