Ahem. What I mean is that with some patching, RELRO can be enabled by default on several archs. The first chunk below enables it on x86, arm, and sparc64. I'm 95% positive that it would Just Work on alpha and sh (TEXT_PLT archs like amd64, arm, and i386) and sparc (looks like sparc64, shock!), but this is untested there.
So what is RELRO anyway? RELRO is basically a hook for marking sections of memory of an object as being "Read-Only after RELocation". We've been doing a version of this for years on OpenBSD via the __{got,plt}_{start,end} symbols: ld.so would mprotect the regions between those symbols after relocation, and then when relocating lazy binding it would mark the necessary bits temporarily writable. Last year we added kbind() so that lazy relocations could be done securely and efficiently through the kernel. Since then, we've practically eliminated the need for the __plt_{start,end} handling by treating all RWX sections as RW-until- -relocation-and-RX-after-relocation. While our design works, the GNU_RELRO design by the GNU people offers some advantages: - no need for symbol lookup. The start address and length are coded directly into the section instead of needing two symbol lookups - covers even more than we did. Theo and Dale had to do serious hacking to get our support to cover not just the GOT but also the .ctors and .dtors segments. Well, the GNU people hacked more and managed to make the .eh_frame, .tdata, .tbss, dynamic, .{init,preinit,fini}_array, and .jcr segments also RELRO. - fewer mappings. There are two areas, both of which need to start out read-write but the first needs to switch to read-only. The GNU people realized that if you align the data correctly in the file, you can do *one* mmap() that covers both but place the division between them on a page boundary so it can be the start of a later mprotect(), thus saving the cost of a separate mmap() call. So what's going on in this diff? The armelf_obsd.sh chunk makes that arch order things like the others, setting things up before sourcing the common elf_obsd bits that depend on them, with 4KB as the normal pagesize. If there's nothing special about 16KB in our uvm/pmap layer then lowering MAXPAGESIZE may save space. While I don't have RELRO 100% working on powerpc (damn bss-plt compat) or mips64 yet, these are a start...and I've been testing with them so long I'm not sure things work without them. I really don't know what *PAGESIZE values are appropriate for mips BE & LE: loongson has 16KB pages, are there mips64le with smaller? As for elf.sc: "Cthulhu touches you with his tentacle: you lose 5 sanity" The diff here does this: - move some not-really-executable bits from the start of the inital RX section to start of the first RO section - move the PLT in the "executable, but initially mutable and not required to be before the GOT" case from immediately before the .data segment to between the RO and RW sections. This is used, for example, on sparc64 where the sections end up in the order RX .init .text .fini R .interp .note* .hash .dyn* .rel* .rodata .eh_frame RWX .plt RW .openbsd.randomdata .jcr .dynamic .got .cdtors .data .bss - move up the __got_start symbols to the start of the RW section - *don't* pad before the PLT when it's a DATA_PLT in the relro area - when doing RELRO, put the .ctor and .dtor sections right after the .got and *right before* the RELRO RO-vs-RW boundary Have I lost everyone? Beuhler? Beuhler? oks? Philip Guenther Index: gnu/usr.bin/binutils-2.17/ld/ldmain.c =================================================================== RCS file: /cvs/src/gnu/usr.bin/binutils-2.17/ld/ldmain.c,v retrieving revision 1.9 diff -u -p -r1.9 ldmain.c --- gnu/usr.bin/binutils-2.17/ld/ldmain.c 21 Jun 2016 02:55:57 -0000 1.9 +++ gnu/usr.bin/binutils-2.17/ld/ldmain.c 7 Aug 2016 03:18:37 -0000 @@ -299,7 +299,12 @@ main (int argc, char **argv) link_info.new_dtags = FALSE; link_info.combreloc = TRUE; link_info.eh_frame_hdr = FALSE; +#if defined(__amd64__) || defined(__arm__) || defined(__i386__) || \ + defined(__sparc64__) + link_info.relro = TRUE; +#else link_info.relro = FALSE; +#endif link_info.strip_discarded = TRUE; link_info.strip = strip_none; link_info.discard = discard_sec_merge; Index: gnu/usr.bin/binutils-2.17/ld/emulparams/armelf_obsd.sh =================================================================== RCS file: /cvs/src/gnu/usr.bin/binutils-2.17/ld/emulparams/armelf_obsd.sh,v retrieving revision 1.1 diff -u -p -r1.1 armelf_obsd.sh --- gnu/usr.bin/binutils-2.17/ld/emulparams/armelf_obsd.sh 24 Apr 2011 20:19:25 -0000 1.1 +++ gnu/usr.bin/binutils-2.17/ld/emulparams/armelf_obsd.sh 7 Aug 2016 03:18:37 -0000 @@ -1,8 +1,10 @@ . ${srcdir}/emulparams/armelf.sh -. ${srcdir}/emulparams/elf_obsd.sh MAXPAGESIZE=0x8000 +COMMONPAGESIZE=0x1000 TEXT_START_ADDR=0x00008000 TARGET2_TYPE=got-rel unset EMBEDDED + +. ${srcdir}/emulparams/elf_obsd.sh Index: gnu/usr.bin/binutils-2.17/ld/emulparams/elf32ppc_obsd.sh =================================================================== RCS file: /cvs/src/gnu/usr.bin/binutils-2.17/ld/emulparams/elf32ppc_obsd.sh,v retrieving revision 1.3 diff -u -p -r1.3 elf32ppc_obsd.sh --- gnu/usr.bin/binutils-2.17/ld/emulparams/elf32ppc_obsd.sh 23 Aug 2015 15:19:32 -0000 1.3 +++ gnu/usr.bin/binutils-2.17/ld/emulparams/elf32ppc_obsd.sh 7 Aug 2016 03:18:37 -0000 @@ -1,7 +1,2 @@ -. ${srcdir}/emulparams/elf32ppccommon.sh -# We deliberately keep the traditional OpenBSD W^X layout for both the -# old BSS-PLT and the new Secure-PLT ABI. -BSS_PLT= -OTHER_TEXT_SECTIONS="*(.glink)" -EXTRA_EM_FILE=ppc32elf +. ${srcdir}/emulparams/elf32ppc.sh . ${srcdir}/emulparams/elf_obsd.sh Index: gnu/usr.bin/binutils-2.17/ld/emulparams/elf64btsmip_obsd.sh =================================================================== RCS file: /cvs/src/gnu/usr.bin/binutils-2.17/ld/emulparams/elf64btsmip_obsd.sh,v retrieving revision 1.2 diff -u -p -r1.2 elf64btsmip_obsd.sh --- gnu/usr.bin/binutils-2.17/ld/emulparams/elf64btsmip_obsd.sh 16 Jun 2015 20:25:35 -0000 1.2 +++ gnu/usr.bin/binutils-2.17/ld/emulparams/elf64btsmip_obsd.sh 7 Aug 2016 03:18:37 -0000 @@ -1,5 +1,6 @@ . ${srcdir}/emulparams/elf64btsmip.sh MAXPAGESIZE=0x10000 +COMMONPAGESIZE=0x1000 TEXT_START_ADDR="0x10000000" . ${srcdir}/emulparams/elf_obsd.sh # XXX causes GOT oflows Index: gnu/usr.bin/binutils-2.17/ld/emulparams/elf64ltsmip_obsd.sh =================================================================== RCS file: /cvs/src/gnu/usr.bin/binutils-2.17/ld/emulparams/elf64ltsmip_obsd.sh,v retrieving revision 1.2 diff -u -p -r1.2 elf64ltsmip_obsd.sh --- gnu/usr.bin/binutils-2.17/ld/emulparams/elf64ltsmip_obsd.sh 16 Jun 2015 20:25:35 -0000 1.2 +++ gnu/usr.bin/binutils-2.17/ld/emulparams/elf64ltsmip_obsd.sh 7 Aug 2016 03:18:37 -0000 @@ -1,5 +1,6 @@ . ${srcdir}/emulparams/elf64ltsmip.sh MAXPAGESIZE=0x10000 +COMMONPAGESIZE=0x1000 TEXT_START_ADDR="0x10000000" . ${srcdir}/emulparams/elf_obsd.sh # XXX causes GOT oflows Index: gnu/usr.bin/binutils-2.17/ld/scripttempl/elf.sc =================================================================== RCS file: /cvs/src/gnu/usr.bin/binutils-2.17/ld/scripttempl/elf.sc,v retrieving revision 1.8 diff -u -p -r1.8 elf.sc --- gnu/usr.bin/binutils-2.17/ld/scripttempl/elf.sc 9 Aug 2014 04:49:47 -0000 1.8 +++ gnu/usr.bin/binutils-2.17/ld/scripttempl/elf.sc 7 Aug 2016 03:18:38 -0000 @@ -267,6 +267,35 @@ SECTIONS ${CREATE_SHLIB-${CREATE_PIE-${RELOCATING+PROVIDE (__executable_start = ${TEXT_START_ADDR}); . = ${TEXT_BASE_ADDRESS};}}} ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_TEXT_START_ADDR:-0} + SIZEOF_HEADERS;}} ${CREATE_PIE+${RELOCATING+. = ${SHLIB_TEXT_START_ADDR:-0} + SIZEOF_HEADERS;}} + .init ${RELOCATING-0} : + { + ${RELOCATING+${INIT_START}} + KEEP (*(.init)) + ${RELOCATING+${INIT_END}} + } =${NOP-0} + + ${TEXT_PLT+${PLT}} + ${TINY_READONLY_SECTION} + .text ${RELOCATING-0} : + { + ${RELOCATING+${TEXT_START_SYMBOLS}} + *(.text .stub${RELOCATING+ .text.* .gnu.linkonce.t.*}) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + ${RELOCATING+${OTHER_TEXT_SECTIONS}} + } =${NOP-0} + .fini ${RELOCATING-0} : + { + ${RELOCATING+${FINI_START}} + KEEP (*(.fini)) + ${RELOCATING+${FINI_END}} + } =${NOP-0} + ${RELOCATING+PROVIDE (__${ETEXT_NAME} = .);} + ${RELOCATING+PROVIDE (_${ETEXT_NAME} = .);} + ${RELOCATING+PROVIDE (${ETEXT_NAME} = .);} + + ${PAD_RO+${PAD_RO0}} ${CREATE_SHLIB-${INTERP}} ${INITIAL_READONLY_SECTIONS} ${TEXT_DYNAMIC+${DYNAMIC}} @@ -337,34 +366,6 @@ cat <<EOF .rela.plt ${RELOCATING-0} : { *(.rela.plt) } ${OTHER_PLT_RELOC_SECTIONS} - .init ${RELOCATING-0} : - { - ${RELOCATING+${INIT_START}} - KEEP (*(.init)) - ${RELOCATING+${INIT_END}} - } =${NOP-0} - - ${TEXT_PLT+${PLT}} - ${TINY_READONLY_SECTION} - .text ${RELOCATING-0} : - { - ${RELOCATING+${TEXT_START_SYMBOLS}} - *(.text .stub${RELOCATING+ .text.* .gnu.linkonce.t.*}) - KEEP (*(.text.*personality*)) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - ${RELOCATING+${OTHER_TEXT_SECTIONS}} - } =${NOP-0} - .fini ${RELOCATING-0} : - { - ${RELOCATING+${FINI_START}} - KEEP (*(.fini)) - ${RELOCATING+${FINI_END}} - } =${NOP-0} - ${RELOCATING+PROVIDE (__${ETEXT_NAME} = .);} - ${RELOCATING+PROVIDE (_${ETEXT_NAME} = .);} - ${RELOCATING+PROVIDE (${ETEXT_NAME} = .);} - ${PAD_RO+${PAD_RO0}} ${WRITABLE_RODATA-${RODATA}} .rodata1 ${RELOCATING-0} : { *(.rodata1) } ${CREATE_SHLIB-${SDATA2}} @@ -374,11 +375,15 @@ cat <<EOF .eh_frame ${RELOCATING-0} : ONLY_IF_RO { KEEP (*(.eh_frame)) } .gcc_except_table ${RELOCATING-0} : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + ${DATA_NONEXEC_PLT-${DATA_PLT+${PLT_BEFORE_GOT-${PAD_PLT+${PAD_PLT0}}}}} + ${DATA_NONEXEC_PLT-${DATA_PLT+${PLT_BEFORE_GOT-${PLT}}}} + /* Adjust the address for the data segment. We want to adjust up to the same address within the page on the next page up. */ ${CREATE_SHLIB-${CREATE_PIE-${RELOCATING+. = ${DATA_ADDR-${DATA_SEGMENT_ALIGN}};}}} ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_DATA_ADDR-${DATA_SEGMENT_ALIGN}};}} ${CREATE_PIE+${RELOCATING+. = ${SHLIB_DATA_ADDR-${DATA_SEGMENT_ALIGN}};}} + ${DATA_GOT+${RELRO_NOW+${PAD_GOT+${RELOCATING+PROVIDE_HIDDEN(__got_start = .);}}}} /* Exception handling */ .eh_frame ${RELOCATING-0} : ONLY_IF_RW { KEEP (*(.eh_frame)) } @@ -419,11 +424,13 @@ cat <<EOF ${RELOCATING+${DATARELRO}} ${OTHER_RELRO_SECTIONS} ${TEXT_DYNAMIC-${DYNAMIC}} - ${DATA_GOT+${PAD_GOT+${PAD_GOT0}}} + ${DATA_GOT+${RELRO_NOW-${PAD_GOT+${PAD_GOT0}}}} ${DATA_GOT+${DATA_NONEXEC_PLT+${PLT}}} ${DATA_GOT+${RELRO_NOW+${GOT}}} ${DATA_GOT+${RELRO_NOW+${GOTPLT}}} - ${DATA_GOT+${RELRO_NOW+${PAD_GOT+${PAD_GOT1}}}} + ${DATA_GOT+${RELRO_NOW+${PAD_CDTOR+${RELOCATING+${CTOR}}}}} + ${DATA_GOT+${RELRO_NOW+${PAD_CDTOR+${RELOCATING+${DTOR}}}}} + ${DATA_GOT+${RELRO_NOW+${PAD_GOT+${RELOCATING+PROVIDE_HIDDEN(__got_end = .);}}}} ${DATA_GOT+${RELRO_NOW-${SEPARATE_GOTPLT+${GOT}}}} /* If PAD_CDTOR, and separate .got and .got.plt sections, CTOR and DTOR are relocated here to receive the same mprotect protection as .got */ @@ -437,10 +444,6 @@ cat <<EOF ${DATA_GOT+${RELRO_NOW-${SEPARATE_GOTPLT-${PAD_GOT+${PAD_GOT1}}}}} ${DATA_GOT+${RELRO_NOW-${GOTPLT}}} - ${DATA_NONEXEC_PLT-${DATA_PLT+${PLT_BEFORE_GOT-${PAD_PLT+${PAD_PLT0}}}}} - ${DATA_NONEXEC_PLT-${DATA_PLT+${PLT_BEFORE_GOT-${PLT}}}} - ${DATA_NONEXEC_PLT-${DATA_PLT+${PLT_BEFORE_GOT-${PAD_PLT+${PAD_PLT1}}}}} - .data ${RELOCATING-0} : { ${RELOCATING+${DATA_START_SYMBOLS}} @@ -462,8 +465,6 @@ cat <<EOF ${SDATA_GOT+${RELOCATING+${OTHER_GOT_SYMBOLS}}} ${SDATA_GOT+${GOT}} - ${DATA_GOT+${RELRO_NOW+${PAD_CDTOR+${RELOCATING+${CTOR}}}}} - ${DATA_GOT+${RELRO_NOW+${PAD_CDTOR+${RELOCATING+${DTOR}}}}} ${DATA_GOT-${PAD_CDTOR+${RELOCATING+${CTOR}}}} ${DATA_GOT-${PAD_CDTOR+${RELOCATING+${DTOR}}}}