|
|
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.