diff mbox series

[uclibc-ng-devel,1/1] powerpc: fix PIE/PIC builds with newer gcc/binutils which use secureplt by default

Message ID 20210528065958.3965167-2-yann@sionneau.net
State Superseded
Headers show
Series V3 fix powerpc PIE/PIC + secure-plt builds | expand

Commit Message

Yann Sionneau May 28, 2021, 6:59 a.m. UTC
This patch fixes segfault of all user space processes (including init, which caused a panic) on recent buildroot powerpc32 builds.

The issue has been reported by Romain Naour in this thread: https://mailman.uclibc-ng.org/pipermail/devel/2021-May/002068.html

Recent buildroot toolchain enables secure PLT in powerpc gcc.
The latter will then supply -msecure-plt to gas invocations by default.
Recent buildroot also enables PIE by default.

For the secure PLT to work in PIC, the r30 register needs to point to the GOT.
Old "bss plt" was just a one-instruction-wide PLT slot, pointed-to by a R_PPC_JMP_SLOT relocation, which was written on-the-fly to contain a branch instruction to the correct address. It therefore had to stay writable+executable, which you generally want to avoid for security reasons.
New secure PLT only contains read-only code which loads the branch address from the writable GOT.

Note: secure PLT without PIC does not need r30 to be set. Because offset between plt stub code and got is known at link-time. In this case the PLT entry looks like:
1009b3e0 <__uClibc_main@plt>:
1009b3e0:       3d 60 10 0e     lis     r11,4110
1009b3e4:       81 6b 03 74     lwz     r11,884(r11)
1009b3e8:       7d 69 03 a6     mtctr   r11
1009b3ec:       4e 80 04 20     bctr

Whereas secure PLT with PIC - offset between plt and got is unknown at link-time - looks like this:
000af800 <00000000.plt_pic32.__uClibc_main>:
   af800:       81 7e 03 80     lwz     r11,896(r30)
   af804:       7d 69 03 a6     mtctr   r11
   af808:       4e 80 04 20     bctr
   af80c:       60 00 00 00     nop

Signed-off-by: Yann Sionneau <yann@sionneau.net>
---
 Rules.mak                         | 3 ++-
 ldso/ldso/powerpc/dl-startup.h    | 3 +++
 libc/sysdeps/linux/powerpc/crt1.S | 4 ++++
 3 files changed, 9 insertions(+), 1 deletion(-)

Comments

Romain Naour May 31, 2021, 8:10 p.m. UTC | #1
Hello Yann,

Le 28/05/2021 à 08:59, Yann Sionneau a écrit :
> This patch fixes segfault of all user space processes (including init, which caused a panic) on recent buildroot powerpc32 builds.
> 
> The issue has been reported by Romain Naour in this thread: https://mailman.uclibc-ng.org/pipermail/devel/2021-May/002068.html
> 
> Recent buildroot toolchain enables secure PLT in powerpc gcc.
> The latter will then supply -msecure-plt to gas invocations by default.
> Recent buildroot also enables PIE by default.
> 
> For the secure PLT to work in PIC, the r30 register needs to point to the GOT.
> Old "bss plt" was just a one-instruction-wide PLT slot, pointed-to by a R_PPC_JMP_SLOT relocation, which was written on-the-fly to contain a branch instruction to the correct address. It therefore had to stay writable+executable, which you generally want to avoid for security reasons.
> New secure PLT only contains read-only code which loads the branch address from the writable GOT.
> 
> Note: secure PLT without PIC does not need r30 to be set. Because offset between plt stub code and got is known at link-time. In this case the PLT entry looks like:
> 1009b3e0 <__uClibc_main@plt>:
> 1009b3e0:       3d 60 10 0e     lis     r11,4110
> 1009b3e4:       81 6b 03 74     lwz     r11,884(r11)
> 1009b3e8:       7d 69 03 a6     mtctr   r11
> 1009b3ec:       4e 80 04 20     bctr
> 
> Whereas secure PLT with PIC - offset between plt and got is unknown at link-time - looks like this:
> 000af800 <00000000.plt_pic32.__uClibc_main>:
>    af800:       81 7e 03 80     lwz     r11,896(r30)
>    af804:       7d 69 03 a6     mtctr   r11
>    af808:       4e 80 04 20     bctr
>    af80c:       60 00 00 00     nop
> 
> Signed-off-by: Yann Sionneau <yann@sionneau.net>
> ---
>  Rules.mak                         | 3 ++-
>  ldso/ldso/powerpc/dl-startup.h    | 3 +++
>  libc/sysdeps/linux/powerpc/crt1.S | 4 ++++
>  3 files changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/Rules.mak b/Rules.mak
> index 1fa09be23..c789aefd3 100644
> --- a/Rules.mak
> +++ b/Rules.mak
> @@ -483,9 +483,10 @@ ifeq ($(TARGET_ARCH),powerpc)
>  	PICFLAG:=-fpic
>  	PIEFLAG_NAME:=-fpie
>  	PPC_HAS_REL16:=$(shell printf "\t.text\n\taddis 11,30,_GLOBAL_OFFSET_TABLE_-.@ha\n" | $(CC) -c -x assembler -o /dev/null -  2> /dev/null && echo -n y || echo -n n)
> +	PPC_HAS_SECUREPLT:=$(shell $(CC) --verbose 2>&1 | grep -- --enable-secureplt > /dev/null && echo -n y || echo -n n)

