diff options
author | Philip Guenther <guenther@cvs.openbsd.org> | 2019-05-10 13:29:22 +0000 |
---|---|---|
committer | Philip Guenther <guenther@cvs.openbsd.org> | 2019-05-10 13:29:22 +0000 |
commit | 7a997fa007d2414371c7b9fa2f4e83a0c3d406c2 (patch) | |
tree | ff8056bf55e605b407ec688972a67a4ab35dcd2b | |
parent | f16e61e66b2b5ec79eca82af98886596c97a38bb (diff) |
ld.so boot cleanup support:
- put functions and data which are only used before calling the executable's
start function into their own page-aligned segments for unmapping
(only done on amd64, arm64, armv7, powerpc, and sparc64 so far)
- pass .init_array and .preinit_array functions an addition argument which
is a callback to get a structure which includes a function that frees
the boot text and data
- sometimes delay doing RELRO processing: for a shared-object marked
DF_1_INITFIRST do it after the object's .init_array, for the executable
do it after the .preinit_array
- improve test-ld.so to link against libpthread and trigger its initialization
late
libc changes to use this will come later
ok kettenis@
-rw-r--r-- | etc/rc | 8 | ||||
-rw-r--r-- | include/tib.h | 24 | ||||
-rw-r--r-- | lib/csu/boot.h | 14 | ||||
-rw-r--r-- | lib/csu/crt0.c | 6 | ||||
-rw-r--r-- | lib/csu/extern.h | 4 | ||||
-rw-r--r-- | libexec/ld.so/Makefile | 15 | ||||
-rw-r--r-- | libexec/ld.so/aarch64/Makefile.inc | 3 | ||||
-rw-r--r-- | libexec/ld.so/aarch64/ld.script | 69 | ||||
-rw-r--r-- | libexec/ld.so/aarch64/ldasm.S | 11 | ||||
-rw-r--r-- | libexec/ld.so/amd64/Makefile.inc | 3 | ||||
-rw-r--r-- | libexec/ld.so/amd64/ld.script | 69 | ||||
-rw-r--r-- | libexec/ld.so/amd64/ldasm.S | 11 | ||||
-rw-r--r-- | libexec/ld.so/arm/Makefile.inc | 3 | ||||
-rw-r--r-- | libexec/ld.so/arm/ld.script | 70 | ||||
-rw-r--r-- | libexec/ld.so/arm/ldasm.S | 10 | ||||
-rw-r--r-- | libexec/ld.so/boot.c | 4 | ||||
-rw-r--r-- | libexec/ld.so/loader.c | 109 | ||||
-rw-r--r-- | libexec/ld.so/powerpc/Makefile.inc | 3 | ||||
-rw-r--r-- | libexec/ld.so/powerpc/ld.script | 70 | ||||
-rw-r--r-- | libexec/ld.so/powerpc/ldasm.S | 10 | ||||
-rw-r--r-- | libexec/ld.so/resolve.h | 38 | ||||
-rw-r--r-- | libexec/ld.so/sparc64/Makefile.inc | 3 | ||||
-rw-r--r-- | libexec/ld.so/sparc64/ld.script | 69 | ||||
-rw-r--r-- | libexec/ld.so/sparc64/ldasm.S | 10 | ||||
-rw-r--r-- | libexec/ld.so/util.h | 14 |
25 files changed, 572 insertions, 78 deletions
@@ -1,4 +1,4 @@ -# $OpenBSD: rc,v 1.536 2019/04/01 11:39:46 tedu Exp $ +# $OpenBSD: rc,v 1.537 2019/05/10 13:29:21 guenther Exp $ # System startup script run by init on autoboot or after single-user. # Output and error are redirected to console by init, and the console is the @@ -210,9 +210,11 @@ reorder_libs() { cd $_tmpdir ar x $_liba if [[ $_lib == ld.so ]]; then - ld -g -x -e _dl_start \ + args="-g -x -e _dl_start \ --version-script=Symbols.map --shared -Bsymbolic \ - --no-undefined -o ld.so.test $(ls *.o | sort -R) + --no-undefined" + [[ -f ld.script ]] && args="$args -T ld.script" + ld $args -o ld.so.test $(ls *.o | sort -R) chmod u+x test-ld.so [[ $(./test-ld.so ok) == './test-ld.so: ok!' ]] $_install /usr/libexec/ld.so /usr/libexec/ld.so.save diff --git a/include/tib.h b/include/tib.h index 1c610222df6..8d9216f19dc 100644 --- a/include/tib.h +++ b/include/tib.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tib.h,v 1.6 2017/11/28 18:57:02 kettenis Exp $ */ +/* $OpenBSD: tib.h,v 1.7 2019/05/10 13:29:21 guenther Exp $ */ /* * Copyright (c) 2011,2014 Philip Guenther <guenther@openbsd.org> * @@ -225,6 +225,28 @@ struct tib { __BEGIN_DECLS +struct dl_info; +struct dl_phdr_info; +struct dl_cb_0 { + void *(*dl_allocate_tib)(size_t); + void (*dl_free_tib)(void *, size_t); + void (*dl_clean_boot)(void); + void *(*dlopen)(const char *, int); + int (*dlclose)(void *); + void *(*dlsym)(void *, const char *); + int (*dladdr)(const void *, struct dl_info *); + int (*dlctl)(void *, int, void *); + char *(*dlerror)(void); + int (*dl_iterate_phdr)(int (*)(struct dl_phdr_info *, + size_t, void *), void *); +}; + +#define DL_CB_CUR 0 +typedef struct dl_cb_0 dl_cb; + +/* type of function passed to init functions that returns a dl_cb */ +typedef const void *dl_cb_cb(int _version); + void *_dl_allocate_tib(size_t _extra) __dso_public; void _dl_free_tib(void *_tib, size_t _extra) __dso_public; diff --git a/lib/csu/boot.h b/lib/csu/boot.h index c899af9303b..6ec5256bb06 100644 --- a/lib/csu/boot.h +++ b/lib/csu/boot.h @@ -1,4 +1,4 @@ -/* $OpenBSD: boot.h,v 1.29 2018/11/22 21:37:29 guenther Exp $ */ +/* $OpenBSD: boot.h,v 1.30 2019/05/10 13:29:21 guenther Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -81,6 +81,14 @@ struct boot_dyn { #endif }; +static void *relro_addr; +static size_t relro_size; +#define RCRT0_RELRO() \ + do { \ + if (relro_addr != NULL && relro_size != 0) \ + mprotect(relro_addr, relro_size, PROT_READ); \ + } while (0) + /* * Local decls. */ @@ -220,8 +228,8 @@ _dl_boot_bind(const long sp, long *dl_data, Elf_Dyn *dynamicp) break; #endif case PT_GNU_RELRO: - mprotect((void *)(phdp->p_vaddr + loff), phdp->p_memsz, - PROT_READ); + relro_addr = (void *)(phdp->p_vaddr + loff); + relro_size = phdp->p_memsz; /* * GNU_RELRO (a) covers the GOT, and (b) comes after * all LOAD sections, so if we found it then we're done diff --git a/lib/csu/crt0.c b/lib/csu/crt0.c index ac2966b5490..2c113e73428 100644 --- a/lib/csu/crt0.c +++ b/lib/csu/crt0.c @@ -1,4 +1,4 @@ -/* $OpenBSD: crt0.c,v 1.13 2019/05/08 20:27:29 guenther Exp $ */ +/* $OpenBSD: crt0.c,v 1.14 2019/05/10 13:29:21 guenther Exp $ */ /* * Copyright (c) 1995 Christopher G. Demetriou @@ -49,6 +49,9 @@ static void ___start(MD_START_ARGS) __used; #ifndef MD_EPROL_LABEL #define MD_EPROL_LABEL __asm(" .text\n_eprol:") #endif +#ifndef RCRT0_RELRO +#define RCRT0_RELRO() do {} while (0) +#endif char ***_csu_finish(char **_argv, char **_envp, void (*_cleanup)(void)); @@ -89,6 +92,7 @@ ___start(MD_START_ARGS) size = __preinit_array_end - __preinit_array_start; for (i = 0; i < size; i++) __preinit_array_start[i](argc, argv, envp, NULL); + RCRT0_RELRO(); size = __init_array_end - __init_array_start; for (i = 0; i < size; i++) __init_array_start[i](argc, argv, envp, NULL); diff --git a/lib/csu/extern.h b/lib/csu/extern.h index 5cc17413c8a..92dc12a0437 100644 --- a/lib/csu/extern.h +++ b/lib/csu/extern.h @@ -17,8 +17,8 @@ void __init(void) __dso_hidden; int main(int argc, char *argv[], char *envp[]); -struct dl_cb; -typedef void (*initarray_f)(int, char **, char **, const struct dl_cb *); +typedef const void *dl_cb_cb(int); +typedef void (*initarray_f)(int, char **, char **, dl_cb_cb *); typedef void (*init_f)(void); /* diff --git a/libexec/ld.so/Makefile b/libexec/ld.so/Makefile index ea50d59ae6f..da14f65f531 100644 --- a/libexec/ld.so/Makefile +++ b/libexec/ld.so/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.73 2018/08/29 15:56:46 robert Exp $ +# $OpenBSD: Makefile,v 1.74 2019/05/10 13:29:21 guenther Exp $ SUBDIR=ldconfig ldd MAN= ld.so.1 @@ -43,6 +43,11 @@ SRCS+= library.c .include "${.CURDIR}/${MACHINE_CPU}/Makefile.inc" .PATH: ${.CURDIR}/${MACHINE_CPU} +.ifdef LD_SCRIPT + ELF_LDFLAGS+=-T ${LD_SCRIPT} + CFLAGS += -DDO_CLEAN_BOOT +.endif + DEBUG?= -g CFLAGS += -fno-builtin CFLAGS += -Wall -Werror @@ -60,10 +65,10 @@ candidate= $(PROG).test CLEANFILES+= ${candidate} $(test_prog): - printf '#include <stdio.h>\nint main(int argc, char **argv){ printf("%%s: ", argv[0]); printf("%%s!\\n", argv[1] ? argv[1] : "foo"); }\n' | \ - $(CC) -P -x c - -Wl,-dynamic-linker,./$(candidate) -o $@ + printf '#include <stdio.h>\n#include <pthread.h>\nint main(int argc, char **argv){ pthread_attr_t attr; printf("%%s: ", argv[0]); pthread_attr_init(&attr); printf("%%s!\\n", argv[1] ? argv[1] : "foo"); }\n' | \ + $(CC) -P -x c - -Wl,-dynamic-linker,./$(candidate) -o $@ -lpthread -$(PROG): $(test_prog) ${VERSION_SCRIPT} $(OBJS) +$(PROG): $(test_prog) ${VERSION_SCRIPT} $(OBJS) ${LD_SCRIPT} .if defined(SYSPATCH_PATH) $(LD) ${DEBUG} -e _dl_start $(ELF_LDFLAGS) -o $(candidate) \ `readelf -Ws ${SYSPATCH_PATH}/usr/libexec/${.TARGET} | \ @@ -88,7 +93,7 @@ CLEANFILES+= ld.so.a all: ld.so.a -ld.so.a: ${OBJS} ${.CURDIR}/Symbols.map ${test_prog} +ld.so.a: ${OBJS} ${.CURDIR}/Symbols.map ${test_prog} ${LD_SCRIPT} ar cqD $@ $? afterinstall: ld.so.a diff --git a/libexec/ld.so/aarch64/Makefile.inc b/libexec/ld.so/aarch64/Makefile.inc index f8922395ef7..4d952565dc1 100644 --- a/libexec/ld.so/aarch64/Makefile.inc +++ b/libexec/ld.so/aarch64/Makefile.inc @@ -1,6 +1,7 @@ -# $OpenBSD: Makefile.inc,v 1.3 2017/08/26 16:26:17 kettenis Exp $ +# $OpenBSD: Makefile.inc,v 1.4 2019/05/10 13:29:21 guenther Exp $ CFLAGS += -fpic CFLAGS += -march=armv8-a+nofp+nosimd # this is -msoft-float AFLAGS += -D_STANDALONE CPPFLAGS += -I${.CURDIR}/../../lib/libc/arch/aarch64 +LD_SCRIPT = ${.CURDIR}/${MACHINE_CPU}/ld.script diff --git a/libexec/ld.so/aarch64/ld.script b/libexec/ld.so/aarch64/ld.script new file mode 100644 index 00000000000..d0231259a0b --- /dev/null +++ b/libexec/ld.so/aarch64/ld.script @@ -0,0 +1,69 @@ +PHDRS +{ + rodata PT_LOAD FILEHDR PHDRS FLAGS (4); + text PT_LOAD; + data PT_LOAD; + random PT_OPENBSD_RANDOMIZE; + relro PT_GNU_RELRO; + dynamic PT_DYNAMIC; + note PT_NOTE; +} + +SECTIONS +{ + /* RODATA */ + . = 0 + SIZEOF_HEADERS; + .dynsym : { *(.dynsym) } :rodata + .gnu.hash : { *(.gnu.hash) } :rodata + .dynstr : { *(.dynstr) } :rodata + .rodata : { *(.rodata .rodata.*) } :rodata + .eh_frame : { *(.eh_frame) } :rodata + + /* TEXT */ + . = ALIGN(0x10000); + .text : { *(.text .text.*) } :text + . = ALIGN(0x1000); + .boot.text : + { + boot_text_start = .; + *(.boot.text) + boot_text_end = .; + } :text + + /* RELRO DATA */ + . = DATA_SEGMENT_ALIGN (0x10000, 0x1000); + .openbsd.randomdata : + { + *(.openbsd.randomdata .openbsd.randomdata.*) + } :data :relro :random + .data.rel.ro : { *(.data.rel.ro.local*) *(.data.rel.ro*) } :data :relro + .dynamic : { *(.dynamic) } :data :relro :dynamic + .got : { *(.got.plt) *(.got) } :data :relro + . = DATA_SEGMENT_RELRO_END (0, .); + + /* BOOTDATA */ + . = ALIGN(0x1000); + boot_data_start = .; + .rela.dyn : + { + *(.rela.text .rela.text.*) + *(.rela.rodata .rela.rodata.*) + *(.rela.data .rela.data.*) + *(.rela.got) + *(.rela.bss .rela.bss.*) + } :data +/* XXX .rela.plt is unused but cannot delete: ld.bfd zeros DT_RELASZ then! */ + .rela.plt : { *(.rela.plt) } :data + .hash : { *(.hash) } :data + .note : { *(.note.openbsd.*) } :data :note + .boot.data : { *(.boot.data .boot.data.*) } :data + boot_data_end = .; + + /* DATA */ + . = ALIGN(0x1000); + .data : { *(.data .data.*) } :data + .bss : { *(.dynbss) *(.bss .bss.*) *(COMMON) } :data + . = DATA_SEGMENT_END (.); + + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/libexec/ld.so/aarch64/ldasm.S b/libexec/ld.so/aarch64/ldasm.S index 64c594e291c..9da1c9f20f3 100644 --- a/libexec/ld.so/aarch64/ldasm.S +++ b/libexec/ld.so/aarch64/ldasm.S @@ -1,4 +1,4 @@ -/* $OpenBSD: ldasm.S,v 1.7 2018/10/01 22:53:48 mortimer Exp $ */ +/* $OpenBSD: ldasm.S,v 1.8 2019/05/10 13:29:21 guenther Exp $ */ /* * Copyright (c) 2016 Dale Rahn @@ -30,7 +30,11 @@ #include <machine/asm.h> #include <sys/syscall.h> -ENTRY(_dl_start) + .section .boot.text,"ax",@progbits + _ALIGN_TEXT + .globl _dl_start + .type _dl_start,#function +_dl_start: mov x29, sp // need to worry about alignment, I think not? mov x19, sp @@ -62,6 +66,7 @@ ENTRY(_dl_start) ldr x2, [x8, :got_lo12:_dl_dtors] br x0 +END(_dl_start) ENTRY(_dl_bind_start) /* @@ -103,9 +108,11 @@ ENTRY(_dl_bind_start) // restore LR saved by PLT stub ldp xzr, x30, [sp], #16 br x17 +END(_dl_bind_start) ENTRY(_rtld_tlsdesc) RETGUARD_SETUP(_rtld_tlsdesc, x15) ldr x0, [x0, #8] RETGUARD_CHECK(_rtld_tlsdesc, x15) ret +END(_rtld_tlsdesc) diff --git a/libexec/ld.so/amd64/Makefile.inc b/libexec/ld.so/amd64/Makefile.inc index 94a3002bc03..cfd3018d9f8 100644 --- a/libexec/ld.so/amd64/Makefile.inc +++ b/libexec/ld.so/amd64/Makefile.inc @@ -1,4 +1,5 @@ -# $OpenBSD: Makefile.inc,v 1.4 2018/04/27 06:49:06 guenther Exp $ +# $OpenBSD: Makefile.inc,v 1.5 2019/05/10 13:29:21 guenther Exp $ CFLAGS += -fPIC -mno-sse2 -mno-sse -mno-3dnow -mno-mmx AFLAGS += -fpic +LD_SCRIPT = ${.CURDIR}/${MACHINE_CPU}/ld.script diff --git a/libexec/ld.so/amd64/ld.script b/libexec/ld.so/amd64/ld.script new file mode 100644 index 00000000000..5629239dd52 --- /dev/null +++ b/libexec/ld.so/amd64/ld.script @@ -0,0 +1,69 @@ +PHDRS +{ + rodata PT_LOAD FILEHDR PHDRS FLAGS (4); + text PT_LOAD; + data PT_LOAD; + random PT_OPENBSD_RANDOMIZE; + relro PT_GNU_RELRO; + dynamic PT_DYNAMIC; + note PT_NOTE; +} + +SECTIONS +{ + . = 0 + SIZEOF_HEADERS; + /* RODATA */ + .gnu.hash : { *(.gnu.hash) } :rodata + .dynsym : { *(.dynsym) } :rodata + .dynstr : { *(.dynstr) } :rodata + .rodata : { *(.rodata .rodata.*) } :rodata + .eh_frame : { *(.eh_frame) } :rodata + + /* TEXT */ + . = ALIGN(0x100000) + (. & (0x100000 - 1)) + 0; + .boot.text : + { + boot_text_start = .; + *(.boot.text) + boot_text_end = .; + } :text =0xcccccccc + . = ALIGN(0x1000); + .text : { *(.text .text.*) } :text =0xcccccccc + + /* RELRO DATA */ + . = DATA_SEGMENT_ALIGN (0x100000, 0x1000); + .openbsd.randomdata : + { + *(.openbsd.randomdata .openbsd.randomdata.*) + } :data :relro :random + .data.rel.ro : { *(.data.rel.ro.local*) *(.data.rel.ro*) } :data :relro + .dynamic : { *(.dynamic) } :data :relro :dynamic + .got : { *(.got.plt) *(.got) } :data :relro + . = DATA_SEGMENT_RELRO_END (0, .); + + /* BOOTDATA */ + . = ALIGN(0x1000); + boot_data_start = .; + .rela.dyn : + { + *(.rela.text .rela.text.*) + *(.rela.rodata .rela.rodata.*) + *(.rela.data .rela.data.*) + *(.rela.got) + *(.rela.bss .rela.bss.*) + } :data +/* XXX .rela.plt is unused but cannot delete: ld.bfd zeros DT_RELASZ then! */ + .rela.plt : { *(.rela.plt) } :data + .note : { *(.note.openbsd.*) } :data :note + .hash : { *(.hash) } :data + .boot.data : { *(.boot.data .boot.data.*) } :data + boot_data_end = .; + + /* DATA */ + . = ALIGN(0x1000); + .data : { *(.data .data.*) } :data + .bss : { *(.dynbss) *(.bss .bss.*) *(COMMON) } :data + . = DATA_SEGMENT_END (.); + + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/libexec/ld.so/amd64/ldasm.S b/libexec/ld.so/amd64/ldasm.S index 9f18b87617a..6ae3f8de1d4 100644 --- a/libexec/ld.so/amd64/ldasm.S +++ b/libexec/ld.so/amd64/ldasm.S @@ -1,4 +1,4 @@ -/* $OpenBSD: ldasm.S,v 1.29 2017/08/28 14:12:09 deraadt Exp $ */ +/* $OpenBSD: ldasm.S,v 1.30 2019/05/10 13:29:21 guenther Exp $ */ /* * Copyright (c) 2002,2004 Dale Rahn @@ -32,7 +32,7 @@ #define DL_LOFF_OFFSET (7*8) /* index 7 */ #include <machine/asm.h> - .text + .section .boot.text,"ax",@progbits .align 16,0xcc .globl _dl_start .type _dl_start,@function @@ -65,11 +65,9 @@ _dl_start: leaq _dl_dtors(%rip), %rdx # %rdx = cleanup movq %r12, %rsp jmp *%rax +END(_dl_start) - .align 16,0xcc - .global _dl_bind_start - .type _dl_bind_start,@function -_dl_bind_start: +_ENTRY(_dl_bind_start) .cfi_startproc .cfi_adjust_cfa_offset 16 pushfq # save registers @@ -143,3 +141,4 @@ _dl_bind_start: .cfi_adjust_cfa_offset -8 ret .cfi_endproc +END(_dl_bind_start) diff --git a/libexec/ld.so/arm/Makefile.inc b/libexec/ld.so/arm/Makefile.inc index 844566f0766..1de862f8d44 100644 --- a/libexec/ld.so/arm/Makefile.inc +++ b/libexec/ld.so/arm/Makefile.inc @@ -1,7 +1,8 @@ -# $OpenBSD: Makefile.inc,v 1.5 2016/08/14 18:46:03 guenther Exp $ +# $OpenBSD: Makefile.inc,v 1.6 2019/05/10 13:29:21 guenther Exp $ CFLAGS += -fpic -msoft-float AFLAGS += -D_STANDALONE +LD_SCRIPT = ${.CURDIR}/${MACHINE_CPU}/ld.script CPPFLAGS += -I${.CURDIR}/../../lib/libc/arch/arm SRCS+= divsi3.S LIBCSRCDIR=${.CURDIR}/../../lib/libc diff --git a/libexec/ld.so/arm/ld.script b/libexec/ld.so/arm/ld.script new file mode 100644 index 00000000000..f18abe07795 --- /dev/null +++ b/libexec/ld.so/arm/ld.script @@ -0,0 +1,70 @@ +PHDRS +{ + rodata PT_LOAD FILEHDR PHDRS FLAGS (4); + text PT_LOAD; + data PT_LOAD; + random PT_OPENBSD_RANDOMIZE; + relro PT_GNU_RELRO; + dynamic PT_DYNAMIC; + note PT_NOTE; +} + +SECTIONS +{ + /* RODATA */ + . = 0 + SIZEOF_HEADERS; + .ARM.exidx : { *(.ARM.exidx*) } :rodata + .dynsym : { *(.dynsym) } :rodata + .gnu.hash : { *(.gnu.hash) } :rodata + .dynstr : { *(.dynstr) } :rodata + .rodata : { *(.rodata .rodata.*) } :rodata + .eh_frame : { *(.eh_frame) } :rodata + + /* TEXT */ + . = ALIGN(0x10000); + .text : { *(.text .text.*) } :text + . = ALIGN(0x1000); + .boot.text : + { + boot_text_start = .; + *(.boot.text) + boot_text_end = .; + } :text + + /* RELRO DATA */ + . = DATA_SEGMENT_ALIGN (0x10000, 0x1000); + .openbsd.randomdata : + { + *(.openbsd.randomdata .openbsd.randomdata.*) + } :data :relro :random + .data.rel.ro : { *(.data.rel.ro.local*) *(.data.rel.ro*) } :data :relro + .dynamic : { *(.dynamic) } :data :relro :dynamic + .got : { *(.got.plt) *(.got) } :data :relro + . = DATA_SEGMENT_RELRO_END (0, .); + + /* BOOTDATA */ + . = ALIGN(0x1000); + boot_data_start = .; + .rel.dyn : + { + *(.rel.text .rel.text.*) + *(.rel.rodata .rel.rodata.*) + *(.rel.data .rel.data.*) + *(.rel.got) + *(.rel.bss .rel.bss.*) + } :data +/* XXX .rel.plt is unused but cannot delete: ld.bfd zeros DT_RELASZ then! */ + .rel.plt : { *(.rel.plt) } :data + .hash : { *(.hash) } :data + .note : { *(.note.openbsd.*) } :data :note + .boot.data : { *(.boot.data .boot.data.*) } :data + boot_data_end = .; + + /* DATA */ + . = ALIGN(0x1000); + .data : { *(.data .data.*) } :data + .bss : { *(.dynbss) *(.bss .bss.*) *(COMMON) } :data + . = DATA_SEGMENT_END (.); + + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/libexec/ld.so/arm/ldasm.S b/libexec/ld.so/arm/ldasm.S index 47c6a76d0de..5bc623513ae 100644 --- a/libexec/ld.so/arm/ldasm.S +++ b/libexec/ld.so/arm/ldasm.S @@ -1,4 +1,4 @@ -/* $OpenBSD: ldasm.S,v 1.27 2017/08/28 14:12:09 deraadt Exp $ */ +/* $OpenBSD: ldasm.S,v 1.28 2019/05/10 13:29:21 guenther Exp $ */ /* * Copyright (c) 2004 Dale Rahn @@ -30,7 +30,11 @@ #include <machine/asm.h> #include <sys/syscall.h> -ENTRY(_dl_start) + .section .boot.text,"ax",%progbits + _ALIGN_TEXT + .globl _dl_start + .type _dl_start,#function +_dl_start: mov fp, sp mov r5, sp mov lr, r6 @ save lr @@ -70,6 +74,7 @@ ENTRY(_dl_start) .long _DYNAMIC(GOTOFF) .L_dl_dtors: .long _dl_dtors(GOTOFF) +END(_dl_start) ENTRY(_dl_bind_start) @@ -89,3 +94,4 @@ ENTRY(_dl_bind_start) mov ip, r0 ldmia sp!, {r0-r4,sl,fp,lr} mov pc, ip +END(_dl_bind_start) diff --git a/libexec/ld.so/boot.c b/libexec/ld.so/boot.c index 0205b7d3103..b9b05685cc7 100644 --- a/libexec/ld.so/boot.c +++ b/libexec/ld.so/boot.c @@ -1,4 +1,4 @@ -/* $OpenBSD: boot.c,v 1.16 2018/10/23 04:01:45 guenther Exp $ */ +/* $OpenBSD: boot.c,v 1.17 2019/05/10 13:29:21 guenther Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -74,7 +74,7 @@ struct boot_dyn { /* * Local decls. */ -void _dl_boot_bind(const long, long *, Elf_Dyn *); +void _dl_boot_bind(const long, long *, Elf_Dyn *) __boot; void _dl_boot_bind(const long sp, long *dl_data, Elf_Dyn *dynp) diff --git a/libexec/ld.so/loader.c b/libexec/ld.so/loader.c index 19a58a5e2ae..a597f0cbd72 100644 --- a/libexec/ld.so/loader.c +++ b/libexec/ld.so/loader.c @@ -1,4 +1,4 @@ -/* $OpenBSD: loader.c,v 1.177 2018/12/03 05:29:56 guenther Exp $ */ +/* $OpenBSD: loader.c,v 1.178 2019/05/10 13:29:21 guenther Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -37,6 +37,7 @@ #include <link.h> #include <limits.h> /* NAME_MAX */ #include <dlfcn.h> +#include <tib.h> #include "syscall.h" #include "archdep.h" @@ -48,30 +49,51 @@ /* * Local decls. */ -unsigned long _dl_boot(const char **, char **, const long, long *); +unsigned long _dl_boot(const char **, char **, const long, long *) __boot; void _dl_debug_state(void); -void _dl_setup_env(const char *_argv0, char **_envp); +void _dl_setup_env(const char *_argv0, char **_envp) __boot; void _dl_dtors(void); -void _dl_fixup_user_env(void); -void _dl_call_preinit(elf_object_t *); +void _dl_dopreload(char *_paths) __boot; +void _dl_fixup_user_env(void) __boot; +void _dl_call_preinit(elf_object_t *) __boot; void _dl_call_init_recurse(elf_object_t *object, int initfirst); +void _dl_clean_boot(void); int _dl_pagesz __relro = 4096; int _dl_bindnow __relro = 0; int _dl_debug __relro = 0; int _dl_trust __relro = 0; char **_dl_libpath __relro = NULL; +const char **_dl_argv __relro = NULL; +int _dl_argc __relro = 0; -/* XXX variables which are only used during boot */ -char *_dl_preload __relro = NULL; -char *_dl_tracefmt1 __relro = NULL; -char *_dl_tracefmt2 __relro = NULL; -char *_dl_traceprog __relro = NULL; +char *_dl_preload __boot_data = NULL; +char *_dl_tracefmt1 __boot_data = NULL; +char *_dl_tracefmt2 __boot_data = NULL; +char *_dl_traceprog __boot_data = NULL; + +char **environ = NULL; +char *__progname = NULL; int _dl_traceld; struct r_debug *_dl_debug_map; -void _dl_dopreload(char *paths); +static dl_cb_cb _dl_cb_cb; +const struct dl_cb_0 callbacks_0 = { + .dl_allocate_tib = &_dl_allocate_tib, + .dl_free_tib = &_dl_free_tib, +#if DO_CLEAN_BOOT + .dl_clean_boot = &_dl_clean_boot, +#endif + .dlopen = &dlopen, + .dlclose = &dlclose, + .dlsym = &dlsym, + .dladdr = &dladdr, + .dlctl = &dlctl, + .dlerror = &dlerror, + .dl_iterate_phdr = &dl_iterate_phdr, +}; + /* * Run dtors for a single object. @@ -182,6 +204,18 @@ _dl_dtors(void) _dl_run_all_dtors(); } +#if DO_CLEAN_BOOT +void +_dl_clean_boot(void) +{ + extern char boot_text_start[], boot_text_end[]; + extern char boot_data_start[], boot_data_end[]; + + _dl_munmap(boot_text_start, boot_text_end - boot_text_start); + _dl_munmap(boot_data_start, boot_data_end - boot_data_start); +} +#endif /* DO_CLEAN_BOOT */ + void _dl_dopreload(char *paths) { @@ -208,8 +242,6 @@ _dl_dopreload(char *paths) * grab interesting environment variables, zap bad env vars if * issetugid, and set the exported environ and __progname variables */ -char **environ = NULL; -char *__progname = NULL; void _dl_setup_env(const char *argv0, char **envp) { @@ -429,6 +461,10 @@ _dl_boot(const char **argv, char **envp, const long dyn_loff, long *dl_data) if (dl_data[AUX_pagesz] != 0) _dl_pagesz = dl_data[AUX_pagesz]; _dl_malloc_init(); + + _dl_argv = argv; + while (_dl_argv[_dl_argc] != NULL) + _dl_argc++; _dl_setup_env(argv[0], envp); /* @@ -692,17 +728,6 @@ _dl_rtld(elf_object_t *object) object->obj_flags & DF_1_NOW)); /* - * Handle GNU_RELRO - */ - if (object->relro_addr != 0 && object->relro_size != 0) { - Elf_Addr addr = object->relro_addr; - - DL_DEB(("protect RELRO [0x%lx,0x%lx) in %s\n", - addr, addr + object->relro_size, object->load_name)); - _dl_mprotect((void *)addr, object->relro_size, PROT_READ); - } - - /* * Look for W&X segments and make them read-only. */ for (llist = object->load_list; llist != NULL; llist = llist->next) { @@ -733,7 +758,8 @@ _dl_call_preinit(elf_object_t *object) DL_DEB(("doing preinitarray obj %p @%p: [%s]\n", object, object->dyn.preinit_array, object->load_name)); for (i = 0; i < num; i++) - (*object->dyn.preinit_array[i])(); + (*object->dyn.preinit_array[i])(_dl_argc, _dl_argv, + environ, &_dl_cb_cb); } } @@ -744,6 +770,21 @@ _dl_call_init(elf_object_t *object) _dl_call_init_recurse(object, 0); } +static void +_dl_relro(elf_object_t *object) +{ + /* + * Handle GNU_RELRO + */ + if (object->relro_addr != 0 && object->relro_size != 0) { + Elf_Addr addr = object->relro_addr; + + DL_DEB(("protect RELRO [0x%lx,0x%lx) in %s\n", + addr, addr + object->relro_size, object->load_name)); + _dl_mprotect((void *)addr, object->relro_size, PROT_READ); + } +} + void _dl_call_init_recurse(elf_object_t *object, int initfirst) { @@ -765,6 +806,9 @@ _dl_call_init_recurse(elf_object_t *object, int initfirst) if (initfirst && (object->obj_flags & DF_1_INITFIRST) == 0) return; + if (!initfirst) + _dl_relro(object); + if (object->dyn.init) { DL_DEB(("doing ctors obj %p @%p: [%s]\n", object, object->dyn.init, object->load_name)); @@ -778,9 +822,13 @@ _dl_call_init_recurse(elf_object_t *object, int initfirst) DL_DEB(("doing initarray obj %p @%p: [%s]\n", object, object->dyn.init_array, object->load_name)); for (i = 0; i < num; i++) - (*object->dyn.init_array[i])(); + (*object->dyn.init_array[i])(_dl_argc, _dl_argv, + environ, &_dl_cb_cb); } + if (initfirst) + _dl_relro(object); + object->status |= STAT_INIT_DONE; } @@ -864,3 +912,12 @@ _dl_fixup_user_env(void) *((char **)(sym->st_value + ooff)) = __progname; } } + +const void * +_dl_cb_cb(int version) +{ + DL_DEB(("version %d callbacks requested\n", version)); + if (version == 0) + return &callbacks_0; + return NULL; +} diff --git a/libexec/ld.so/powerpc/Makefile.inc b/libexec/ld.so/powerpc/Makefile.inc index f59eaab6642..f979b8f7405 100644 --- a/libexec/ld.so/powerpc/Makefile.inc +++ b/libexec/ld.so/powerpc/Makefile.inc @@ -1,3 +1,4 @@ -# $OpenBSD: Makefile.inc,v 1.2 2002/12/09 20:56:34 drahn Exp $ +# $OpenBSD: Makefile.inc,v 1.3 2019/05/10 13:29:21 guenther Exp $ CFLAGS += -fpic -msoft-float +LD_SCRIPT = ${.CURDIR}/${MACHINE_CPU}/ld.script diff --git a/libexec/ld.so/powerpc/ld.script b/libexec/ld.so/powerpc/ld.script new file mode 100644 index 00000000000..96614bc9732 --- /dev/null +++ b/libexec/ld.so/powerpc/ld.script @@ -0,0 +1,70 @@ +PHDRS +{ + rodata PT_LOAD FILEHDR PHDRS FLAGS (4); + text PT_LOAD; + data PT_LOAD; + random PT_OPENBSD_RANDOMIZE; + relro PT_GNU_RELRO; + dynamic PT_DYNAMIC; + note PT_NOTE; +} + +SECTIONS +{ + . = 0 + SIZEOF_HEADERS; + /* RODATA */ + .dynsym : { *(.dynsym) } :rodata + .gnu.hash : { *(.gnu.hash) } :rodata + .dynstr : { *(.dynstr) } :rodata + .rodata : { *(.rodata .rodata.*) } :rodata + .eh_frame : { *(.eh_frame) } :rodata + + /* TEXT */ + . = ALIGN(0x10000); + .boot.text : + { + boot_text_start = .; + *(.boot.text) + boot_text_end = .; + } :text + . = ALIGN(0x1000); + .text : { *(.text .text.*) } :text + + /* RELRO DATA */ + . = DATA_SEGMENT_ALIGN (0x10000, 0x1000); + .openbsd.randomdata : + { + *(.openbsd.randomdata .openbsd.randomdata.*) + } :data :relro :random + .data.rel.ro : { *(.data.rel.ro.local*) *(.data.rel.ro*) } :data :relro + .dynamic : { *(.dynamic) } :data :relro :dynamic + .got : { *(.got.plt) *(.got) } :data :relro + . = DATA_SEGMENT_RELRO_END (0, .); + + /* BOOTDATA */ + boot_data_start = .; + .rela.dyn : + { + *(.rela.text .rela.text.*) + *(.rela.rodata .rela.rodata.*) + *(.rela.data .rela.data.*) + *(.rela.got) + *(.rela.bss .rela.bss.*) + } :data +/* XXX .rela.plt is unused but cannot delete: ld.bfd zeros DT_RELASZ then! */ + .rela.plt : { *(.rela.plt) } :data + .hash : { *(.hash) } :data + .note : { *(.note.openbsd.*) } :data :note + .boot.data : { *(.boot.data .boot.data.*) } :data + boot_data_end = .; + + /* DATA */ + . = ALIGN(0x1000); + .sdata : { *(.sdata .sdata.*) } :data + .data : { *(.data .data.*) } :data + .sbss : { *(.sbss .sbss.*) } :data + .bss : { *(.dynbss) *(.bss .bss.*) *(COMMON) } :data + . = DATA_SEGMENT_END (.); + + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/libexec/ld.so/powerpc/ldasm.S b/libexec/ld.so/powerpc/ldasm.S index 67ec6945ef0..a19bc4068fa 100644 --- a/libexec/ld.so/powerpc/ldasm.S +++ b/libexec/ld.so/powerpc/ldasm.S @@ -1,4 +1,4 @@ -/* $OpenBSD: ldasm.S,v 1.32 2017/08/27 21:59:52 deraadt Exp $ */ +/* $OpenBSD: ldasm.S,v 1.33 2019/05/10 13:29:21 guenther Exp $ */ /* * Copyright (c) 1999 Dale Rahn @@ -31,7 +31,11 @@ #include <machine/asm.h> #include <sys/syscall.h> -ENTRY(_dl_start) + .section .boot.text,"ax",@progbits + .align 2 + .globl _dl_start + .type _dl_start,@function +_dl_start: mr 19, 1 stwu 1, (-16 -((AUX_entry+3)*4))(1) # Some space. @@ -84,6 +88,7 @@ ENTRY(_dl_start) mtlr 27 lwz 1, 0(1) # Restore stack pointer. bctr # Go execute the 'real' program. +END(_dl_start) ENTRY(_dl_bind_start) stwu 1,-72(1) @@ -121,3 +126,4 @@ ENTRY(_dl_bind_start) addi 1,1,72 bctr +END(_dl_bind_start) diff --git a/libexec/ld.so/resolve.h b/libexec/ld.so/resolve.h index 6a87eb538cd..1f313788a5b 100644 --- a/libexec/ld.so/resolve.h +++ b/libexec/ld.so/resolve.h @@ -1,4 +1,4 @@ -/* $OpenBSD: resolve.h,v 1.90 2019/04/21 04:11:42 deraadt Exp $ */ +/* $OpenBSD: resolve.h,v 1.91 2019/05/10 13:29:21 guenther Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -30,11 +30,22 @@ #define _RESOLVE_H_ #include <sys/queue.h> -#include <link.h> #include <dlfcn.h> +#include <link.h> +#include <tib.h> #define __relro __attribute__((section(".data.rel.ro"))) +#ifndef __boot +# if DO_CLEAN_BOOT +# define __boot __attribute__((section(".boot.text"))) +# define __boot_data __attribute__((section(".boot.data"))) +# else +# define __boot +# define __boot_data +# endif +#endif + /* Number of low tags that are used saved internally (0 .. DT_NUM-1) */ #define DT_NUM (DT_PREINIT_ARRAYSZ + 1) @@ -47,6 +58,9 @@ struct load_list { long foff; }; +typedef void initarrayfunc(int, const char **, char **, dl_cb_cb *); +typedef void initfunc(void); /* also fini and fini_array functions */ + /* Alpha uses 8byte entries for DT_HASH */ #ifdef __alpha__ typedef uint64_t Elf_Hash_Word; @@ -88,8 +102,8 @@ struct elf_object { Elf_Addr relaent; Elf_Addr strsz; Elf_Addr syment; - void (*init)(void); - void (*fini)(void); + initfunc *init; + initfunc *fini; const char *soname; const char *rpath; Elf_Addr symbolic; @@ -101,14 +115,14 @@ struct elf_object { Elf_Addr textrel; Elf_Addr jmprel; Elf_Addr bind_now; - void (**init_array)(void); - void (**fini_array)(void); + initarrayfunc **init_array; + initfunc **fini_array; Elf_Addr init_arraysz; Elf_Addr fini_arraysz; const char *runpath; Elf_Addr flags; Elf_Addr encoding; - void (**preinit_array)(void); + initarrayfunc **preinit_array; Elf_Addr preinit_arraysz; } u; } Dyn; @@ -291,16 +305,16 @@ typedef void lock_cb(int); void _dl_thread_kern_go(lock_cb *); lock_cb *_dl_thread_kern_stop(void); -char *_dl_getenv(const char *, char **); -void _dl_unsetenv(const char *, char **); +char *_dl_getenv(const char *, char **) __boot; +void _dl_unsetenv(const char *, char **) __boot; -void _dl_trace_setup(char **); +void _dl_trace_setup(char **) __boot; void _dl_trace_object_setup(elf_object_t *); int _dl_trace_plt(const elf_object_t *, const char *); /* tib.c */ -void _dl_allocate_tls_offsets(void); -void _dl_allocate_first_tib(void); +void _dl_allocate_tls_offsets(void) __boot; +void _dl_allocate_first_tib(void) __boot; void _dl_set_tls(elf_object_t *_object, Elf_Phdr *_ptls, Elf_Addr _libaddr, const char *_libname); extern int _dl_tib_static_done; diff --git a/libexec/ld.so/sparc64/Makefile.inc b/libexec/ld.so/sparc64/Makefile.inc index d2418bcf03d..a6c279e5787 100644 --- a/libexec/ld.so/sparc64/Makefile.inc +++ b/libexec/ld.so/sparc64/Makefile.inc @@ -1,4 +1,5 @@ -# $OpenBSD: Makefile.inc,v 1.1 2002/08/21 15:40:30 art Exp $ +# $OpenBSD: Makefile.inc,v 1.2 2019/05/10 13:29:21 guenther Exp $ CFLAGS += -fpic -msoft-float AFLAGS += -fpic +LD_SCRIPT = ${.CURDIR}/${MACHINE_CPU}/ld.script diff --git a/libexec/ld.so/sparc64/ld.script b/libexec/ld.so/sparc64/ld.script new file mode 100644 index 00000000000..ca16652722b --- /dev/null +++ b/libexec/ld.so/sparc64/ld.script @@ -0,0 +1,69 @@ +PHDRS +{ + rodata PT_LOAD FILEHDR PHDRS FLAGS (4); + text PT_LOAD; + data PT_LOAD; + random PT_OPENBSD_RANDOMIZE; + relro PT_GNU_RELRO; + dynamic PT_DYNAMIC; + note PT_NOTE; +} + +SECTIONS +{ + . = 0 + SIZEOF_HEADERS; + /* RODATA */ + .gnu.hash : { *(.gnu.hash) } :rodata + .dynsym : { *(.dynsym) } :rodata + .dynstr : { *(.dynstr) } :rodata + .rodata : { *(.rodata .rodata.*) } :rodata +/* .eh_frame : { *(.eh_frame) } :rodata */ + + /* TEXT */ + . = ALIGN(0x100000) + (. & (0x100000 - 1)) + 0; + .boot.text : + { + boot_text_start = .; + *(.boot.text) + boot_text_end = .; + } :text =0xcccccccc + . = ALIGN(0x100000); + .text : { *(.text .text.*) } :text =0xcccccccc + + /* RELRO DATA */ + . = DATA_SEGMENT_ALIGN (0x100000, 0x2000); + .openbsd.randomdata : + { + *(.openbsd.randomdata .openbsd.randomdata.*) + } :data :relro :random + .data.rel.ro : { *(.data.rel.ro.local*) *(.data.rel.ro*) } :data :relro + .dynamic : { *(.dynamic) } :data :relro :dynamic + .got : { *(.got.plt) *(.got) } :data :relro + . = DATA_SEGMENT_RELRO_END (0, .); + + /* BOOTDATA */ + . = ALIGN(0x100000); + boot_data_start = .; + .rela.dyn : + { + *(.rela.text .rela.text.*) + *(.rela.rodata .rela.rodata.*) + *(.rela.data .rela.data.*) + *(.rela.got) + *(.rela.bss .rela.bss.*) + } :data +/* XXX .rela.plt is unused but cannot delete: ld.bfd zeros DT_RELASZ then! */ + .rela.plt : { *(.rela.plt) } :data + .note : { *(.note.openbsd.*) } :data :note + .hash : { *(.hash) } :data + .boot.data : { *(.boot.data .boot.data.*) } :data + boot_data_end = .; + + /* DATA */ + . = ALIGN(0x100000); + .data : { *(.data .data.*) } :data + .bss : { *(.dynbss) *(.bss .bss.*) *(COMMON) } :data + . = DATA_SEGMENT_END (.); + + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/libexec/ld.so/sparc64/ldasm.S b/libexec/ld.so/sparc64/ldasm.S index e5503e52804..1ea377927e1 100644 --- a/libexec/ld.so/sparc64/ldasm.S +++ b/libexec/ld.so/sparc64/ldasm.S @@ -1,4 +1,4 @@ -/* $OpenBSD: ldasm.S,v 1.46 2017/08/27 21:59:52 deraadt Exp $ */ +/* $OpenBSD: ldasm.S,v 1.47 2019/05/10 13:29:21 guenther Exp $ */ /* $NetBSD: rtld_start.S,v 1.5 2001/08/14 22:17:48 eeh Exp $ */ /* @@ -86,7 +86,7 @@ /* XXX - DL_DATA_SIZE should be (9*8), but I can't think right now. */ #define DL_DATA_SIZE (16*8) - .section ".text" + .section .boot.text,"ax",@progbits .align 16 .register %g2,#scratch @@ -136,6 +136,7 @@ _ENTRY(_dl_start) jmp %o0 ldx [%l7 + _dl_dtors], %g1 ! %g1 = cleanup +END(_dl_start) /* * We have two separate entry points to the runtime linker. @@ -164,8 +165,7 @@ _ENTRY(_dl_start) * done in the PLT entry. */ - /* NOTE: _dl_bind_start_0 is untested. Hence the debug stuff */ - + .text _ENTRY(_dl_bind_start_0) # (x, y) sethi %hi(32768*32-8), %l1 sub %o0, %o1, %l0 /* x - y */ @@ -197,6 +197,7 @@ _ENTRY(_dl_bind_start_0) # (x, y) jmp %o0 /* return value == function address */ restore /* Dump our stack frame */ +END(_dl_bind_start_0) _ENTRY(_dl_bind_start_1) # (x, y) srax %o0, 15, %o2 /* %o0 is the index to our PLT slot */ @@ -208,3 +209,4 @@ _ENTRY(_dl_bind_start_1) # (x, y) jmp %o0 /* return value == function address */ restore /* Dump our stack frame */ +END(_dl_bind_start_1) diff --git a/libexec/ld.so/util.h b/libexec/ld.so/util.h index b21769cdb0f..fcf7f1835d1 100644 --- a/libexec/ld.so/util.h +++ b/libexec/ld.so/util.h @@ -1,4 +1,4 @@ -/* $OpenBSD: util.h,v 1.34 2019/01/25 00:19:26 millert Exp $ */ +/* $OpenBSD: util.h,v 1.35 2019/05/10 13:29:21 guenther Exp $ */ /* * Copyright (c) 1998 Todd C. Miller <millert@openbsd.org> @@ -35,8 +35,18 @@ #include <stdarg.h> #include <stddef.h> /* for NULL */ +#ifndef __boot +# if DO_CLEAN_BOOT +# define __boot __attribute__((section(".boot.text"))) +# define __boot_data __attribute__((section(".boot.data"))) +# else +# define __boot +# define __boot_data +# endif +#endif + __BEGIN_HIDDEN_DECLS -void _dl_malloc_init(void); +void _dl_malloc_init(void) __boot; void *_dl_malloc(size_t size); void *_dl_calloc(size_t nmemb, const size_t size); void *_dl_realloc(void *, size_t size); |