[PATCH] aarch64: Fix error messages for GCS and BTI incompatible modules

Adhemerval Zanella Netto adhemerval.zanella@linaro.org
Fri Dec 19 14:17:55 GMT 2025



On 12/12/25 09:14, Yury Khrustalev wrote:
> When either program path of module name is empty, don't print an
> empty string followed by a colon.

Afaik the module name will be always not empty.

> ---
>  sysdeps/aarch64/dl-bti.c | 15 ++++++++++++---
>  sysdeps/aarch64/dl-gcs.c | 16 ++++++++++++----
>  2 files changed, 24 insertions(+), 7 deletions(-)
> 
> diff --git a/sysdeps/aarch64/dl-bti.c b/sysdeps/aarch64/dl-bti.c
> index e654dde484..c506090485 100644
> --- a/sysdeps/aarch64/dl-bti.c
> +++ b/sysdeps/aarch64/dl-bti.c
> @@ -62,17 +62,26 @@ _dl_bti_protect (struct link_map *map, int fd)
>        }
>  }
>  
> +#define STR_NOT_EMPTY(x) ((x != NULL) && x[0])
>  
>  static void
>  bti_failed (struct link_map *l, const char *program)
>  {
> -  if (program)
> +  if (STR_NOT_EMPTY (program) && STR_NOT_EMPTY (l->l_name))
> +    /* A program's dependency is not GCS compatible.  */
>      _dl_fatal_printf ("%s: %s: failed to turn on BTI protection\n",
>  		      program, l->l_name);
> +  else if (STR_NOT_EMPTY (program))
> +    /* The program itself is not GCS compatible.  */
> +    _dl_fatal_printf ("%s: failed to turn on BTI protection\n", program);
> +  else if (program)
> +    /* For static binaries, program will be an empty string.  */
> +    _dl_fatal_printf ("error: failed to turn on BTI protection\n");
>    else
> -    /* Note: the errno value is not available any more.  */
> +    /* If program is NULL, we are processing a dlopen operation.
> +       Note: the errno value is not available any more.  */
>      _dl_signal_error (0, l->l_name, "dlopen",
> -		      N_("failed to turn on BTI protection"));
> +		      "failed to turn on BTI protection");
>  }
>  

We can assume that l->l_name is always non NULL (even though there is
some code that assumes otherwise) and if is not empty then program
is also non-null:

  elf/rtld.c
  \_ _rtld_main_check (main_map, _dl_argv[0]);
      \_ _dl_bti_check (m, program);
         \_ _dl_bti_check

In this case _dl_argv is always non-null as well.

If program is NULL, we can then assume that l->l_name always contains
a proper name (dlopen case)

So I think we can simplify to:

  static void
  bti_failed (struct link_map *l, const char *program)
  {
    if (l->l_name[0] == '\0')
      {
        if (program[0] == '\0')
          _dl_fatal_printf ("error: failed to turn on BTI protection\n");
        else
          _dl_fatal_printf ("%s: failed to turn on BTI protection\n",
                           program);
      }
    else
      /* Note: the errno value is not available any more.  */
      _dl_signal_error (0, l->l_name, "dlopen",
                        N_("failed to turn on BTI protection"));
  }

The dynamic linked binaries will now issue:

  <program>: failed to turn on BTI protection

And static/static-pie will issue:

  error: failed to turn on BTI protection

Unfortunately we can safely enable an 'assert (program != NULL)' on the
startup case because of [1]

[1] https://patchwork.sourceware.org/project/glibc/patch/20251117202613.2565803-5-adhemerval.zanella@linaro.org/

>  
> diff --git a/sysdeps/aarch64/dl-gcs.c b/sysdeps/aarch64/dl-gcs.c
> index 4ac86a5d6f..9374fd4931 100644
> --- a/sysdeps/aarch64/dl-gcs.c
> +++ b/sysdeps/aarch64/dl-gcs.c
> @@ -30,21 +30,29 @@
>  /* Override binary marking and always enabled GCS.  */
>  #define GCS_POLICY_OVERRIDE 3
>  
> +#define STR_NOT_EMPTY(x) ((x != NULL) && x[0])
> +
>  static void
>  fail (struct link_map *l, const char *program)
>  {
> -  if (program && program[0])
> -    _dl_fatal_printf ("%s: %s: %s\n", program, l->l_name, "not GCS compatible");
> +  if (STR_NOT_EMPTY (program) && STR_NOT_EMPTY (l->l_name))
> +    /* A program's dependency is not GCS compatible.  */
> +    _dl_fatal_printf ("%s: %s: not GCS compatible\n", program, l->l_name);
> +  else if (STR_NOT_EMPTY (program))
> +    /* The program itself is not GCS compatible.  */
> +    _dl_fatal_printf ("%s: not GCS compatible\n", program);
>    else if (program)
> -    _dl_fatal_printf ("%s\n", "not GCS compatible");
> +    /* For static binaries, program will be an empty string.  */
> +    _dl_fatal_printf ("error: not GCS compatible\n");
>    else
> +    /* If program is NULL, we are processing a dlopen operation.  */
>      _dl_signal_error (0, l->l_name, "dlopen", "not GCS compatible");
>  }
>  
>  static void
>  unsupported (void)
>  {
> -  _dl_fatal_printf ("%s\n", "unsupported GCS policy");
> +  _dl_fatal_printf ("unsupported GCS policy\n");
>  }
>  
>  /* This function is called only when binary markings are not



More information about the Libc-alpha mailing list