I'm not sure if this is the recommended way to check for a compiler support but
I don't have a better proposal.

> +	CPU_CFLAGS-$(PPC_HAS_SECUREPLT) += -DPPC_HAS_SECUREPLT
>  	CPU_CFLAGS-$(PPC_HAS_REL16)+= -DHAVE_ASM_PPC_REL16
>  	CPU_CFLAGS-$(CONFIG_E500) += "-D__NO_MATH_INLINES"
> -
>  endif
>  
>  ifeq ($(TARGET_ARCH),bfin)
> diff --git a/ldso/ldso/powerpc/dl-startup.h b/ldso/ldso/powerpc/dl-startup.h
> index 8b2a517e2..7749395eb 100644
> --- a/ldso/ldso/powerpc/dl-startup.h
> +++ b/ldso/ldso/powerpc/dl-startup.h
> @@ -25,6 +25,9 @@ __asm__(
>  #else
>      "	bl	_GLOBAL_OFFSET_TABLE_-4@local\n" /*  Put our GOT pointer in r31, */
>      "	mflr	31\n"
> +#endif
> +#ifdef PPC_HAS_SECUREPLT
> +    "   mr      30,31\n"
>  #endif
>      "	addi	1,1,16\n" /* Restore SP */
>      "	lwz	7,_dl_skip_args@got(31)\n" /* load EA of _dl_skip_args */
> diff --git a/libc/sysdeps/linux/powerpc/crt1.S b/libc/sysdeps/linux/powerpc/crt1.S
> index 27bfc5a5a..3f5d056c0 100644
> --- a/libc/sysdeps/linux/powerpc/crt1.S
> +++ b/libc/sysdeps/linux/powerpc/crt1.S
> @@ -56,6 +56,10 @@ _start:
>  # else
>  	bl	_GLOBAL_OFFSET_TABLE_-4@local
>  	mflr	r31
> +# endif
> +	/* in PIC/PIE, plt stubs need r30 to point to the GOT if using secure-plt */
> +# ifdef PPC_HAS_SECUREPLT
> +	mr	30,31

We need this instruction only for PPC_HAS_SECUREPLT and PIC/PIE enabled by
default. But this is enabled as soon as PPC_HAS_SECUREPLT is enabled, so the
register copy is useless if PIC/PIE is not used.

As is, this patch fix the issue!

Tested-by: Romain Naour <romain.naour@gmail.com>

Best regards,
Romain


>  # endif
>  #endif
>  	/* Set up the small data pointer in r13.  */
>
diff mbox series

Patch

diff --git a/Rules.mak b/Rules.mak
index 1fa09be23..c789aefd3 100644
--- a/Rules.mak
+++ b/Rules.mak
@@ -483,9 +483,10 @@  ifeq ($(TARGET_ARCH),powerpc)
 	PICFLAG:=-fpic
 	PIEFLAG_NAME:=-fpie
 	PPC_HAS_REL16:=$(shell printf "\t.text\n\taddis 11,30,_GLOBAL_OFFSET_TABLE_-.@ha\n" | $(CC) -c -x assembler -o /dev/null -  2> /dev/null && echo -n y || echo -n n)
+	PPC_HAS_SECUREPLT:=$(shell $(CC) --verbose 2>&1 | grep -- --enable-secureplt > /dev/null && echo -n y || echo -n n)
+	CPU_CFLAGS-$(PPC_HAS_SECUREPLT) += -DPPC_HAS_SECUREPLT
 	CPU_CFLAGS-$(PPC_HAS_REL16)+= -DHAVE_ASM_PPC_REL16
 	CPU_CFLAGS-$(CONFIG_E500) += "-D__NO_MATH_INLINES"
-
 endif
 
 ifeq ($(TARGET_ARCH),bfin)
diff --git a/ldso/ldso/powerpc/dl-startup.h b/ldso/ldso/powerpc/dl-startup.h
index 8b2a517e2..7749395eb 100644
--- a/ldso/ldso/powerpc/dl-startup.h
+++ b/ldso/ldso/powerpc/dl-startup.h
@@ -25,6 +25,9 @@  __asm__(
 #else
     "	bl	_GLOBAL_OFFSET_TABLE_-4@local\n" /*  Put our GOT pointer in r31, */
     "	mflr	31\n"
+#endif
+#ifdef PPC_HAS_SECUREPLT
+    "   mr      30,31\n"
 #endif
     "	addi	1,1,16\n" /* Restore SP */
     "	lwz	7,_dl_skip_args@got(31)\n" /* load EA of _dl_skip_args */
diff --git a/libc/sysdeps/linux/powerpc/crt1.S b/libc/sysdeps/linux/powerpc/crt1.S
index 27bfc5a5a..3f5d056c0 100644
--- a/libc/sysdeps/linux/powerpc/crt1.S
+++ b/libc/sysdeps/linux/powerpc/crt1.S
@@ -56,6 +56,10 @@  _start:
 # else
 	bl	_GLOBAL_OFFSET_TABLE_-4@local
 	mflr	r31
+# endif
+	/* in PIC/PIE, plt stubs need r30 to point to the GOT if using secure-plt */
+# ifdef PPC_HAS_SECUREPLT
+	mr	30,31
 # endif
 #endif
 	/* Set up the small data pointer in r13.  */