[PATCH v3] dlfcn: Add dlinfo request type RTLD_DI_ORIGIN_PATH (bug #24298)

Carlos O'Donell carlos@redhat.com
Fri Jan 16 21:33:15 GMT 2026


On 1/16/26 3:18 PM, Arjun Shankar wrote:
> The existing dlinfo request type RTLD_DI_ORIGIN used for querying the
> value of the '$ORIGIN' dynamic string token is prone to buffer
> overflows.
> 
> This commit adds a new request type named RTLD_DI_ORIGIN_PATH that
> returns a pointer to the dynamic string token (i.e. the 'l_origin' field
> in the link map) instead.  The dlinfo manual is updated with the new
> request type, and the description of RTLD_DI_ORIGIN is updated to
> recommend RTLD_DI_ORIGIN_PATH instead.
> 
> A test for the new request type is also added to tst-dlinfo.

Adding a new flag seems like the best option here. Likewise we'll have
to migrate away users from the other API. How do we plan to do that?
Can we add a "sleep(10)" or deprecation warning?

OK to keep my RB if you accept my textual suggestion.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>

> ---
> v2: https://inbox.sourceware.org/libc-alpha/20260116150921.3841139-1-arjun@redhat.com/
> Changes in v3: Address Carlos' review comments on the manual change:
>   * Specify the lifetime of the result's validity
> ---
>   dlfcn/dlfcn.h       |  7 ++++++-
>   dlfcn/dlinfo.c      |  7 +++++++
>   dlfcn/tst-dlinfo.c  |  8 ++++++++
>   manual/dynlink.texi | 12 +++++++++++-
>   4 files changed, 32 insertions(+), 2 deletions(-)
> 
> diff --git a/dlfcn/dlfcn.h b/dlfcn/dlfcn.h
> index a1ee0765bd..a73303a17e 100644
> --- a/dlfcn/dlfcn.h
> +++ b/dlfcn/dlfcn.h
> @@ -167,7 +167,12 @@ enum
>          the number of program headers in the array.  */
>       RTLD_DI_PHDR = 11,
>   
> -    RTLD_DI_MAX = 11
> +    /* Treat ARG as `const char **' and at that location, store the address
> +       of the directory name used to expand $ORIGIN in this shared object's
> +       dependency file names.  */
> +    RTLD_DI_ORIGIN_PATH = 12,
> +
> +    RTLD_DI_MAX = 12
>     };
>   
>   
> diff --git a/dlfcn/dlinfo.c b/dlfcn/dlinfo.c
> index 6a1a7345b5..a4c6ffb5b8 100644
> --- a/dlfcn/dlinfo.c
> +++ b/dlfcn/dlinfo.c
> @@ -67,6 +67,13 @@ dlinfo_doit (void *argsblock)
>         strcpy (args->arg, l->l_origin);
>         break;
>   
> +    case RTLD_DI_ORIGIN_PATH:
> +      if (l->l_origin != (char *) -1)
> +        *(const char **) args->arg = l->l_origin;
> +      else
> +        *(const char **) args->arg = NULL;
> +      break;
> +
>       case RTLD_DI_TLS_MODID:
>         *(size_t *) args->arg = 0;
>         *(size_t *) args->arg = l->l_tls_modid;
> diff --git a/dlfcn/tst-dlinfo.c b/dlfcn/tst-dlinfo.c
> index 014cb1b6ff..d0c8d8fb6d 100644
> --- a/dlfcn/tst-dlinfo.c
> +++ b/dlfcn/tst-dlinfo.c
> @@ -20,6 +20,7 @@
>   #include <stdio.h>
>   #include <stdlib.h>
>   #include <error.h>
> +#include <support/check.h>
>   
>   #define TEST_FUNCTION do_test ()
>   
> @@ -56,6 +57,13 @@ do_test (void)
>         printf ("origin: %s\n", origin);
>       }
>   
> +  const char *origin_path;
> +  TRY (RTLD_DI_ORIGIN_PATH, &origin_path)
> +    {
> +      TEST_COMPARE_STRING (origin, origin_path);
> +      printf ("origin_path: %s\n", origin_path);
> +    }
> +
>     Dl_serinfo counts;
>     TRY (RTLD_DI_SERINFOSIZE, &counts)
>       {
> diff --git a/manual/dynlink.texi b/manual/dynlink.texi
> index a388d7eeeb..477370b81a 100644
> --- a/manual/dynlink.texi
> +++ b/manual/dynlink.texi
> @@ -554,13 +554,23 @@ The namespace identifier of @var{handle} is written to
>   @code{*@var{arg}}.  The @var{arg} argument must be the address of an
>   object of type @code{Lmid_t}.
>   
> +@item RTLD_DI_ORIGIN_PATH
> +The @code{$ORIGIN} dynamic string token pointer for @var{handle} is written
> +to @code{*@var{arg}}.  The @var{arg} argument must be the address of a
> +@code{const char *}.  If the @code{$ORIGIN} could not be determined, the
> +function still returns 0 but writes a null pointer to @code{*@var{arg}}.
> +The returned string is only valid as long as the corresponding handle is
> +valid.  Accessing it after @code{dlclose} has been called for the
> +corresponding object is not safe.

Accessing the string is UAF after dlclose() of HANDLE.

Suggest:
s/object is not safe/@var{handle} is undefined behavior./g


> +
>   @item RTLD_DI_ORIGIN
>   The value of the @code{$ORIGIN} dynamic string token for @var{handle} is
>   written to the character array starting at @var{arg} as a
>   null-terminated string.
>   
>   This request type should not be used because it is prone to buffer
> -overflows.
> +overflows.  Instead, @code{RTLD_DI_ORIGIN_PATH} described above should be
> +used.
>   
>   @item RTLD_DI_SERINFO
>   @itemx RTLD_DI_SERINFOSIZE


-- 
Cheers,
Carlos.



More information about the Libc-alpha mailing list