[PATCH] elf: Keep using minimal malloc after early DTV resize (bug 32412)

DJ Delorie dj@redhat.com
Wed Feb 12 03:16:58 GMT 2025


Copyright dates need updating now.  Otherwise LGTM

Reviewed-by: DJ Delorie <dj@redhat.com>

Florian Weimer <fweimer@redhat.com> writes:
> If an auditor loads many TLS-using modules during startup, it is
> possible to trigger DTV resizing.  Previously, the DTV was marked
> as allocated by the main malloc afterwards, even if the minimal
> malloc was still in use.  With this change, _dl_resize_dtv marks
> the resized DTV as allocated with the minimal malloc.

> diff --git a/elf/Makefile b/elf/Makefile
> index a5a25a8370..f2711d0a61 100644
> --- a/elf/Makefile
> +++ b/elf/Makefile
> @@ -378,6 +378,7 @@ tests += \
>    tst-align3 \
>    tst-audit-tlsdesc \
>    tst-audit-tlsdesc-dlopen \
> +  tst-audit-tlsdesc-dlopen2 \
>    tst-audit1 \
>    tst-audit2 \
>    tst-audit8 \
> @@ -844,6 +845,7 @@ modules-names += \
>    tst-auditmanymod8 \
>    tst-auditmanymod9 \
>    tst-auditmod-tlsdesc  \
> +  tst-auditmod-tlsdesc2 \
>    tst-auditmod1 \
>    tst-auditmod11 \
>    tst-auditmod12 \

Ok.

> +$(objpfx)tst-audit-tlsdesc-dlopen2.out: $(objpfx)tst-auditmod-tlsdesc2.so \
> +  $(patsubst %, $(objpfx)%.so, $(tlsmod17a-modules))
> +tst-audit-tlsdesc-dlopen2-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc2.so

OK.

> diff --git a/elf/dl-tls.c b/elf/dl-tls.c
>        if (newp == NULL)
>  	oom ();
>        memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t));
> +#ifdef SHARED
> +      /* Auditors can trigger a DTV resize event while the full malloc
> +	 is not yet in use.  Mark the new DTV allocation as the
> +	 initial allocation.  */
> +      if (!__rtld_malloc_is_complete ())
> +	GL(dl_initial_dtv) = &newp[1];
> +#endif
>      }

Based on every use of dl_initial_dtv, this variable means "if non-NULL,
this pointer was allocated with the minimal malloc".  Since we're only
retaining one pointer at a time (i.e. realloc) and we "clean up" here,
setting this pointer to the value we've allocated looks correct.

> diff --git a/elf/tst-audit-tlsdesc-dlopen2.c b/elf/tst-audit-tlsdesc-dlopen2.c

> +/* Loading TLS-using modules from auditors (bug 32412).  Main program.
> +   Copyright (C) 2021-2024 Free Software Foundation, Inc.

2025 now.

> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */

Ok.

> +#include <support/xdlfcn.h>
> +#include <stdio.h>
> +
> +static int
> +do_test (void)
> +{
> +  puts ("info: start of main program");
> +
> +  /* Load TLS-using modules, to trigger DTV resizing.  The dynamic
> +     linker will load them again (requiring their own TLS) because the
> +     dlopen calls from the auditor were in the auditing namespace.  */
> +  for (int i = 1; i <= 19; ++i)
> +    {
> +      char dso[30];
> +      snprintf (dso, sizeof (dso), "tst-tlsmod17a%d.so", i);
> +      char sym[30];
> +      snprintf (sym, sizeof(sym), "tlsmod17a%d", i);
> +
> +      void *handle = xdlopen (dso, RTLD_LAZY);
> +      int (*func) (void) = xdlsym (handle, sym);
> +      /* Trigger TLS allocation.  */
> +      func ();
> +    }
> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>

Ok.

> diff --git a/elf/tst-auditmod-tlsdesc2.c b/elf/tst-auditmod-tlsdesc2.c

> +/* Loading TLS-using modules from auditors (bug 32412).  Audit module.
> +   Copyright (C) 2021-2024 Free Software Foundation, Inc.

2025 now.

> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <dlfcn.h>
> +#include <link.h>
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <unistd.h>

Ok.

> +unsigned int
> +la_version (unsigned int version)
> +{

audit api OK.

> +  /* Open some modules, to trigger DTV resizing before the switch to
> +     the main malloc.  */
> +  for (int i = 1; i <= 19; ++i)
> +    {
> +      char dso[30];
> +      snprintf (dso, sizeof (dso), "tst-tlsmod17a%d.so", i);
> +      char sym[30];
> +      snprintf (sym, sizeof(sym), "tlsmod17a%d", i);
> +
> +      void *handle = dlopen (dso, RTLD_LAZY);

Why not xdlopen like the other file?  /me assumes because the error
message below needs to be different in case it fails.  Ok.

Maybe a comment clarifying this for the next reader?

> +      if (handle == NULL)
> +        {
> +          printf ("error: dlmopen from auditor: %s\n", dlerror  ());
> +          fflush (stdout);
> +          _exit (1);
> +        }
> +      int (*func) (void) = dlsym (handle, sym);
> +      if (func == NULL)
> +        {
> +          printf ("error: dlsym from auditor: %s\n", dlerror  ());
> +          fflush (stdout);
> +          _exit (1);
> +        }
> +      /* Trigger TLS allocation.  */
> +      func ();
> +    }
> +
> +  puts ("info: TLS-using modules loaded from auditor");
> +  fflush (stdout);
> +
> +  return LAV_CURRENT;
> +}

Ok.



More information about the Libc-alpha mailing list