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.
This commit is contained in:
matt 2011-01-16 01:22:29 +00:00
parent 89497f8548
commit d31dbd7578
4 changed files with 131 additions and 79 deletions

View File

@ -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 @@ void _rtld_powerpc_pltresolve(Elf_Word, Elf_Word);
((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 @@ static inline int _rtld_relocate_plt_object(const Obj_Entry *,
*/
/*
* 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 @@ static inline int _rtld_relocate_plt_object(const Obj_Entry *,
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 @@ _rtld_relocate_nonplt_objects(Obj_Entry *obj)
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 @@ _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, int reloff
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 @@ _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, int reloff
/* 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 @@ _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, int reloff
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;

View File

@ -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 @@ _rtld_start:
/* 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 @@ _rtld_start:
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 @@ _rtld_bind_start:
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 @@ _rtld_bind_start:
addi %r1,%r1,160
bctr
END(_rtld_bind_start)
.globl _rtld_powerpc_pltcall
.globl _rtld_powerpc_pltresolve
@ -117,8 +125,8 @@ _rtld_powerpc_pltcall:
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

View File

@ -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>
@ -240,6 +240,11 @@ _rtld_digest_dynamic(const char *execname, Obj_Entry *obj)
&_rtld_debug;
#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 =

View File

@ -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 @@ typedef struct Struct_Obj_Entry {
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 */