Module Name: src Committed By: matt Date: Sun Jan 16 01:22:29 UTC 2011
Modified Files: src/libexec/ld.elf_so: headers.c rtld.h src/libexec/ld.elf_so/arch/powerpc: ppc_reloc.c rtld_start.S Log Message: 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. To generate a diff of this commit: cvs rdiff -u -r1.38 -r1.39 src/libexec/ld.elf_so/headers.c cvs rdiff -u -r1.97 -r1.98 src/libexec/ld.elf_so/rtld.h cvs rdiff -u -r1.45 -r1.46 src/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c cvs rdiff -u -r1.13 -r1.14 src/libexec/ld.elf_so/arch/powerpc/rtld_start.S Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/libexec/ld.elf_so/headers.c diff -u src/libexec/ld.elf_so/headers.c:1.38 src/libexec/ld.elf_so/headers.c:1.39 --- src/libexec/ld.elf_so/headers.c:1.38 Fri Dec 24 12:41:43 2010 +++ src/libexec/ld.elf_so/headers.c Sun Jan 16 01:22:29 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: headers.c,v 1.38 2010/12/24 12:41:43 skrll Exp $ */ +/* $NetBSD: headers.c,v 1.39 2011/01/16 01:22:29 matt Exp $ */ /* * Copyright 1996 John D. Polstra. @@ -40,7 +40,7 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: headers.c,v 1.38 2010/12/24 12:41:43 skrll Exp $"); +__RCSID("$NetBSD: headers.c,v 1.39 2011/01/16 01:22:29 matt Exp $"); #endif /* not lint */ #include <err.h> @@ -241,6 +241,11 @@ #endif break; #endif +#ifdef __powerpc__ + case DT_PPC_GOT: + obj->gotptr = (Elf_Addr *)(obj->relocbase + dynp->d_un.d_ptr); + break; +#endif case DT_FLAGS_1: obj->z_now = ((dynp->d_un.d_val & DF_1_BIND_NOW) != 0); Index: src/libexec/ld.elf_so/rtld.h diff -u src/libexec/ld.elf_so/rtld.h:1.97 src/libexec/ld.elf_so/rtld.h:1.98 --- src/libexec/ld.elf_so/rtld.h:1.97 Fri Dec 24 12:41:43 2010 +++ src/libexec/ld.elf_so/rtld.h Sun Jan 16 01:22:29 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: rtld.h,v 1.97 2010/12/24 12:41:43 skrll Exp $ */ +/* $NetBSD: rtld.h,v 1.98 2011/01/16 01:22:29 matt Exp $ */ /* * Copyright 1996 John D. Polstra. @@ -167,6 +167,9 @@ Elf_Word symtabno; /* Number of dynamic symbols */ Elf_Word gotsym; /* First dynamic symbol in GOT */ #endif +#ifdef __powerpc__ + Elf_Addr *gotptr; /* GOT table (secure-plt only) */ +#endif const Elf_Symindx *buckets; /* Hash table buckets array */ unsigned long unused1; /* Used to be nbuckets */ Index: src/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c diff -u src/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c:1.45 src/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c:1.46 --- src/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c:1.45 Fri Aug 6 16:33:18 2010 +++ src/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c Sun Jan 16 01:22:29 2011 @@ -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; - - /* Entries beyond 8192 take twice as much space. */ - if (N > 8192) - N += N-8192; - - pltcall = obj->pltgot; - jmptab = pltcall + 18 + N * 2; - - memcpy(pltcall, _rtld_powerpc_pltcall, PLTCALL_SIZE); - pltcall[1] |= ha(jmptab); - pltcall[2] |= l(jmptab); - - 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); - /* - * Invalidate the icache for only the code part of the PLT - * (and not the jump table at the end). + * Secure-PLT is much more sane. */ - __syncicache(pltcall, (char *)jmptab - (char *)pltcall); + 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; + + pltcall = obj->pltgot; + jmptab = pltcall + 18 + N * 2; + + memcpy(pltcall, _rtld_powerpc_pltcall, PLTCALL_SIZE); + pltcall[1] |= ha(jmptab); + pltcall[2] |= l(jmptab); + + pltresolve = obj->pltgot + 8; + + 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); + } } 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 (reloff < 32768) { - /* li r11,reloff */ - *where++ = 0x39600000 | reloff; + if (obj->gotptr != NULL) { + /* + * For now, simply treat then as relative. + */ + *where += (Elf_Addr)obj->relocbase; } 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); + int distance; - /* - * 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); */ + 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); */ + } } 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; Index: src/libexec/ld.elf_so/arch/powerpc/rtld_start.S diff -u src/libexec/ld.elf_so/arch/powerpc/rtld_start.S:1.13 src/libexec/ld.elf_so/arch/powerpc/rtld_start.S:1.14 --- src/libexec/ld.elf_so/arch/powerpc/rtld_start.S:1.13 Wed Dec 4 01:19:37 2002 +++ src/libexec/ld.elf_so/arch/powerpc/rtld_start.S Sun Jan 16 01:22:29 2011 @@ -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 @@ mr %r3,%r12 # obj mr %r4,%r11 # reloff - bl _rtld_bind@plt # _rtld_bind(obj, reloff) + bl _rtld_bind # _rtld_bind(obj, reloff) mtctr %r3 lmw %r3,24(%r1) # load r3-r31 @@ -105,6 +112,7 @@ addi %r1,%r1,160 bctr +END(_rtld_bind_start) .globl _rtld_powerpc_pltcall .globl _rtld_powerpc_pltresolve @@ -117,8 +125,8 @@ bctr _rtld_powerpc_pltresolve: - lis %r12,0 # lis 12,_rtld_bind_start@ha - addi %r12,%r12,0 # addi 12,12,_rtld_bind_start@l + lis %r12,0 # lis 12,_rtld_bind_bssplt_start@ha + addi %r12,%r12,0 # addi 12,12,_rtld_bind_bssplt_start@l mtctr %r12 lis %r12,0 # lis 12,obj@ha addi %r12,%r12,0 # addi 12,12,obj@l