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

Reply via email to