Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [day] [month] [year] [list]
Message-ID:
 <DS4PR01MB99445317F95516FC965800CDC3EA692@DS4PR01MB994453.prod.exchangelabs.com>
Date: Wed, 4 Nov 2026 03:31:35 +0000
From: "Puranam, Ananta Srikar" <srikar.puranam@....edu>
To: "musl@...ts.openwall.com" <musl@...ts.openwall.com>,
        "dalias@...c.org"
	<dalias@...c.org>
CC: "West, Emily" <emily.west1@....edu>, "Priya, Swarn" <swarn.priya@....edu>,
        "Gao, Peng" <penggao@...edu>,
        "Ammanaghatta Shivakumar, Basavesh"
	<basavesh.shivakumar@....edu>
Subject: ldso: TLS alignment above page size, initial-exec TLS error name, and
 malformed-ELF list

Hi Rich,

As discussed in the e_phentsize thread
(https://www.openwall.com/lists/musl/2026/11/03/5), here is everything
in one place. I checked the first two on master at 7813e911 on x86_64.

1. TLS alignment above the page size

A __thread variable aligned to 8 KiB or more, in a library or in the
program, is not placed at that alignment. In ldso/dynlink.c the static
TLS offset is chosen from the run-time address of the TLS image (line
1240 for the library, 1938 for the program) rather than from p_vaddr,
so it is only right when the module's base is a multiple of the TLS
alignment.

Test: the program and a DT_NEEDED library each have
  __thread char big[64] __attribute__((aligned(ALIGN)));
plus some initialized __thread variables, linked with GNU ld, gold,
LLD and mold.

- The library's block is misaligned by 4096 to 28672 bytes for
  ALIGN 8192 to 65536. The amount changes from run to run with the
  load address; with ASLR off it is always 4096 at 8192.
- With LLD and mold at ALIGN 32768 and 65536, the program's own
  initialized __thread variables read as 0, and so do the library's.
- glibc 2.43 places and initializes every one of these correctly.

I only tested the main thread.

2. Name in the initial-exec TLS error

The "initial-exec TLS resolves to dynamic definition" error in
do_relocs prints name, which is only set when sym_index is nonzero
(line 429). For the symbol-less TPOFF64 relocation a library gets for
its own static __thread variable, built with -ftls-model=initial-exec
and then dlopen'ed:

- master prints an empty name, or a stale one from an earlier
  relocation (reg_next_instance from another library in my test);
- 1.2.5 prints garbage bytes here, and segfaulted inside dlopen on
  Alpine 3.22.

The refusal itself is correct; only the name is wrong.

3. Malformed-ELF list, for later

These are all deliberately malformed files, and each one crashes or
misbehaves in dlopen. I have a reproducer for each if you ever want
it.

- PT_LOAD extent arithmetic not checked (p_offset/p_filesz/p_memsz):
  crash in map_library
- PT_LOAD p_vaddr + p_memsz overflow: SIGBUS while clearing BSS
- PT_LOAD p_vaddr + p_memsz overflow: SIGBUS while scanning PT_DYNAMIC
- PT_LOAD with p_memsz 0 covering relocation targets: write through
  an invalid address in do_relocs
- PT_TLS p_vaddr overflow: out-of-bounds read
- DT_RELA pointer far outside the image: read in do_relocs
- DT_RELR pointer far outside the image: read in do_relr_relocs
- dynamic symbol st_name far outside .dynstr: bad pointer passed to
  find_sym
- DT_GNU_HASH pointer far outside the image: read in
  gnu_lookup_filtered
- DT_VERSYM pointer far outside the image: read in gnu_lookup

The relocation table sizes that wrap around (DT_RELASZ, DT_RELRSZ)
are in my earlier email "ldso: relocation table sizes can wrap around
in do_relocs".

Thanks,
Srikar

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.