[PATCH] powerpc: Restore NULL check on _rtld_global_ro in INIT_ARCH [BZ #34503]
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Thu Sep 3 16:50:57 GMT 2026
On 11/08/26 10:28, Michael Pfeifroth wrote:
> On 11/08/26 08:50, Adhemerval Zanella Netto wrote:
>> The patch looks good, but maybe it would be good to add a regression testcase
>> for that. [...]
>
> Thanks for the review. v2 adds the test as suggested — ppc64 only as
> you noted.
>
> The module (tst-ppc64-ifunc-bind-now-mod.so) is linked with -z,now and
> has no DT_NEEDED on libm; the main binary has DT_NEEDED on libm so modf
> resolves correctly at runtime. The test simply calls ifunc_ptr(2.5,
> &ip) and checks the result: without the fix the process would segfault
> before reaching the check.
>
> -- >8 --
> From 0000000000000000000000000000000000000002 Mon Sep 17 00:00:00 2001
> From: Michael Pfeifroth <micpf@westermo.com>
> Date: Mon, 11 Aug 2026 14:30:00 +0200
> Subject: [PATCH v2] powerpc: Restore NULL check on _rtld_global_ro in
> INIT_ARCH [BZ #34503]
>
> Commit 21841f0d562f ("PowerPC: Influence cpu/arch hwcap features via
> GLIBC_TUNABLES") changed the INIT_ARCH() macro used by powerpc32/power4
> and (via a one-line include) powerpc64 multiarch IFUNC resolvers to
> read hwcap and hwcap2 through a direct
>
> &GLRO(dl_powerpc_cpu_features)
>
> reference, instead of the previous __GLRO() wrapper. The __GLRO() macro
> performs a volatile NULL check on _rtld_global_ro, which matters because
> IFUNC resolvers can run before _rtld_global_ro has been relocated for the
> current library.
>
> This regression triggers when a shared library's IFUNC symbol from libm
> is resolved via BIND_NOW (full RELRO) before libm's own GOT is relocated:
> the resolver's INIT_ARCH() then dereferences a NULL _rtld_global_ro and
> segfaults at the hwcap load. The concrete failure seen was rsyslogd
> crashing on startup on powerpc64 (e5500, BE) with
>
> rsyslogd -> librsyslog -> libfastjson -> modf() IFUNC in libm
>
> when libfastjson lacked a DT_NEEDED on libm, so libm was relocated after
> libfastjson's IFUNC resolvers ran.
>
> Restore the __GLRO()-based access for both hwcap and hwcap2, matching
> the pre-2.41 behaviour and how use_cached_memopt is already read in the
> same macro. This is a no-op once _rtld_global_ro is fully initialised
> and simply reinstates the early-startup NULL guard.
>
> Add a regression test (ppc64 only; ppc32 has additional early-startup
> constraints that make the same test infeasible there). The module is
> linked with -z,now and intentionally has no DT_NEEDED on libm, so the
> IFUNC resolver for modf() runs before libm is fully relocated.
>
> Signed-off-by: Michael Pfeifroth <micpf@westermo.com>
LGTM, thanks.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
> ---
> sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h | 6 ++--
> sysdeps/powerpc/powerpc64/Makefile | 13 +++++++
> sysdeps/powerpc/powerpc64/tst-ppc64-ifunc-bind-now-mod.c | 28 +++++++++++++++
> sysdeps/powerpc/powerpc64/tst-ppc64-ifunc-bind-now.c | 45 +++++++++++++++++++++++++
> 4 files changed, 89 insertions(+), 3 deletions(-)
> create mode 100644 sysdeps/powerpc/powerpc64/tst-ppc64-ifunc-bind-now-mod.c
> create mode 100644 sysdeps/powerpc/powerpc64/tst-ppc64-ifunc-bind-now.c
>
> diff --git a/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h b/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h
> index 9aab67a5..e681b452 100644
> --- a/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h
> +++ b/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h
> @@ -36,9 +36,9 @@
> /* Get the hardware information post the tunables set, the macro checks
> it and fills the previous ones. */
> #define INIT_ARCH() \
> - const struct cpu_features *features = &GLRO(dl_powerpc_cpu_features); \
> - unsigned long int hwcap = features->hwcap; \
> - unsigned long int __attribute__((unused)) hwcap2 = features->hwcap2; \
> + unsigned long int hwcap = __GLRO(dl_powerpc_cpu_features.hwcap); \
> + unsigned long int __attribute__((unused)) hwcap2 = \
> + __GLRO(dl_powerpc_cpu_features.hwcap2); \
> bool __attribute__((unused)) use_cached_memopt = \
> __GLRO(dl_powerpc_cpu_features.use_cached_memopt); \
> if (hwcap & PPC_FEATURE_ARCH_2_06) \
>
> diff --git a/sysdeps/powerpc/powerpc64/Makefile b/sysdeps/powerpc/powerpc64/Makefile
> index 12345678..abcdefab 100644
> --- a/sysdeps/powerpc/powerpc64/Makefile
> +++ b/sysdeps/powerpc/powerpc64/Makefile
> @@ -42,6 +42,19 @@ CFLAGS-rtld-strnlen.os = $(no-special-regs)
> ifeq ($(subdir),elf)
> # help gcc inline asm code from dl-machine.h
> +cflags += -finline-limit=2000
> +
> +# Regression test for BZ #34503: IFUNC resolver crash with BIND_NOW when
> +# _rtld_global_ro has not been relocated yet in the calling library's GOT.
> +# Restricted to ppc64; ppc32 has additional early-startup constraints.
> +tests += tst-ppc64-ifunc-bind-now
> +modules-names += tst-ppc64-ifunc-bind-now-mod
> +tst-ppc64-ifunc-bind-now-mod.so-no-z-defs = yes
> +LDFLAGS-tst-ppc64-ifunc-bind-now-mod.so = -Wl,-z,now
> +$(objpfx)tst-ppc64-ifunc-bind-now: $(objpfx)tst-ppc64-ifunc-bind-now-mod.so
> +LDLIBS-tst-ppc64-ifunc-bind-now = -Wl,--no-as-needed -lm \
> + $(objpfx)tst-ppc64-ifunc-bind-now-mod.so
> endif
>
> diff --git a/sysdeps/powerpc/powerpc64/tst-ppc64-ifunc-bind-now-mod.c b/sysdeps/powerpc/powerpc64/tst-ppc64-ifunc-bind-now-mod.c
> new file mode 100644
> index 00000000..11111111
> --- /dev/null
> +++ b/sysdeps/powerpc/powerpc64/tst-ppc64-ifunc-bind-now-mod.c
> @@ -0,0 +1,28 @@
> +/* Shared library module for tst-ppc64-ifunc-bind-now.
> + Copyright (C) 2026 Free Software Foundation, Inc.
> + 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/>. */
> +
> +/* Reference modf without a DT_NEEDED on libm. This module is linked
> + with -z,now so its BIND_NOW IFUNC relocation for modf() runs as early
> + as possible during dynamic linking -- before _rtld_global_ro has been
> + relocated in this library's GOT context. Tests that INIT_ARCH()
> + handles a NULL _rtld_global_ro gracefully (BZ #34503). */
> +
> +extern double modf (double, double *);
> +
> +double (*volatile ifunc_ptr) (double, double *) = modf;
>
> diff --git a/sysdeps/powerpc/powerpc64/tst-ppc64-ifunc-bind-now.c b/sysdeps/powerpc/powerpc64/tst-ppc64-ifunc-bind-now.c
> new file mode 100644
> index 00000000..22222222
> --- /dev/null
> +++ b/sysdeps/powerpc/powerpc64/tst-ppc64-ifunc-bind-now.c
> @@ -0,0 +1,45 @@
> +/* Regression test for BZ #34503: powerpc IFUNC resolver crash with BIND_NOW.
> + Copyright (C) 2026 Free Software Foundation, Inc.
> + 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/>. */
> +
> +/* Verify that calling an IFUNC function (modf from libm) via a function
> + pointer exported from a shared library that was linked with -z,now and
> + has no DT_NEEDED on libm does not crash.
> +
> + Without the fix, INIT_ARCH() in the modf IFUNC resolver dereferences
> + _rtld_global_ro directly; if that pointer has not been relocated yet
> + in the module's GOT context, the dereference faults. With the fix,
> + the __GLRO() wrapper returns 0 when _rtld_global_ro is NULL and the
> + resolver falls back to the default implementation. */
> +
> +#include <math.h>
> +#include <stdio.h>
> +#include <support/check.h>
> +
> +/* Exported by tst-ppc64-ifunc-bind-now-mod.so, which is built with
> + -z,now and has no DT_NEEDED on libm. */
> +extern double (*volatile ifunc_ptr) (double, double *);
> +
> +static int
> +do_test (void)
> +{
> + double ip;
> + double frac = ifunc_ptr (2.5, &ip);
> + printf ("modf(2.5) = %g + %g (expect 0.5 + 2)\n", frac, ip);
> + TEST_VERIFY (frac == 0.5);
> + TEST_VERIFY (ip == 2.0);
> + return 0;
> +}
> +
> +#include <support/test-driver.c>
More information about the Libc-alpha
mailing list