NetBSD-Bugs archive

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

Re: port-alpha/57511: ld.elf_so(1) does not support secure PLT for alpha



The attached patch addresses PR 57511 and PR 57717 by implementing
support for secureplt in ld.elf_so on alpha and flipping it back on by
default (as upstream has it) in binutils.

I also took the liberty of leaving some more explanatory comments
about what's going on in rtld_start.S, based on examination of PLT
headers actually generated by binutils.

Missing: automatic tests of programs built with `-Wl,--secureplt',
`-Wl,--no-secureplt', and `-Wl,--no-secureplt,--traditional-format',
so we make sure all three paths remain exercised.

Review welcome!  I hope my accent isn't showing through too much in
the assembly code as a non-native Alpha speaker.
# HG changeset patch
# User Taylor R Campbell <riastradh%NetBSD.org@localhost>
# Date 1744917745 0
#      Thu Apr 17 19:22:25 2025 +0000
# Branch trunk
# Node ID ff8aa06d8f252223c352e0560098b25e54967e80
# Parent  438b14ea036dd2bd2e1109f5e08f7d74109e6fae
# EXP-Topic riastradh-pr57511-alphasecureplt
ld.elf_so on alpha: Add support for secureplt.

Enable secureplt by default in binutils now that ld.elf_so can handle
it.

PR port-alpha/57511: ld.elf_so(1) does not support secure PLT for alpha
PR port-alpha/57717: Alpha linker generates LOAD segments (and
  generates warnings about them)

diff -r 438b14ea036d -r ff8aa06d8f25 doc/HACKS
--- a/doc/HACKS	Thu Apr 17 13:43:59 2025 +0000
+++ b/doc/HACKS	Thu Apr 17 19:22:25 2025 +0000
@@ -949,17 +949,6 @@ descr
 	kernel cannot execute /sbin/init.
 kcah
 
-hack	Disable secure PLT for alpha
-cdate	Fri Jul  7 08:33:25 UTC 2023
-who	rin
-port	alpha
-file	src/external/gpl3/binutils/dist/bfd/elf64-alpha.c: 1.11
-pr	port-alpha/57511
-descr
-	Temporally disable secure PLT support, introduced by
-	binutils 2.39 for us. We need its support to ld.elf_so(1).
-kcah
-
 hack	openssl: Disable ec_nistp_64_gcc_128 on aarch64eb
 cdate	Sat Jul  8 23:54:27 UTC 2023
 who	rin
diff -r 438b14ea036d -r ff8aa06d8f25 external/gpl3/binutils/dist/bfd/elf64-alpha.c
--- a/external/gpl3/binutils/dist/bfd/elf64-alpha.c	Thu Apr 17 13:43:59 2025 +0000
+++ b/external/gpl3/binutils/dist/bfd/elf64-alpha.c	Thu Apr 17 19:22:25 2025 +0000
@@ -83,7 +83,7 @@
 
 /* Set by ld emulation.  Putting this into the link_info or hash structure
    is simply working too hard.  */
-#if defined(USE_SECUREPLT) && 0 /* XXX port-alpha/57511 */
+#if defined(USE_SECUREPLT)
 bool elf64_alpha_use_secureplt = true;
 #else
 bool elf64_alpha_use_secureplt = false;
diff -r 438b14ea036d -r ff8aa06d8f25 libexec/ld.elf_so/arch/alpha/alpha_reloc.c
--- a/libexec/ld.elf_so/arch/alpha/alpha_reloc.c	Thu Apr 17 13:43:59 2025 +0000
+++ b/libexec/ld.elf_so/arch/alpha/alpha_reloc.c	Thu Apr 17 19:22:25 2025 +0000
@@ -78,6 +78,7 @@
 #define	adbg(x)		/* nothing */
 #endif
 
+void _rtld_bind_start_secureplt(void);
 void _rtld_bind_start(void);
 void _rtld_bind_start_old(void);
 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
