To: musl@lists.openwall.com
Subject: [BUG] ldso applies load bias to SHN_ABS symbols during x86_64 R_X86_64_64 relocation

Hello,

I believe musl's dynamic linker applies the load bias to an x86-64
R_X86_64_64 relocation when the resolved symbol definition is SHN_ABS.

The expected result for R_X86_64_64 is S + A. For an SHN_ABS symbol, the ELF
gABI says the symbol value is absolute and is not affected by relocation. The
observed affected behavior is B + S + A, where B is the load base of the DSO
that defines the absolute symbol.

Minimal reproducer:

  See the attached repro/ directory.

  bash repro/repro.sh

The reproducer builds:

  * libabs_provider.so, which exports:
      abs_sym = 0x12345678
    as an SHN_ABS symbol.

  * main, a freestanding PIE containing one data slot:
      .quad abs_sym + 1

    The PIE exits 0 if the relocated slot equals 0x12345679, otherwise it exits
    42.

Observed locally:

  This reproduces with the system musl 1.2.4 loader from Ubuntu's musl 1.2.4-2
  package and with a local build of the official musl 1.2.6 release tarball.

    glibc loader: 0
    musl 1.2.4 loader: 42
    musl 1.2.6 loader: 42

    provider symbol:
      0000000012345678     8 OBJECT  GLOBAL DEFAULT  ABS abs_sym

    main relocation:
      R_X86_64_64 abs_sym + 1

Expected:

  The relocated slot should be 0x12345679, and the reproducer should exit 0.

Actual on the affected musl loader:

  The reproducer exits 42 when run through musl's loader. The same binary exits
  0 with glibc's loader.

Root-cause pointer:

  On x86-64, R_X86_64_64 uses the symbolic relocation path. In ldso/dynlink.c,
  the resolved symbol value appears to be computed as laddr(def.dso,
  def.sym->st_value) for all definitions. That is correct for section-relative
  symbol values, but not for SHN_ABS definitions, where st_value is already
  absolute.

Source pointer and possible minimal fix:

  In the official musl 1.2.6 release:

    arch/x86_64/reloc.h:3:
      #define REL_SYMBOLIC    R_X86_64_64

    ldso/dynlink.c:453:
      sym_val = def.sym ? (size_t)laddr(def.dso, def.sym->st_value) : 0;

    ldso/dynlink.c:467:
      case REL_SYMBOLIC:

    ldso/dynlink.c:470:
      *reloc_addr = sym_val + addend;

  The smallest relocation-only change matching the reproducer appears to be:

    sym_val = def.sym ? (def.sym->st_shndx == SHN_ABS ? def.sym->st_value : (size_t)laddr(def.dso, def.sym->st_value)) : 0;

  I am presenting this as a root-cause pointer rather than a fully audited
  patch. There is a similar-looking laddr(def.dso, def.sym->st_value) return in
  the dlsym path at ldso/dynlink.c:2289, but the attached reproducer only
  covers relocation processing.

Duplicate search:

  I searched the musl list archive for SHN_ABS/R_X86_64_64/load-bias reports and
  did not find an existing report for this specific case.

Environment:

  musl tested version:
    musl 1.2.6 release, built locally from:
      https://musl.libc.org/releases/musl-1.2.6.tar.gz
      sha256 d585fd3b613c66151fc3249e8ed44f77020cb5e6c1e635a616d3f9f82460512a
      configure command:
        ./configure --prefix=/tmp/verilink-musl-1.2.6.zy4nlJ/install
    system musl 1.2.4, Ubuntu package 1.2.4-2, also reproduces
  local loaders used:
    musl 1.2.6 build:
      /tmp/verilink-musl-1.2.6.zy4nlJ/musl-1.2.6/lib/libc.so
    system musl 1.2.4:
      /lib/ld-musl-x86_64.so.1 -> /lib/x86_64-linux-musl/libc.so
      sha256 6e8ff8ad02f4a3a0b70029577e2eb9df8f6526aea302a60a8d649874d6fa45ea
  binutils version used for preliminary reproducer:
    GNU ld 2.42, Ubuntu package 2.42-4ubuntu2.10
  host OS/kernel/architecture:
    Ubuntu 24.04.4 LTS
    Linux Hihi142-Linux 7.0.0-30-generic x86_64 GNU/Linux
  full local output:
    repro/build/report-system-musl-1.2.4.txt
    repro/build/report-upstream-musl-1.2.6.txt

I am happy to test a proposed patch or adjust the reproducer if this case is
outside musl's intended dynamic-linker scope.

If this message is delayed for moderation because I am not subscribed, please
keep me Cc'd on replies.

Thanks,
TODO
