Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <CAN30aBH8QW4v7s6fh63YOprKBZrd30ErDQaV72jRvPu97mKY7A@mail.gmail.com>
Date: Fri, 12 Jun 2026 19:28:49 -0700
From: Fangrui Song <i@...kray.me>
To: musl@...ts.openwall.com
Subject: Feature request: Support multiple PT_GNU_RELRO in ldso

Multi-GOT executables are being explored for two main use cases: (1)
managing huge binaries, and (2) CHERI compartmentalization. Because
each GOT needs to be write-protected after relocation, the dynamic
linker needs to support multiple PT_GNU_RELRO segments.
https://discourse.llvm.org/t/rfc-forming-a-massive-binaries-working-group-in-lld/91031/5

FreeBSD already gained support in
https://cgit.freebsd.org/src/commit/?id=fda0403eb0839b29b0b271c69c5cb6bfc874a3b5

musl keeps a single PT_GNU_RELRO range, so an object with two
PT_GNU_RELRO headers would have only one of the two.

If musl implements multi-RELRO support, reclaim_gaps can be adjusted
to conservatively check the first RELRO range.

The following lit test will create a multi-RELRO executable for testing.


# RUN: rm -rf %t && split-file %s %t && cd %t
# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o
# RUN: clang -fuse-ld=lld -nostdlib -pie -Wl,-T,a.lds a.o -o out
# RUN: llvm-readelf -l out | FileCheck %s
# RUN: ./out | FileCheck %s --check-prefix=EXEC

#             Type      Offset   VirtAddr           PhysAddr
FileSiz  MemSiz   Flg Align
# CHECK:      INTERP    {{.*}}
                   R   0x1
# CHECK:      GNU_RELRO 0x001000 0x0000000000001000 0x0000000000001000
0x001000 0x001000 R   0x8
# CHECK-NEXT: GNU_RELRO 0x003000 0x0000000000003000 0x0000000000003000
0x001000 0x001000 R   0x1

# CHECK:      Section to Segment mapping:
# CHECK:      .data.rel.ro .dynamic .relro_pad1 {{$}}
# CHECK-NEXT: .jcr .relro_pad2 {{$}}

# EXEC: Hello from multi-RELRO

#--- a.lds
PHDRS {
  phdr   PT_PHDR PHDRS;
  interp PT_INTERP;
  load   PT_LOAD FILEHDR PHDRS;
  rw     PT_LOAD;
  dyn    PT_DYNAMIC;
  relro1 PT_GNU_RELRO FLAGS(0x4);
  relro2 PT_GNU_RELRO FLAGS(0x4);
}
SECTIONS {
  . = SIZEOF_HEADERS;
  .interp   : { *(.interp) }   :load :interp
  .dynsym   : { *(.dynsym) }   :load
  .gnu.hash : { *(.gnu.hash) } :load
  .dynstr   : { *(.dynstr) }   :load
  .rela.dyn : { *(.rela.dyn) } :load
  .text     : { *(.text) }     :load

  . = ALIGN(CONSTANT(MAXPAGESIZE));
  ## relro run 1, padded up to a full page so ld.so protects all of it
  .data.rel.ro : { *(.data.rel.ro) }                   :rw :relro1
  .dynamic     : { *(.dynamic) }                       :rw :relro1 :dyn
  .relro_pad1  : { . = ALIGN(CONSTANT(MAXPAGESIZE)); } :rw :relro1

  ## a full non-relro page separates the two relro segments
  .data : { *(.data); . += CONSTANT(MAXPAGESIZE); }    :rw
  . = ALIGN(CONSTANT(MAXPAGESIZE));

  ## relro run 2, padded up to a full page
  .jcr        : { *(.jcr) }                            :rw :relro2
  .relro_pad2 : { . = ALIGN(CONSTANT(MAXPAGESIZE)); }  :rw :relro2
}

#--- a.s
.section .interp,"a",@progbits
  .asciz "/lib64/ld-linux-x86-64.so.2"

.text
.global _start
_start:
  ## write(1, msg, msglen)
  mov $1, %rax
  mov $1, %rdi
  lea msg(%rip), %rsi
  mov $msglen, %edx
  syscall
  ## exit(0)
  mov $60, %rax
  xor %edi, %edi
  syscall

.section .data.rel.ro,"aw",@progbits
msg:
  .ascii "Hello from multi-RELRO\n"
  .equ msglen, . - msg

.section .jcr,"aw",@progbits
  .quad msg

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.