https://sourceware.org/bugzilla/show_bug.cgi?id=34958
Bug ID: 34958
Summary: GNU ld --dynamic-list misses an exact .symver default
symbol
Product: binutils
Version: 2.48 (HEAD)
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: ld
Assignee: unassigned at sourceware dot org
Reporter: basavesh.shivakumar at wsu dot edu
Target Milestone: ---
Created attachment 17251
--> https://sourceware.org/bugzilla/attachment.cgi?id=17251&action=edit
repro
## Description
GNU ld does not apply an exact `--dynamic-list` entry to a symbol defined as a
default-version `.symver` alias. It consequently binds a reference inside the
shared object to the local definition even though the dynamic list asks for
that symbol to remain preemptible.
The attached standalone x86-64 reproducer defines `prov` as follows:
```c
__asm__(".symver prov_impl, prov@@V1");
```
The symbol is exported as the default version in `V1`, the shared object calls
`prov`, and the exact dynamic list is:
```text
{
prov;
};
```
With GNU ld 2.46, the resulting shared object has no dynamic relocation for
the internal call to `prov`. An `LD_PRELOAD` definition of `prov` is therefore
not called.
Expected behavior: the exact entry `prov` should match the exported default
symbol `prov@@V1` and keep the shared object's reference preemptible. The
linked object should retain an `R_X86_64_JUMP_SLOT` relocation for `prov@@V1`,
allowing the preload definition to interpose.
Three GNU ld controls behave as expected:
- omitting `--dynamic-list`;
- using the wildcard entry `prov*`; and
- using a plain `prov` definition whose version is assigned by the version
script.
Each control retains `R_X86_64_JUMP_SLOT prov@@V1` and calls the preload.
Gold 1.16, LLD 21.1.8, and mold 2.40.4 also retain the dynamic relocation for
the exact entry.
I reproduced the failure with GNU ld 2.46 and Binutils master commit
`b89169e9d45` (GNU ld snapshot 2.47.50.20261020). An earlier master build at
`692a398424b5468c17843b68faefa26169d961a1` reproduced it in an ASan and UBSan
build without a sanitizer diagnostic. The simpler provider-selection test also
reproduced on x86-64 and AArch64 and with glibc and musl.
The likely cause is `bfd_elf_link_mark_dynamic_symbol` in `bfd/elflink.c`. The
dynamic-list matcher is called with `h->root.root.string`, whose value is
`prov@@V1` for this definition. The exact pattern `prov` does not match that
internal spelling, while `prov*` can span the `@@V1` suffix. Current Binutils
master `f735688fcb997db4821ed6f9df40425b31b0cd0c` still contains this matching
path; I reviewed that revision's source but did not rebuild that exact commit.
The archive also includes a bounded constant-time consequence while preserving
the public result. The local provider returns 42 through one of two addresses
selected by an input bit; the preload provider always reads one address and
also returns 42. In the affected exact-list link, GNU ld selects the local
provider and the two inputs have different instruction and exact-address
traces. All three GNU ld controls select the preload and have equal traces.
This is an architectural trace observation, not a timing measurement or a
claim of key recovery.
Reproduction:
```sh
tar -xzf bfd-dynamic-list-symver-ct-provider-bypass-bugzilla.tar.gz
cd artifact
./repro.sh
```
The script requires an x86-64 Linux system with a C compiler, GNU ld, GNU
`nm`, GNU `readelf`, Valgrind, and Python 3. It compiles the inputs, performs
the affected link and all three controls, checks relocations and provider
selection, and compares the paired traces. It finishes with:
```text
PASS: exact { prov; } loses preemption; all GNU ld controls pass
```
--
You are receiving this mail because:
You are on the CC list for the bug.