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