Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/libexec/ld.elf_so Add secure-plt support for powerpc to ld.e...



details:   https://anonhg.NetBSD.org/src/rev/c0d7464da3ce
branches:  trunk
changeset: 760889:c0d7464da3ce
user:      matt <matt%NetBSD.org@localhost>
date:      Sun Jan 16 01:22:29 2011 +0000

description:
Add secure-plt support for powerpc to ld.elf_so.  As part of this, we have to
stop calling into the GOT/_DYNAMIC since they are no longer executable.

diffstat:

 libexec/ld.elf_so/arch/powerpc/ppc_reloc.c  |  142 +++++++++++++++++----------
 libexec/ld.elf_so/arch/powerpc/rtld_start.S |   46 +++++---
 libexec/ld.elf_so/headers.c                 |    9 +-
 libexec/ld.elf_so/rtld.h                    |    5 +-
 4 files changed, 127 insertions(+), 75 deletions(-)

diffs (truncated from 376 to 300 lines):

diff -r 0c13cebb361a -r c0d7464da3ce libexec/ld.elf_so/arch/powerpc/ppc_reloc.c
--- a/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c        Sun Jan 16 01:13:10 2011 +0000
+++ b/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c        Sun Jan 16 01:22:29 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ppc_reloc.c,v 1.45 2010/08/06 16:33:18 joerg Exp $     */
+/*     $NetBSD: ppc_reloc.c,v 1.46 2011/01/16 01:22:29 matt Exp $      */
 
 /*-
  * Copyright (C) 1998  Tsubai Masanari
@@ -30,7 +30,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: ppc_reloc.c,v 1.45 2010/08/06 16:33:18 joerg Exp $");
+__RCSID("$NetBSD: ppc_reloc.c,v 1.46 2011/01/16 01:22:29 matt Exp $");
 #endif /* not lint */
 
 #include <stdarg.h>
