Re: [PATCH 1/2] elf: Honour skip_ifunc for cross-object IFUNC relocations [BZ #34428]

Adhemerval Zanella Netto <[email protected]> Mon, 3 Aug 2026 07:49:33 -0300
Newsgroups gmane.comp.lib.glibc.alpha
Organization Linaro
Message-ID <[email protected]>

On 02/08/26 22:04, H.J. Lu wrote:
> On Mon, Aug 3, 2026 at 8:28 AM H.J. Lu <[email protected]> wrote:
>>
>> On Mon, Aug 3, 2026 at 8:11 AM H.J. Lu <[email protected]> wrote:
>>>
>>> On Mon, Aug 3, 2026 at 7:45 AM Adhemerval Zanella
>>> <[email protected]> wrote:
>>>>
>>>> Commit 63b31c05a8a dropped the skip_ifunc argument from elf_dynamic_do_Rel,
>>>> assuming the elf_dynamic_do_Rel_irelative pass handles every relocation
>>>> that may run an IFUNC resolver.  That only holds for IFUNC symbols defined
>>>> in the object being relocated, a reference to an IFUNC in another object is
>>>> an ordinary JMP_SLOT or GLOB_DAT against an undefined symbol, and being
>>>> IFUNC is only known after symbol resolution (elf_machine_rel).  Those
>>>> relocations stay in the regular pass, which no longer propagated
>>>> skip_ifunc, so __RTLD_NOIFUNC was ignored for them.
>>>>
>>>> ldd -u forces non-lazy binding (GLRO(dl_lazy) = 0 for DL_DEBUG_UNUSED), so
>>>> the resolver was called and the diagnostic emitted:
>>>>
>>>>   $ ldd -u /bin/ls
>>>>   /bin/ls: Relink `' with `/usr/lib64/libc.so.6' for IFUNC symbol `__mempcpy_chk'
>>>>
>>>> ldd -r with LD_BIND_NOW is affected in the same way.
>>>>
>>>> Restore the skip_ifunc parameter and pass it through _ELF_DYNAMIC_DO_RELOC
>>>> and ELF_DYNAMIC_RELOCATE_NOIFUNC.
>>>>
>>>> Checked on x86_64-linux-gnu, aarch64-linux-gnu, and i686-linux-gnu. I
>>>> also built for all supported architectures and run the elf tests on
>>>> qemu-system for armhf, alpha, hppa, loongarch64, mipsel, mips64le,
>>>> powerpc*, riscv64, s390x, and sparc64.
>>>> ---
>>>>  elf/Makefile                      | 28 +++++++++++++++++++++++
>>>>  elf/dl-reloc-static-pie.c         |  2 +-
>>>>  elf/dl-reloc.c                    |  3 ++-
>>>>  elf/do-rel.h                      | 24 ++++++++++++-------
>>>>  elf/dynamic-link.h                | 32 ++++++++++++++++----------
>>>>  elf/tst-ifunc-fault-dep-bindnow.c | 19 ++++++++++++++++
>>>>  elf/tst-ifunc-fault-dep-lazy.c    | 27 ++++++++++++++++++++++
>>>>  elf/tst-ifunc-fault-mod.c         | 38 +++++++++++++++++++++++++++++++
>>>>  8 files changed, 151 insertions(+), 22 deletions(-)
>>>>  create mode 100644 elf/tst-ifunc-fault-dep-bindnow.c
>>>>  create mode 100644 elf/tst-ifunc-fault-dep-lazy.c
>>>>  create mode 100644 elf/tst-ifunc-fault-mod.c
>>>>
>>>> diff --git a/elf/Makefile b/elf/Makefile
>>>> index 94c5b7e6ed8..6cfb1b5cf30 100644
>>>> --- a/elf/Makefile
>>>> +++ b/elf/Makefile
>>>> @@ -1396,6 +1396,13 @@ modules-names += \
>>>>    tst-ifunc-tls-write-lib \
>>>>    tst-tls-tdata-reloc-lib \
>>>>    # modules-names
>>>> +ifeq (yes,$(have-gcc-ifunc))
>>>> +tests += \
>>>> +  tst-ifunc-fault-dep-bindnow \
>>>> +  tst-ifunc-fault-dep-lazy \
>>>> +  # tests
>>>> +modules-names += tst-ifunc-fault-mod
>>>> +endif
>>>>  ifneq (no,$(have-test-mtls-descriptor))
>>>>  tests += tst-ifunc-tls-init-tlsdesc
>>>>  modules-names += tst-ifunc-tls-init-tlsdesc-lib
>>>> @@ -2545,6 +2552,27 @@ $(objpfx)tst-ifunc-fault-bindnow.out: $(objpfx)tst-ifunc-fault-bindnow \
>>>>     $(objpfx)ld.so
>>>>         $(tst-ifunc-fault-script)
>>>>
>>>> +LDFLAGS-tst-ifunc-fault-dep-lazy = -Wl,-z,lazy
>>>> +LDFLAGS-tst-ifunc-fault-dep-bindnow = -Wl,-z,now
>>>> +define tst-ifunc-fault-dep-script
>>>> +( $(test-wrapper) $(rtld-prefix) --verify $< \
>>>> +  && $(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 $(rtld-prefix) $< \
>>>> +  && $(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 LD_DEBUG=unused \
>>>> +                        $(rtld-prefix) $< \
>>>> +  && $(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 LD_WARN=yes LD_BIND_NOW=1 \
>>>> +                        $(rtld-prefix) $< \
>>>> +) > $@; $(evaluate-test)
>>>> +endef
>>>> +$(objpfx)tst-ifunc-fault-dep-lazy: $(objpfx)tst-ifunc-fault-mod.so
>>>> +$(objpfx)tst-ifunc-fault-dep-bindnow: $(objpfx)tst-ifunc-fault-mod.so
>>>> +$(objpfx)tst-ifunc-fault-dep-lazy.out: $(objpfx)tst-ifunc-fault-dep-lazy \
>>>> +   $(objpfx)tst-ifunc-fault-mod.so $(objpfx)ld.so
>>>> +       $(tst-ifunc-fault-dep-script)
>>>> +$(objpfx)tst-ifunc-fault-dep-bindnow.out: \
>>>> +   $(objpfx)tst-ifunc-fault-dep-bindnow \
>>>> +   $(objpfx)tst-ifunc-fault-mod.so $(objpfx)ld.so
>>>> +       $(tst-ifunc-fault-dep-script)
>>>> +
>>>>  LDFLAGS-tst-ifunc-plt-lib.so = -Wl,-z,lazy
>>>>
>>>>  tst-ifunc-plt-bindnow-ENV = LD_BIND_NOW=1
>>>> diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
>>>> index 8463e46147d..53260b57372 100644
>>>> --- a/elf/dl-reloc-static-pie.c
>>>> +++ b/elf/dl-reloc-static-pie.c
>>>> @@ -80,7 +80,7 @@ _dl_relocate_static_pie (void)
>>>>
>>>>    /* Relocate ourselves so we can do normal function calls and data access
>>>>       using the global offset table.  IRELATIVE entries are deferred.  */
>>>> -  ELF_DYNAMIC_RELOCATE_NOIFUNC (main_map, NULL, 0, 0);
>>>> +  ELF_DYNAMIC_RELOCATE_NOIFUNC (main_map, NULL, 0, 0, 0);
>>>>
>>>>    /* Initialize _r_debug_extended.  */
>>>>    struct r_debug *r = _dl_debug_initialize (0, LM_ID_BASE);
>>>> diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
>>>> index 15a6a4cffef..80cd7e25d16 100644
>>>> --- a/elf/dl-reloc.c
>>>> +++ b/elf/dl-reloc.c
>>>> @@ -278,7 +278,8 @@ _dl_relocate_object_no_relro (struct link_map *l, struct r_scope_elem *scope[],
>>>>         IFUNC resolvers.  Without this, a resolver would see the unrelocated
>>>>         initialiser bytes that were placed into the slot by the early
>>>>         _dl_allocate_tls_init.  */
>>>> -    ELF_DYNAMIC_RELOCATE_NOIFUNC (l, scope, lazy, consider_profiling);
>>>> +    ELF_DYNAMIC_RELOCATE_NOIFUNC (l, scope, lazy, consider_profiling,
>>>> +                                 skip_ifunc);
>>>
>>> ELF_DYNAMIC_RELOCATE_NOIFUNC name is confusing.
>>> If it is NOIFUNC, why isn't IFUNC skipped?
>>>
>>
>> There are
>>
>> /* Like ELF_DYNAMIC_RELOCATE but only processes the non-IRELATIVE pass.
>>    The IRELATIVE pass must be completed later via ELF_DYNAMIC_RELOCATE_IFUNC.
>>    Used by the static-pie startup so the TCB and stack-protector canary can
>>    be initialised between the two passes.  */
>> # define ELF_DYNAMIC_RELOCATE_NOIFUNC(map, scope, lazy, consider_profile)
>>
>> This change makes the comments incorrect.
> 
> Can ELF_DYNAMIC_RELOCATE_NOIFUNC/ELF_DYNAMIC_RELOCATE_IFUNC
> be renamed to ELF_DYNAMIC_RELOCATE_PASS:
> 
> # define ELF_DYNAMIC_RELOCATE_PASS(pass, map, scope, lazy, skip_ifunc)
I don't have a strong opinion, I will send a new version with the proposed
name.