https://sourceware.org/bugzilla/show_bug.cgi?id=34961
Bug ID: 34961
Summary: LoongArch TLS-LE relaxation can leave a stale base
when RELAX precedes LO12_R
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 17254
--> https://sourceware.org/bugzilla/attachment.cgi?id=17254&action=edit
repro
## Description
GNU ld partially applies a LoongArch TLS local-exec relaxation when the
`R_LARCH_RELAX` entry of the final same-address pair precedes
`R_LARCH_TLS_LE_LO12_R`. It deletes the preceding HI20 and ADD instructions,
but it does not rewrite the final `addi.d` to use `tp`. The linked function
therefore returns an address derived from the caller's incoming `a0` instead
of the thread pointer.
The two attached input objects differ only in the order of the last two
`.rela.text` entries:
```text
canonical: ... R_LARCH_TLS_LE_LO12_R@8, R_LARCH_RELAX@8
trigger: ... R_LARCH_RELAX@8, R_LARCH_TLS_LE_LO12_R@8
```
Both have the same code bytes, symbols, addends, section layout, and relocation
multiset. Each normal TLS-LE relocation is paired with one `R_LARCH_RELAX` at
the same offset. The LoongArch ELF ABI describes `R_LARCH_RELAX` as paired
with a normal relocation at the same address; it does not specify an ordering
between those two relocation records. The three `_R` relocations form the
relaxable TLS-LE sequence.
With current GNU ld, the canonical object becomes:
```text
addi.d $a0, $tp, 0
ret
```
The trigger becomes:
```text
addi.d $a0, $a0, 0
ret
```
The behavior appears to come from `loongarch_elf_relax_section` in
`bfd/elfnn-loongarch.c`. It considers each TLS-LE relocation independently
and invokes `loongarch_relax_tls_le` only when the *next* relocation-array
entry is `R_LARCH_RELAX` at the same offset. The relaxer deletes marked
`R_LARCH_TLS_LE_HI20_R` and `R_LARCH_TLS_LE_ADD_R` instructions, while the
marked `R_LARCH_TLS_LE_LO12_R` case performs the required base-register
rewrite to `tp`. If only the final pair is stored hint-first, the first two
transformations occur and the dependency-producing instructions disappear,
but the base-register rewrite is skipped.
GNU ld 2.46 reproduced this in both static and PIE links. I also fetched and
built official Binutils master commit
`f735688fcb997db4821ed6f9df40425b31b0cd0c` (GNU ld
2.47.50.20261105) with all targets enabled. Its `ld-new` had SHA-256
`d367606f7c0175cd360c74a8b2abb2dc829af4bd2fefdc52992c17f2ba4e64ed`
and reproduced the same result. On that build, the attached runtime observed
`tp=0x124020`. The canonical and `--no-relax` controls loaded through that
address for both inputs; the relaxed trigger loaded through `0x122000` and
`0x123000`.
The attached standalone reproducer also shows a bounded constant-time
consequence. It supplies two equal-valued candidate addresses in incoming
`a0`, performs the affected load, and then calls a separately compiled
PQClean ML-KEM-768 selector. Both inputs exit successfully and emit the same
32-byte output, with SHA-256
`630dcd2966c4336691125448bbb25b4ff412a49c732db2c8abc1b8581bd710dd`.
Only the trigger's effective load address differs. This demonstrates that the
partial relaxation can make a previously dead caller value control an
architectural memory address. It does not claim measured cache timing, key
recovery, or an attacker-controlled read.
Reproduction:
```sh
tar -xzf bfd-loongarch-tlsle-hint-order-secret-address-bugzilla.tar.gz
cd artifact
LD=/path/to/ld-new ./repro.sh
```
The script requires `qemu-loongarch64`,
`loongarch64-linux-gnu-objdump`, `nm`, Python 3, and `sha256sum`. If `LD` is
unset, it uses `loongarch64-linux-gnu-ld.bfd`. It verifies the frozen input
hashes, freshly links the trigger and two controls, executes both input values,
parses the register state at the observed load, and checks the disassembly and
equal output. It finishes with:
```text
PASS: only the relaxed noncanonical relocation order retains incoming a0
```
LoongArch ELF ABI:
https://github.com/loongson/la-abi-specs/blob/release/laelf.adoc
--
You are receiving this mail because:
You are on the CC list for the bug.