@@ -50,10 +50,11 @@
                        ((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16)
 #define l(x) ((u_int32_t)(x) & 0xffff)
 
-void _rtld_bind_start(void);
+void _rtld_bind_bssplt_start(void);
+void _rtld_bind_secureplt_start(void);
 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
 caddr_t _rtld_bind(const Obj_Entry *, Elf_Word);
-static inline int _rtld_relocate_plt_object(const Obj_Entry *,
+static int _rtld_relocate_plt_object(const Obj_Entry *,
     const Elf_Rela *, int, Elf_Addr *);
 
 /*
@@ -67,7 +68,7 @@
  */
 
 /*
- * Setup the plt glue routines.
+ * Setup the plt glue routines (for bss-plt).
  */
 #define PLTCALL_SIZE   20
 #define PLTRESOLVE_SIZE        24
@@ -75,34 +76,42 @@
 void
 _rtld_setup_pltgot(const Obj_Entry *obj)
 {
-       Elf_Word *pltcall, *pltresolve;
-       Elf_Word *jmptab;
-       int N = obj->pltrelalim - obj->pltrela;
+       /*
+        * Secure-PLT is much more sane.
+        */
+       if (obj->gotptr != NULL) {
+               obj->gotptr[1] = (Elf_Addr) _rtld_bind_secureplt_start;
+               obj->gotptr[2] = (Elf_Addr) obj;
+       } else {
+               Elf_Word *pltcall, *pltresolve;
+               Elf_Word *jmptab;
+               int N = obj->pltrelalim - obj->pltrela;
 
-       /* Entries beyond 8192 take twice as much space. */
-       if (N > 8192)
-               N += N-8192;
+               /* Entries beyond 8192 take twice as much space. */
+               if (N > 8192)
+                       N += N-8192;
 
-       pltcall = obj->pltgot;
-       jmptab = pltcall + 18 + N * 2;
+               pltcall = obj->pltgot;
+               jmptab = pltcall + 18 + N * 2;
 
-       memcpy(pltcall, _rtld_powerpc_pltcall, PLTCALL_SIZE);
-       pltcall[1] |= ha(jmptab);
-       pltcall[2] |= l(jmptab);
+               memcpy(pltcall, _rtld_powerpc_pltcall, PLTCALL_SIZE);
+               pltcall[1] |= ha(jmptab);
+               pltcall[2] |= l(jmptab);
 
-       pltresolve = obj->pltgot + 8;
+               pltresolve = obj->pltgot + 8;
 
-       memcpy(pltresolve, _rtld_powerpc_pltresolve, PLTRESOLVE_SIZE);
-       pltresolve[0] |= ha(_rtld_bind_start);
-       pltresolve[1] |= l(_rtld_bind_start);
-       pltresolve[3] |= ha(obj);
-       pltresolve[4] |= l(obj);
+               memcpy(pltresolve, _rtld_powerpc_pltresolve, PLTRESOLVE_SIZE);
+               pltresolve[0] |= ha(_rtld_bind_bssplt_start);
+               pltresolve[1] |= l(_rtld_bind_bssplt_start);
+               pltresolve[3] |= ha(obj);
+               pltresolve[4] |= l(obj);
 
-       /*
-        * Invalidate the icache for only the code part of the PLT
-        * (and not the jump table at the end).
-        */
-       __syncicache(pltcall, (char *)jmptab - (char *)pltcall);
+               /*
+                * Invalidate the icache for only the code part of the PLT
+                * (and not the jump table at the end).
+                */
+               __syncicache(pltcall, (char *)jmptab - (char *)pltcall);
+       }
 }
 
 void
@@ -207,44 +216,52 @@
 int
 _rtld_relocate_plt_lazy(const Obj_Entry *obj)
 {
+       Elf_Addr * const pltresolve = obj->pltgot + 8;
        const Elf_Rela *rela;
        int reloff;
 
-       for (rela = obj->pltrela, reloff = 0; rela < obj->pltrelalim; rela++, reloff++) {
+       for (rela = obj->pltrela, reloff = 0;
+            rela < obj->pltrelalim;
+            rela++, reloff++) {
                Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
-               int distance;
-               Elf_Addr *pltresolve;
 
                assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT));
 
-               pltresolve = obj->pltgot + 8;
+               if (obj->gotptr != NULL) {
+                       /*
+                        * For now, simply treat then as relative.
+                        */
+                       *where += (Elf_Addr)obj->relocbase;
+               } else {
+                       int distance;
 
-               if (reloff < 32768) {
-                       /* li   r11,reloff */
-                       *where++ = 0x39600000 | reloff;
-               } else {
-                       /* lis  r11,ha(reloff) */
-                       /* addi r11,l(reloff) */
-                       *where++ = 0x3d600000 | ha(reloff);
-                       *where++ = 0x396b0000 | l(reloff);
+                       if (reloff < 32768) {
+                               /* li   r11,reloff */
+                               *where++ = 0x39600000 | reloff;
+                       } else {
+                               /* lis  r11,ha(reloff) */
+                               /* addi r11,l(reloff) */
+                               *where++ = 0x3d600000 | ha(reloff);
+                               *where++ = 0x396b0000 | l(reloff);
+                       }
+                       /* b    pltresolve */
+                       distance = (Elf_Addr)pltresolve - (Elf_Addr)where;
+                       *where++ = 0x48000000 | (distance & 0x03fffffc);
+
+                       /*
+                        * Icache invalidation is not done for each entry here
+                        * because we sync the entire code part of the PLT once
+                        * in _rtld_setup_pltgot() after all the entries have been
+                        * initialized.
+                        */
+                       /* __syncicache(where - 3, 12); */
                }
-               /* b    pltresolve */
-               distance = (Elf_Addr)pltresolve - (Elf_Addr)where;
-               *where++ = 0x48000000 | (distance & 0x03fffffc);
-
-               /*
-                * Icache invalidation is not done for each entry here
-                * because we sync the entire code part of the PLT once
-                * in _rtld_setup_pltgot() after all the entries have been
-                * initialized.
-                */
-               /* __syncicache(where - 3, 12); */
        }
 
        return 0;
 }
 
-static inline int
+static int
 _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, int reloff, Elf_Addr *tp)
 {
        Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
@@ -267,7 +284,15 @@
        rdbg(("bind now/fixup in %s --> new=%p", 
            defobj->strtab + def->st_name, (void *)value));
 
-       if (abs(distance) < 32*1024*1024) {     /* inside 32MB? */
+       if (obj->gotptr != NULL) {
+               /*
+                * For Secure-PLT we simply replace the entry in GOT with the address
+                * of the routine.
+                */
+               assert(where >= (Elf_Word *)obj->pltgot);
+               assert(where < (Elf_Word *)obj->pltgot + (obj->pltrelalim - obj->pltrela));
+               *where = value;
+       } else if (abs(distance) < 32*1024*1024) {      /* inside 32MB? */
                /* b    value   # branch directly */
                *where = 0x48000000 | (distance & 0x03fffffc);
                __syncicache(where, 4);
@@ -288,10 +313,21 @@
                        /* li   r11,reloff */
                        *where++ = 0x39600000 | reloff;
                } else {
+#ifdef notyet
+                       /* lis  r11,ha(value) */
+                       /* addi r11,l(value) */
+                       /* mtctr r11 */
+                       /* bctr */
+                       *where++ = 0x3d600000 | ha(value);
+                       *where++ = 0x396b0000 | l(value);
+                       *where++ = 0x7d6903a6;
+                       *where++ = 0x4e800420;
+#else
                        /* lis  r11,ha(reloff) */
                        /* addi r11,l(reloff) */
                        *where++ = 0x3d600000 | ha(reloff);
                        *where++ = 0x396b0000 | l(reloff);
+#endif
                }
                /* b    pltcall */
                distance = (Elf_Addr)pltcall - (Elf_Addr)where;
@@ -307,7 +343,7 @@
 caddr_t
 _rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
 {
-       const Elf_Rela *rela = obj->pltrela + reloff;
+       const Elf_Rela *rela = (const void *)((const char *)obj->pltrela + reloff);
        Elf_Addr new_value;
        int err;
 
diff -r 0c13cebb361a -r c0d7464da3ce libexec/ld.elf_so/arch/powerpc/rtld_start.S
--- a/libexec/ld.elf_so/arch/powerpc/rtld_start.S       Sun Jan 16 01:13:10 2011 +0000
+++ b/libexec/ld.elf_so/arch/powerpc/rtld_start.S       Sun Jan 16 01:22:29 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: rtld_start.S,v 1.13 2002/12/04 01:19:37 thorpej Exp $  */
+/*     $NetBSD: rtld_start.S,v 1.14 2011/01/16 01:22:29 matt Exp $     */
 
 /*-
  * Copyright (C) 1998  Tsubai Masanari
@@ -44,24 +44,22 @@
 /*     stw     %r7,28(%r1)             # cleanup       (always 0) */
        stw     %r8,32(%r1)             # ps_strings
 
-       bl      _GLOBAL_OFFSET_TABLE_-4@local
-       mflr    %r31                    # r31 = (real) GOT
-       lwz     %r28,0(%r31)            # base-relative &_DYNAMIC
-
-       bl      0f                      # lr = next instruction
-       b       _DYNAMIC@local
-0:     mflr    %r30
-       lwz     %r29,0(%r30)            # load instruction contents
-       rlwinm  %r29,%r29,0,6,29        # extract PC offset
-       add     %r3,%r29,%r30           # r3 = &_DYNAMIC
-       sub     %r28,%r3,%r28
+       bcl     20,31,1f
+1:     mflr    %r30
+       mr      %r3,%r30                # save for _DYNAMIC
+       addis   %r30,%r30,_GLOBAL_OFFSET_TABLE_-1b@ha
+       addi    %r30,%r30,_GLOBAL_OFFSET_TABLE_-1b@l
+       addis   %r3,%r3,_DYNAMIC-1b@ha  # get _DYNAMIC actual address
+       addi    %r3,%r3,_DYNAMIC-1b@l
+       lwz     %r28,0(%r30)            # get base-relative &_DYNAMIC
+       sub     %r28,%r3,%r28           # r28 = relocbase
        mr      %r4,%r28                # r4 = relocbase
-       bl      _rtld_relocate_nonplt_self@plt
+       bl      _rtld_relocate_nonplt_self
 
        lwz     %r3,16(%r1)
        addi    %r3,%r3,-12             # sp = &argv[-3]        /* XXX */
        mr      %r4,%r28                # r4 = relocbase
-       bl      _rtld@plt               # _start = _rtld(sp, relocbase)
+       bl      _rtld                   # _start = _rtld(sp, relocbase)
        mtlr    %r3
 
        lwz     %r3,12(%r1)             # argc
@@ -77,11 +75,20 @@
        li      %r0,1                   # _exit()
        sc
 
+END(_rtld_start)
 
-       .globl  _rtld_bind_start
        .globl  _rtld_bind
 
-_rtld_bind_start:
+/*
+ * secure-plt expects %r11 to be the offset to the rela entry.
+ * bss-plt expects %r11 to be index of the rela entry.
+ * So for bss-plt, we multiply the index by 12 to get the offset.
+ */
+ENTRY_NOPROFILE(_rtld_bind_bssplt_start)
+       slwi    %r11,%r11,2
+       add     %r0,%r11,%r11
+       add     %r11,%r11,%r0
+ENTRY_NOPROFILE(_rtld_bind_secureplt_start)
        stwu    %r1,-160(%r1)
 
        stw     %r0,20(%r1)
@@ -93,7 +100,7 @@



Home | Main Index | Thread Index | Old Index