Re: [PATCH] powerpc: Restore NULL check on _rtld_global_ro in INIT_ARCH [BZ #34503]
Michael Pfeifroth <[email protected]>
| Newsgroups | gmane.comp.lib.glibc.alpha |
|---|---|
| Message-ID | <[email protected]> |
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 <[email protected]> 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 <[email protected]> --- 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> -- 2.34.1 On 8/10/26 12:41, Michael Pfeifroth wrote: > Sorry, v1 was mangled by my mail client (tabs converted to spaces on > paste from X11 primary selection). Resending correctly. No changes > from v1 otherwise. > > -- >8 -- > 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. > > Signed-off-by: Michael Pfeifroth <[email protected]> > --- > sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h | 6 +++--- > 1 file changed, 3 insertions(+), 3 deletions(-) > > 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) \