@@ -91,7 +92,19 @@ void
 	uint32_t word0;
 
 	/*
-	 * The PLTGOT on the Alpha looks like this:
+	 * If we're using Alpha secureplt, the PLTGOT points to the
+	 * .got.plt section.  Just fill in the rtld binding stub and
+	 * we're done -- we're not writing to instruction memory, so no
+	 * imb needed.
+	 */
+	if (obj->secureplt) {
+		obj->pltgot[0] = (Elf_Addr) _rtld_bind_start_secureplt;
+		obj->pltgot[1] = (Elf_Addr) obj;
+		return;
+	}
+
+	/*
+	 * The non-secureplt PLTGOT on the Alpha looks like this:
 	 *
 	 *	PLT HEADER
 	 *	.
@@ -418,7 +431,8 @@ static inline int
 		 *
 		 * Note if the shared object uses the old PLT format, then
 		 * we cannot patch up the PLT safely, and so we skip it
-		 * in that case[*].
+		 * in that case[*].  And if the shared object has a read-only
+		 * secureplt, then we also skip it.
 		 *
 		 * [*] Actually, if we're not doing lazy-binding, then
 		 * we *can* (and do) patch up this PLT entry; the PLTGOT
@@ -426,6 +440,10 @@ static inline int
 		 * so this test will fail as it would for the new PLT
 		 * entry format.
 		 */
