Introduce new csu0 variant for -static -pie binaries to use called
authorkurt <kurt@openbsd.org>
Mon, 22 Dec 2014 03:51:08 +0000 (03:51 +0000)
committerkurt <kurt@openbsd.org>
Mon, 22 Dec 2014 03:51:08 +0000 (03:51 +0000)
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
lib/csu/amd64/md_init.h
lib/csu/boot.h [new file with mode: 0644]
lib/csu/crt0.c
libexec/ld.so/amd64/archdep.h

index 4e46d29..561743a 100644 (file)
@@ -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)
 
index c95a7f3..05c2eb4 100644 (file)
@@ -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
        "       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 (file)
index 0000000..a5422d4
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/mman.h>
+#include <sys/exec.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <nlist.h>
+#include <link.h>
+#include <dlfcn.h>
+
+#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 */
index aaef64a..965eba6 100644 (file)
@@ -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 <limits.h>
 
 #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)
index aba43d8..93651a4 100644 (file)
@@ -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);
        }
 }