Make ld.so on alpha cope with binaries built with secureplt (where secure here
authormiod <miod@openbsd.org>
Fri, 29 May 2015 19:12:26 +0000 (19:12 +0000)
committermiod <miod@openbsd.org>
Fri, 29 May 2015 19:12:26 +0000 (19:12 +0000)
means read-only, which our ld.so already enforced, but a smaller plt section).

libexec/ld.so/alpha/ldasm.S
libexec/ld.so/alpha/rtld_machine.c
sys/arch/alpha/include/exec.h

index 4448cd4..42c93dd 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ldasm.S,v 1.28 2014/07/28 04:28:43 guenther Exp $ */
+/*     $OpenBSD: ldasm.S,v 1.29 2015/05/29 19:12:26 miod Exp $ */
 
 /*
  * Copyright (c) 2001 Niklas Hallqvist
@@ -146,8 +146,8 @@ NESTED_NOPROFILE(_dl_bind_start, 0, 168, ra, 0, 0)
         * Load our global pointer.  Note, can't use pv, since it is
         * already used by the PLT code.
         */
-       br      t0, L100
-L100:  LDGP(t0)
+       br      t0, 1f
+1:     LDGP(t0)
 
        /* Set up the arguments for _dl_bind. */
        subq    at_reg, t12, a1
@@ -193,6 +193,82 @@ L100:      LDGP(t0)
        jmp     zero, (pv)
 END(_dl_bind_start)
 
+/*
+ * Lazy binding entry point, called via secure (read-only) PLT.
+ */
+NESTED_NOPROFILE(_dl_bind_secureplt, 0, 168, ra, 0, 0)
+       .set    noat
+       /* at_reg and t11 already used by PLT code. */
+
+       /*
+        * Allocate stack frame and preserve all registers that the caller
+        * would have normally saved themselves.
+        */
+       lda     sp, -160(sp)
+       stq     ra, 0(sp)
+       stq     v0, 8(sp)
+       stq     t0, 16(sp)
+       stq     t1, 24(sp)
+       stq     t2, 32(sp)
+       stq     t3, 40(sp)
+       stq     t4, 48(sp)
+       stq     t5, 56(sp)
+       stq     t6, 64(sp)
+       stq     t7, 72(sp)
+       stq     a0, 80(sp)
+       stq     a1, 88(sp)
+       stq     a2, 96(sp)
+       stq     a3, 104(sp)
+       stq     a4, 112(sp)
+       stq     a5, 120(sp)
+       stq     t8, 128(sp)
+       stq     t9, 136(sp)
+       stq     t10, 144(sp)
+       stq     gp, 152(sp)
+
+       /*
+        * Load our global pointer.  Note, can't use pv, since it is
+        * already used by the PLT code.
+        */
+       br      t0, 1f
+1:     LDGP(t0)
+
+       /* Set up the arguments for _dl_bind. */
+       mov     at_reg, a0      /* object */
+       mov     t11, a1         /* reloff as computed by the plt resolver */
+       CALL(_dl_bind)
+
+       /* Move the destination address into position. */
+       mov     v0, pv
+
+       /* Restore program registers. */
+       ldq     ra, 0(sp)
+       ldq     v0, 8(sp)
+       ldq     t0, 16(sp)
+       ldq     t1, 24(sp)
+       ldq     t2, 32(sp)
+       ldq     t3, 40(sp)
+       ldq     t4, 48(sp)
+       ldq     t5, 56(sp)
+       ldq     t6, 64(sp)
+       ldq     t7, 72(sp)
+       ldq     a0, 80(sp)
+       ldq     a1, 88(sp)
+       ldq     a2, 96(sp)
+       ldq     a3, 104(sp)
+       ldq     a4, 112(sp)
+       ldq     a5, 120(sp)
+       ldq     t8, 128(sp)
+       ldq     t9, 136(sp)
+       ldq     t10, 144(sp)
+       ldq     gp, 152(sp)
+       /* XXX LDGP? */
+
+       /* Pop the stack frame and turn control to the destination. */
+       lda     sp, 160(sp)
+       jmp     zero, (pv)
+END(_dl_bind_secureplt)
+
 
 /*
  * In reality these are not leaves, but they are stubs which does not need
index ce41b65..9e55b6d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rtld_machine.c,v 1.52 2014/12/27 13:13:25 kettenis Exp $ */
+/*     $OpenBSD: rtld_machine.c,v 1.53 2015/05/29 19:12:26 miod Exp $ */
 
 /*
  * Copyright (c) 1999 Dale Rahn
@@ -42,6 +42,8 @@
 #include "archdep.h"
 #include "resolve.h"
 
+#define        DT_PROC(n)      ((n) - DT_LOPROC + DT_NUM)
+
 int
 _dl_md_reloc(elf_object_t *object, int rel, int relasz)
 {
@@ -212,17 +214,7 @@ _dl_bind(elf_object_t *object, int reloff)
        sigset_t savedmask;
 
        rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL] + reloff);
-
        addr = (Elf_Addr *)(object->obj_base + rela->r_offset);
-       if (object->plt_size != 0 && !(*addr >=  object->plt_start &&
-           *addr < (object->plt_start + object->plt_size ))) {
-               /* something is broken, relocation has already occurred */
-#if 0
-               DL_DEB(("*addr doesn't point into plt %p obj %s\n", 
-                   *addr, object->load_name));
-#endif
-               return *addr;
-       }
 
        sym = object->dyn.symtab;
        sym += ELF64_R_SYM(rela->r_info);
