From b7d44ead2528d548ebe369571fb766478149400a Mon Sep 17 00:00:00 2001 From: kurt Date: Mon, 22 Dec 2014 03:51:08 +0000 Subject: [PATCH] Introduce new csu0 variant for -static -pie binaries to use called rcsu0.o where the initial 'r' is for relocatable. rcsu0.o performs self-relocation on static pie binaries by calling a slightly modified copy of ld.so's _dl_boot_bind() in boot.h. The first arch implementatation is also included for amd64 where __start calls _dl_boot_bind() and then calls ___start(). Includes parts from kettenis@ to help get R_X86_64_64 relocations working and proper handling for undefined weak symbols. This is the first part of several to get static pie self-relocating binaries working. binutils, gcc and kernel changes are forthcoming to complete the solution, then per-arch implementations are needed for MD_RCRT0_START in csu. okay kettenis@ pascal@ deraadt@ --- lib/csu/Makefile | 13 +- lib/csu/amd64/md_init.h | 47 ++++++- lib/csu/boot.h | 250 ++++++++++++++++++++++++++++++++++ lib/csu/crt0.c | 9 +- libexec/ld.so/amd64/archdep.h | 5 +- 5 files changed, 318 insertions(+), 6 deletions(-) create mode 100644 lib/csu/boot.h diff --git a/lib/csu/Makefile b/lib/csu/Makefile index 4e46d296312..561743a6c69 100644 --- a/lib/csu/Makefile +++ b/lib/csu/Makefile @@ -1,11 +1,14 @@ -# $OpenBSD: Makefile,v 1.20 2014/11/15 21:59:29 guenther Exp $ +# $OpenBSD: Makefile,v 1.21 2014/12/22 03:51:08 kurt Exp $ OBJS= crt0.o gcrt0.o OBJS+= crtbegin.o crtend.o OBJS+= crtbeginS.o crtendS.o +OBJS+= rcrt0.o SRCS= crt0.c crtbegin.c crtbeginS.c crtend.c crtendS.c CFLAGS+= -I${.CURDIR}/${MACHINE_CPU} +CFLAGS+= -I${.CURDIR}/../../libexec/ld.so +CFLAGS+= -I${.CURDIR}/../../libexec/ld.so/${MACHINE_CPU} # XXX "use -fno-omit-frame-pointer; the reason is almost crazy; pr#287" .if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386" @@ -50,6 +53,12 @@ gcrt0.o: crt0.c @${LD} -x -r -o ${.TARGET} ${.TARGET}.o @rm -f ${.TARGET}.o +rcrt0.o: crt0.c + @echo ${COMPILE.c} -DRCRT0 -fno-stack-protector ${.CURDIR}/crt0.c -o ${.TARGET} + @${COMPILE.c} -DRCRT0 -fno-stack-protector ${.CURDIR}/crt0.c -o ${.TARGET}.o + @${LD} -x -r -o ${.TARGET} ${.TARGET}.o + @rm -f ${.TARGET}.o + crtbegin.o: crtbegin.c @echo ${COMPILE.c} ${.CURDIR}/crtbegin.c -o ${.TARGET} @${COMPILE.c} ${.CURDIR}/crtbegin.c -o ${.TARGET}.o @@ -80,7 +89,7 @@ realinstall: afterdepend: .depend @(TMP=/tmp/_depend$$$$; \ - sed -e 's/^\([^\.]*\).o[ ]*:/\1.o g\1.o:/' \ + sed -e 's/^\([^\.]*\).o[ ]*:/\1.o g\1.o r\1.o:/' \ < .depend > $$TMP; \ mv $$TMP .depend) diff --git a/lib/csu/amd64/md_init.h b/lib/csu/amd64/md_init.h index c95a7f34171..05c2eb4b222 100644 --- a/lib/csu/amd64/md_init.h +++ b/lib/csu/amd64/md_init.h @@ -1,4 +1,4 @@ -/* $OpenBSD: md_init.h,v 1.3 2013/12/03 06:21:40 guenther Exp $ */ +/* $OpenBSD: md_init.h,v 1.4 2014/12/22 03:51:08 kurt Exp $ */ /*- * Copyright (c) 2001 Ross Harvey @@ -79,3 +79,48 @@ " addq $8,%rsp \n" \ " jmp ___start \n" \ " .previous") + + +#define MD_RCRT0_START \ + __asm( \ + ".text \n" \ + " .align 8 \n" \ + " .globl __start \n" \ + " .type __start,@function \n" \ + "_start: \n" \ + "__start: \n" \ + " movq %rsp, %r12 \n" \ + " subq $8, %rsp \n" \ + " andq $~15, %rsp \n" \ + " addq $8, %rsp \n" \ + " pushq %rbx \n" \ + " subq $(16*8), %rsp \n" \ + " leaq _DYNAMIC(%rip),%rdx \n" \ + " movq %rsp, %rsi \n" \ + " movq %r12, %rdi \n" \ + " call _dl_boot_bind@PLT \n" \ + " \n" \ + " movq $0, %rcx \n" \ + " movq %r12, %rsp \n" \ + " movq (%rsp),%rdi \n" \ + " leaq 16(%rsp,%rdi,8),%rdx \n" \ + " leaq 8(%rsp),%rsi \n" \ + " subq $8,%rsp \n" \ + " andq $~15,%rsp \n" \ + " addq $8,%rsp \n" \ + " jmp ___start \n" \ + " \n" \ + " .global _dl_exit \n" \ + " .type _dl_exit,@function \n" \ + " .align 8 \n" \ + "_dl_exit: \n" \ + " movl $(1), %eax \n" \ + " movq %rcx, %r10 \n" \ + " syscall \n" \ + " jb 1f \n" \ + " ret \n" \ + "1: \n" \ + " neg %rax \n" \ + " ret \n" \ + " .previous") + diff --git a/lib/csu/boot.h b/lib/csu/boot.h new file mode 100644 index 00000000000..a5422d4cf15 --- /dev/null +++ b/lib/csu/boot.h @@ -0,0 +1,250 @@ +/* $OpenBSD: boot.h,v 1.1 2014/12/22 03:51:08 kurt Exp $ */ + +/* + * Copyright (c) 1998 Per Fogelstrom, Opsycon AB + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/* + * IMPORTANT: any functions below are NOT protected by SSP. Please + * do not add anything except what is required to reach GOT with + * an adjustment. + */ + +#define _DYN_LOADER + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "syscall.h" +#include "archdep.h" +#include "path.h" +#include "resolve.h" +#include "sod.h" +#include "stdlib.h" +#include "dl_prebind.h" + +#include "../../lib/csu/os-note-elf.h" + +#ifdef RCRT0 +/* + * Local decls. + */ +void _dl_boot_bind(const long, long *, Elf_Dyn *); + +void +_dl_boot_bind(const long sp, long *dl_data, Elf_Dyn *dynamicp) +{ + struct elf_object dynld; /* Resolver data for the loader */ + AuxInfo *auxstack; + long *stack; + Elf_Dyn *dynp; + int n, argc; + char **argv, **envp; + long loff; + + /* + * Scan argument and environment vectors. Find dynamic + * data vector put after them. + */ + stack = (long *)sp; + argc = *stack++; + argv = (char **)stack; + envp = &argv[argc + 1]; + stack = (long *)envp; + while (*stack++ != 0L) + ; + + /* + * Zero out dl_data. + */ + for (n = 0; n <= AUX_entry; n++) + dl_data[n] = 0; + + /* + * Dig out auxiliary data set up by exec call. Move all known + * tags to an indexed local table for easy access. + */ + for (auxstack = (AuxInfo *)stack; auxstack->au_id != AUX_null; + auxstack++) { + if (auxstack->au_id > AUX_entry) + continue; + dl_data[auxstack->au_id] = auxstack->au_v; + } + loff = dl_data[AUX_base]; /* XXX assumes ld.so is linked at 0x0 */ + + /* + * We need to do 'selfreloc' in case the code weren't + * loaded at the address it was linked to. + * + * Scan the DYNAMIC section for the loader. + * Cache the data for easier access. + */ + +#if defined(__alpha__) + dynp = (Elf_Dyn *)((long)_DYNAMIC); +#elif defined(__sparc__) || defined(__sparc64__) || defined(__powerpc__) || \ + defined(__hppa__) || defined(__sh__) + dynp = dynamicp; +#else + dynp = (Elf_Dyn *)((long)_DYNAMIC + loff); +#endif + _dl_memset(dynld.Dyn.info, 0, sizeof(dynld.Dyn.info)); + while (dynp != NULL && dynp->d_tag != DT_NULL) { + if (dynp->d_tag < DT_NUM) + dynld.Dyn.info[dynp->d_tag] = dynp->d_un.d_val; + else if (dynp->d_tag >= DT_LOPROC && + dynp->d_tag < DT_LOPROC + DT_PROCNUM) + dynld.Dyn.info[dynp->d_tag - DT_LOPROC + DT_NUM] = + dynp->d_un.d_val; + if (dynp->d_tag == DT_TEXTREL) + dynld.dyn.textrel = 1; + dynp++; + } + + /* + * Do the 'bootstrap relocation'. This is really only needed if + * the code was loaded at another location than it was linked to. + * We don't do undefined symbols resolving (to difficult..) + */ + + /* "relocate" dyn.X values if they represent addresses */ + { + int i, val; + /* must be code, not pic data */ + int table[20]; + + i = 0; + table[i++] = DT_PLTGOT; + table[i++] = DT_HASH; + table[i++] = DT_STRTAB; + table[i++] = DT_SYMTAB; + table[i++] = DT_RELA; + table[i++] = DT_INIT; + table[i++] = DT_FINI; + table[i++] = DT_REL; + table[i++] = DT_JMPREL; + /* other processors insert their extras here */ + table[i++] = DT_NULL; + for (i = 0; table[i] != DT_NULL; i++) { + val = table[i]; + if (val >= DT_LOPROC && val < DT_LOPROC + DT_PROCNUM) + val = val - DT_LOPROC + DT_NUM; + else if (val >= DT_NUM) + continue; + if (dynld.Dyn.info[val] != 0) + dynld.Dyn.info[val] += loff; + } + } + + { + u_int32_t rs; + Elf_Rel *rp; + int i; + + rp = (Elf_Rel *)(dynld.Dyn.info[DT_REL]); + rs = dynld.dyn.relsz; + + for (i = 0; i < rs; i += sizeof (Elf_Rel)) { + Elf_Addr *ra; + const Elf_Sym *sp; + + sp = dynld.dyn.symtab; + sp += ELF_R_SYM(rp->r_info); + + if (ELF_R_SYM(rp->r_info) && sp->st_value == 0) { +#if 0 +/* cannot printf in this function */ + _dl_wrstderr("Dynamic loader failure: self bootstrapping impossible.\n"); + _dl_wrstderr("Undefined symbol: "); + _dl_wrstderr((char *)dynld.dyn.strtab + + sp->st_name); +#endif + _dl_exit(5); + } + + ra = (Elf_Addr *)(rp->r_offset + loff); + RELOC_REL(rp, sp, ra, loff); + rp++; + } + } + + for (n = 0; n < 2; n++) { + unsigned long rs; + Elf_RelA *rp; + int i; + + switch (n) { + case 0: + rp = (Elf_RelA *)(dynld.Dyn.info[DT_JMPREL]); + rs = dynld.dyn.pltrelsz; + break; + case 1: + rp = (Elf_RelA *)(dynld.Dyn.info[DT_RELA]); + rs = dynld.dyn.relasz; + break; + default: + rp = NULL; + rs = 0; + } + for (i = 0; i < rs; i += sizeof (Elf_RelA)) { + Elf_Addr *ra; + const Elf_Sym *sp; + + sp = dynld.dyn.symtab; + sp += ELF_R_SYM(rp->r_info); + if (ELF_R_SYM(rp->r_info) && sp->st_value == 0) { +#if 0 + _dl_wrstderr("Dynamic loader failure: self bootstrapping impossible.\n"); + _dl_wrstderr("Undefined symbol: "); + _dl_wrstderr((char *)dynld.dyn.strtab + + sp->st_name); +#endif +#ifdef RCRT0 + continue; +#else + _dl_exit(6); +#endif + } + + ra = (Elf_Addr *)(rp->r_offset + loff); + RELOC_RELA(rp, sp, ra, loff, dynld.dyn.pltgot); + rp++; + } + } + + RELOC_GOT(&dynld, loff); + + /* + * we have been fully relocated here, so most things no longer + * need the loff adjustment + */ +} +#endif /* RCRT0 */ diff --git a/lib/csu/crt0.c b/lib/csu/crt0.c index aaef64a7a57..965eba66e97 100644 --- a/lib/csu/crt0.c +++ b/lib/csu/crt0.c @@ -1,4 +1,4 @@ -/* $OpenBSD: crt0.c,v 1.2 2013/12/12 08:12:08 guenther Exp $ */ +/* $OpenBSD: crt0.c,v 1.3 2014/12/22 03:51:08 kurt Exp $ */ /* * Copyright (c) 1995 Christopher G. Demetriou @@ -35,6 +35,7 @@ #include #include "md_init.h" +#include "boot.h" /* some defaults */ #ifndef MD_START_ARGS @@ -64,9 +65,15 @@ extern void _mcleanup(void); extern unsigned char _etext, _eprol; #endif /* MCRT0 */ +#ifdef RCRT0 +#ifdef MD_RCRT0_START +MD_RCRT0_START; +#endif +#else #ifdef MD_CRT0_START MD_CRT0_START; #endif +#endif void MD_START(MD_START_ARGS) diff --git a/libexec/ld.so/amd64/archdep.h b/libexec/ld.so/amd64/archdep.h index aba43d8be83..93651a4134a 100644 --- a/libexec/ld.so/amd64/archdep.h +++ b/libexec/ld.so/amd64/archdep.h @@ -1,4 +1,4 @@ -/* $OpenBSD: archdep.h,v 1.5 2014/01/19 10:25:45 guenther Exp $ */ +/* $OpenBSD: archdep.h,v 1.6 2014/12/22 03:51:08 kurt Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -65,8 +65,9 @@ RELOC_RELA(Elf64_Rela *r, const Elf64_Sym *s, Elf64_Addr *p, unsigned long v, *p = v + r->r_addend; } else if (ELF64_R_TYPE(r->r_info) == R_X86_64_GLOB_DAT) { *p = v + s->st_value + r->r_addend; + } else if (ELF64_R_TYPE(r->r_info) == R_X86_64_64) { + *p = v + s->st_value + r->r_addend; } else { - _dl_printf("unknown bootstrap relocation\n"); _dl_exit(6); } } -- 2.20.1