+		if (obj->secureplt) {
+			rdbg(("  secureplt format"));
+			goto out;
+		}
 		if (obj->pltgot[2] == (Elf_Addr) &_rtld_bind_start_old) {
 			rdbg(("  old PLT format"));
 			goto out;
diff -r 438b14ea036d -r ff8aa06d8f25 libexec/ld.elf_so/arch/alpha/rtld_start.S
--- a/libexec/ld.elf_so/arch/alpha/rtld_start.S	Thu Apr 17 13:43:59 2025 +0000
+++ b/libexec/ld.elf_so/arch/alpha/rtld_start.S	Thu Apr 17 19:22:25 2025 +0000
@@ -92,7 +92,7 @@ END(_rtld_start)
 	lda	sp, -168(sp)					;	\
 	stq	ra, 0(sp)					;	\
 	stq	v0, 8(sp)					;	\
-	stq	t0, 16(sp)					;	\
+	stq	t0, 16(sp)	/* XXX t0-t7 necessary? */	;	\
 	stq	t1, 24(sp)					;	\
 	stq	t2, 32(sp)					;	\
 	stq	t3, 40(sp)					;	\
@@ -106,7 +106,7 @@ END(_rtld_start)
 	stq	a3, 104(sp)					;	\
 	stq	a4, 112(sp)					;	\
 	stq	a5, 120(sp)					;	\
-	stq	t8, 128(sp)					;	\
+	stq	t8, 128(sp)	/* XXX t8-t11 necessary? */	;	\
 	stq	t9, 136(sp)					;	\
 	stq	t10, 144(sp)					;	\
 	stq	t11, 152(sp)					;	\
@@ -119,7 +119,7 @@ END(_rtld_start)
 	br	t0, 1f						;	\
 1:	LDGP(t0)
 
-#define	RTLD_BIND_START_EPILOGUE					\
+#define	RTLD_BIND_START_EPILOGUE(imb)					\
 	/* Move the destination address into position. */		\
 	mov	v0, pv						;	\
 									\
@@ -157,7 +157,77 @@ 1:	LDGP(t0)
 	jmp	zero, (pv)
 
 /*
- * Lazy binding entry point, called via PLT.
+ * _rtld_bind_start_secureplt(_rtld_bind_start_secureplt@pv, obj@at,
+ *     (sizeof(Elf_Rela)*index)@t11)
+ *
+ *	Lazy binding entry point, called via PLT with read-only
+ *	secureplt, when DT_ALPHA_PLTRO is set.  The PLT itself looks
+ *	something like this:
+ *
+ *	_PROCEDURE_LINKAGE_TABLE_:
+ *		subq	pv, at, t11	// t11 := pv - ent0 = 4*index
+ *		s4subq	t11, t11, t11	// t11 := 12*index
+ *		addq	t11, t11, t11	// t11 := 24*index
+ *					//      = sizeof(Elf_Rela)*index
+ *		ldah	at, ...(at)	// at  := PLTGOT
+ *		lda	at, ...(at)
+ *		ldq	pv, 0(at)	// pv  := PLTGOT[0]
+ *					//      = _rtld_bind_start_secureplt
+ *		ldq	at, 8(at)	// at  := PLTGOT[1]
+ *					//	= obj
+ *		jmp	(pv)
+ *	0:	br	at, _PROCEDURE_LINKAGE_TABLE_	// at := ent0
+ *	ent0:	br	0b		// pv - ent0 = 0 = 4*index
+ *	ent1:	br	0b		// pv - ent0 = 4 = 4*index
+ *	ent2:	br	0b		// pv - ent0 = 8 = 4*index
+ *	...
+ */
+NESTED_NOPROFILE(_rtld_bind_start_secureplt, 0, 168, ra, 0, 0)
+
+	RTLD_BIND_START_PROLOGUE
+
+	/* Set up the arguments for _rtld_bind. */
+	mov	at_reg, a0
+	mov	t11, a1
+
+	CALL(_rtld_bind)
+
+	RTLD_BIND_START_EPILOGUE(/* no text writes, so no imb */)
+
+END(_rtld_bind_start_secureplt)
+
+/*
+ * _rtld_bind_start(_rtld_bind_start@pv, &PLTGOT[2]@pv,
+ *     (ent0 + 4*(index + 1))@at)
+ *
+ *	Lazy binding entry point, called via PLT with read/write
+ *	non-secureplt, when DT_ALPHA_PLTRO is not set.  The PLT itself
+ *	looks something like this at program startup, with PLTGOT (an
+ *	array of 64-bit Elf_Addr) pointing at _PROCEDURE_LINKAGE_TABLE_
+ *	and PLTGOT[2] and PLTGOT[3] initialized by _rtld_setup_pltgot:
+ *
+ *	_PROCEDURE_LINKAGE_TABLE_:
+ *		br	pv, .Lref	// pv  := .Lref
+ *	.Lref:	ldq	pv, 12(pv)	// pv  := PLTGOT[2]
+ *					        = _rtld_bind_start
+ *		unop			// no-op for alignment
+ *		jmp	pv, (pv)	// pv  := &PLTGOT[2]
+ *		.qword	(_rtld_bind_start)	// PLTGOT[2]
+ *		.qword	(object pointer)	// PLTGOT[3]
+ *	ent0:	br	at, _PROCEDURE_LINKAGE_TABLE_
+ *		unop			// space for adjusted stub
+ *		unop			// space for adjusted stub
+ *	ent1:	br	at, _PROCEDURE_LINKAGE_TABLE_
+ *		unop
+ *		unop
+ *	ent2:	br	at, _PROCEDURE_LINKAGE_TABLE_
+ *		unop
+ *		unop
+ *	...
+ *
+ *	Note: Distance from &PLTGOT[2] (pv) to ent[0] + 4 (at) is 20
+ *	bytes, and each ent[index] + 4 (at) after that is separated by
+ *	3 instructions, i.e., 12 bytes.
  */
 NESTED_NOPROFILE(_rtld_bind_start, 0, 168, ra, 0, 0)
 
@@ -171,13 +241,37 @@ NESTED_NOPROFILE(_rtld_bind_start, 0, 16
 
 	CALL(_rtld_bind)
 
-	RTLD_BIND_START_EPILOGUE
+	RTLD_BIND_START_EPILOGUE(imb)
 
 END(_rtld_bind_start)
 
 /*
- * Lazy binding entry point, called via PLT.  This version is for the
- * old PLT entry format.
+ * _rtld_bind_start_old(&PLTGOT[2]@pv, (sizeof(Elf_Rela)*index)@at)
+ *
+ *	Lazy binding entry point, called via PLT.  This version is for
+ *	the old PLT entry format, for which the PLT looks something
+ *	like this at program startup, with PLTGOT (an array of 64-bit
+ *	Elf_Addr) pointing at _PROCEDURE_LINKAGE_TABLE_, and PLTGOT[2]
+ *	and PLTGOT[3] initialized by _rtld_setup_pltgot:
+ *
+ *	_PROCEDURE_LINKAGE_TABLE_:
+ *		br	pv, 1f		// pv  := .Lref
+ *	.Lref:	ldq	pv, 12(pv)	// pv  := PLTGOT[2]
+ *					        = _rtld_bind_start
+ *		unop			// no-op for alignment
+ *		jmp	pv, (pv)	// pv  := &PLTGOT[2]
+ *		.qword	(_rtld_bind_start)	// PLTGOT[2]
+ *		.qword	(object pointer)	// PLTGOT[3]
+ *	ent0:	ldah	at, 0		// at  := 24*0
+ *		lda	at, 0(at)	//      = sizeof(Elf_Rela)*index
+ *		br	_PROCEDURE_LINKAGE_TABLE_
+ *	ent1:	ldah	at, 0		// at  := 24*1
+ *		lda	at, 24(at)	//      = sizeof(Elf_Rela)*index
+ *		br	_PROCEDURE_LINKAGE_TABLE_
+ *	ent3:	ldah	at, 0		// at  := 24*2
+ *		lda	at, 48(at)	//      = sizeof(Elf_Rela)*index
+ *		br	_PROCEDURE_LINKAGE_TABLE_
+ *	...
  */
 NESTED_NOPROFILE(_rtld_bind_start_old, 0, 168, ra, 0, 0)
 
@@ -189,6 +283,6 @@ NESTED_NOPROFILE(_rtld_bind_start_old, 0
 
 	CALL(_rtld_bind)
 
-	RTLD_BIND_START_EPILOGUE
+	RTLD_BIND_START_EPILOGUE(imb)
 
 END(_rtld_bind_start_old)
diff -r 438b14ea036d -r ff8aa06d8f25 libexec/ld.elf_so/headers.c
--- a/libexec/ld.elf_so/headers.c	Thu Apr 17 13:43:59 2025 +0000
+++ b/libexec/ld.elf_so/headers.c	Thu Apr 17 19:22:25 2025 +0000
@@ -347,6 +347,11 @@ void
 			break;
 #endif
 
+#ifdef __alpha__
+		case DT_ALPHA_PLTRO:
+			obj->secureplt = (dynp->d_un.d_val != 0);
+			break;
+#endif
 #ifdef __mips__
 		case DT_MIPS_LOCAL_GOTNO:
 			obj->local_gotno = dynp->d_un.d_val;
diff -r 438b14ea036d -r ff8aa06d8f25 libexec/ld.elf_so/rtld.h
--- a/libexec/ld.elf_so/rtld.h	Thu Apr 17 13:43:59 2025 +0000
+++ b/libexec/ld.elf_so/rtld.h	Thu Apr 17 19:22:25 2025 +0000
@@ -218,6 +218,9 @@ typedef struct Struct_Obj_Entry {
 					   dlopen'ed */
 			phdr_loaded:1,	/* Phdr is loaded and doesn't need to
 					 * be freed. */
+#ifdef __alpha__
+			secureplt:1,	/* True if PLT is read-only format */
+#endif
 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
 			tls_static:1,	/* True if static TLS offset
 					 * has been allocated */
diff -r 438b14ea036d -r ff8aa06d8f25 sys/arch/alpha/include/elf_machdep.h
--- a/sys/arch/alpha/include/elf_machdep.h	Thu Apr 17 13:43:59 2025 +0000
+++ b/sys/arch/alpha/include/elf_machdep.h	Thu Apr 17 19:22:25 2025 +0000
@@ -74,4 +74,7 @@
 
 #define	R_TYPE(name)		__CONCAT(R_ALPHA_,name)
 
+/* Alpha dynamic tags */
+#define	DT_ALPHA_PLTRO		0x70000000	/* secure (read-only) PLT */
+
 #endif /* _ALPHA_ELF_MACHDEP_H_ */


Home | Main Index | Thread Index | Old Index