@@ -239,19 +231,17 @@ _dl_bind(elf_object_t *object, int reloff)
        if (sobj->traced && _dl_trace_plt(sobj, symn))
                return ooff + this->st_value + rela->r_addend;
 
-       /* if PLT is protected, allow the write */
-       if (object->plt_size != 0) {
+       /* if GOT is protected, allow the write */
+       if (object->got_size != 0) {
                _dl_thread_bind_lock(0, &savedmask);
-               _dl_mprotect(addr, sizeof(Elf_Addr),
-                   PROT_READ|PROT_WRITE);
+               _dl_mprotect(addr, sizeof(Elf_Addr), PROT_READ | PROT_WRITE);
        }
 
        *addr = ooff + this->st_value + rela->r_addend;
 
-       /* if PLT is (to be protected, change back to RO/X  */
-       if (object->plt_size != 0) {
-               _dl_mprotect(addr, sizeof(Elf_Addr),
-                   PROT_READ);
+       /* if GOT is to be protected, change back to RO */
+       if (object->got_size != 0) {
+               _dl_mprotect(addr, sizeof(Elf_Addr), PROT_READ);
                _dl_thread_bind_lock(1, &savedmask);
        }
 
@@ -267,19 +257,27 @@ _dl_md_reloc_got(elf_object_t *object, int lazy)
        int     fails = 0;
        Elf_Addr *pltgot;
        extern void _dl_bind_start(void);       /* XXX */
+       extern void _dl_bind_secureplt(void);   /* XXX */
        Elf_Addr ooff;
        Elf_Addr plt_addr;
        const Elf_Sym *this;
+       u_long pltro;
 
+       pltro = object->Dyn.info[DT_PROC(DT_ALPHA_PLTRO)];
        pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
 
        object->got_addr = 0;
        object->got_size = 0;
-       this = NULL;
-       ooff = _dl_find_symbol("__got_start", &this,
-           SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL);
-       if (this != NULL)
-               object->got_addr = ooff + this->st_value;
+       if (pltro != 0 && pltgot != NULL)
+               object->got_addr = (Elf_Addr)pltgot;
+       else {
+               this = NULL;
+               ooff = _dl_find_symbol("__got_start", &this,
+                   SYM_SEARCH_OBJ | SYM_NOWARNNOTFOUND | SYM_PLT, NULL,
+                   object, NULL);
+               if (this != NULL)
+                       object->got_addr = ooff + this->st_value;
+       }
 
        this = NULL;
        ooff = _dl_find_symbol("__got_end", &this,
@@ -289,17 +287,29 @@ _dl_md_reloc_got(elf_object_t *object, int lazy)
 
        plt_addr = 0;
        object->plt_size = 0;
-       this = NULL;
-       ooff = _dl_find_symbol("__plt_start", &this,
-           SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL);
-       if (this != NULL)
-               plt_addr = ooff + this->st_value;
+       /*
+        * Do not even attempt to locate the .plt section if we will not
+        * have to write into it.
+        */
+       if (pltro == 0) {
+               if (pltgot != NULL)
+                       plt_addr = (Elf_Addr)pltgot;
+               else {
+                       this = NULL;
+                       ooff = _dl_find_symbol("__plt_start", &this,
+                           SYM_SEARCH_OBJ | SYM_NOWARNNOTFOUND | SYM_PLT, NULL,
+                           object, NULL);
+                       if (this != NULL)
+                               plt_addr = ooff + this->st_value;
+               }
 
-       this = NULL;
-       ooff = _dl_find_symbol("__plt_end", &this,
-           SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL);
-       if (this != NULL)
-               object->plt_size = ooff + this->st_value  - plt_addr;
+               this = NULL;
+               ooff = _dl_find_symbol("__plt_end", &this,
+                   SYM_SEARCH_OBJ | SYM_NOWARNNOTFOUND | SYM_PLT, NULL,
+                   object, NULL);
+               if (this != NULL)
+                       object->plt_size = ooff + this->st_value  - plt_addr;
+       }
 
        if (object->got_addr == 0)
                object->got_start = 0;
@@ -339,8 +349,13 @@ _dl_md_reloc_got(elf_object_t *object, int lazy)
                }
        }
        if (pltgot != NULL) {
-               pltgot[2] = (Elf_Addr)_dl_bind_start;
-               pltgot[3] = (Elf_Addr)object;
+               if (pltro == 0) {
+                       pltgot[2] = (Elf_Addr)_dl_bind_start;
+                       pltgot[3] = (Elf_Addr)object;
+               } else {
+                       pltgot[0] = (Elf_Addr)_dl_bind_secureplt;
+                       pltgot[1] = (Elf_Addr)object;
+               }
        }
        if (object->got_size != 0)
                _dl_mprotect((void*)object->got_start, object->got_size,
index 9442516..cb2750b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: exec.h,v 1.14 2013/10/17 08:02:14 deraadt Exp $       */
+/*     $OpenBSD: exec.h,v 1.15 2015/05/29 19:12:26 miod Exp $  */
 /*     $NetBSD: exec.h,v 1.1 1995/02/13 23:07:37 cgd Exp $     */
 
 /*
@@ -43,4 +43,9 @@
 #define _NLIST_DO_ELF
 #define _KERN_DO_ELF64
 
+/* Processor specific dynamic tag values.  */
+#define        DT_ALPHA_PLTRO          0x70000000
+
+#define        DT_PROCNUM              (DT_ALPHA_PLTRO + 1 - DT_LOPROC)
+
 #endif /* !_MACHINE_EXEC_H_ */