diff mbox series

[uclibc-ng-devel] Static PIE support for i386, x86_64, and arm

Message ID CANP1oa2OJge+9oM01rhpc8tuGPx69Q7yKFZFrayyH-p0hv+njQ@mail.gmail.com
State Superseded
Headers show
Series [uclibc-ng-devel] Static PIE support for i386, x86_64, and arm | expand

Commit Message

linted July 14, 2022, 8:11 p.m. UTC
Hello,
I implemented support for static pie generation on i386, x86_64, and arm.

This patch adds the generation of rcrt1.o which is used by gcc when
compiling with the --static-pie flag. The main difference in rcrt1.o is
that it is required to perform dynamic relocations which would normally
occur in ldso. The new reloc_static_pie function handles parsing the elf
headers, locating the dynamic section, and performing the relocations.

Comments

Lance Fredrickson July 15, 2022, 4:45 p.m. UTC | #1
I'm super excited to see this! Was just thinking about asking the 
mailing about static pie.
Looking at the code I wonder if the depends line should look something 
like this.

depends on DOPIC && (TARGET_arm || TARGET_i386 || TARGET_x86_64)

So that only those arches can select it.

Lance
On 7/14/2022 2:11 PM, linted wrote:
> Hello,
> I implemented support for static pie generation on i386, x86_64, and arm.
>
> This patch adds the generation of rcrt1.o which is used by gcc when 
> compiling with the --static-pie flag. The main difference in rcrt1.o 
> is that it is required to perform dynamic relocations which would 
> normally occur in ldso. The new reloc_static_pie function handles 
> parsing the elf headers, locating the dynamic section, and performing 
> the relocations.
>
> _______________________________________________
> devel mailing list -- devel@uclibc-ng.org
> To unsubscribe send an email to devel-leave@uclibc-ng.org
linted July 15, 2022, 8:18 p.m. UTC | #2
That's actually a really good idea, I completely forgot to limit the
selection to supported architectures. I'll test that change right away!






On Fri, Jul 15, 2022 at 12:45 PM Lance Fredrickson <lancethepants@gmail.com>
wrote:

> I'm super excited to see this! Was just thinking about asking the
> mailing about static pie.
> Looking at the code I wonder if the depends line should look something
> like this.
>
> depends on DOPIC && (TARGET_arm || TARGET_i386 || TARGET_x86_64)
>
> So that only those arches can select it.
>
> Lance
> On 7/14/2022 2:11 PM, linted wrote:
> > Hello,
> > I implemented support for static pie generation on i386, x86_64, and arm.
> >
> > This patch adds the generation of rcrt1.o which is used by gcc when
> > compiling with the --static-pie flag. The main difference in rcrt1.o
> > is that it is required to perform dynamic relocations which would
> > normally occur in ldso. The new reloc_static_pie function handles
> > parsing the elf headers, locating the dynamic section, and performing
> > the relocations.
> >
> > _______________________________________________
> > devel mailing list -- devel@uclibc-ng.org
> > To unsubscribe send an email to devel-leave@uclibc-ng.org
>
> _______________________________________________
> devel mailing list -- devel@uclibc-ng.org
> To unsubscribe send an email to devel-leave@uclibc-ng.org
>
diff mbox series

Patch

From fcd9c50578ff5da51be6b85e1a53f207f87cd408 Mon Sep 17 00:00:00 2001
From: linted <linted@users.noreply.github.com>
Date: Tue, 12 Jul 2022 14:04:19 -0400
Subject: [PATCH] Added static pie support for i368, x86_64 and arm

Signed-off-by: linted <linted@users.noreply.github.com>
---
 Makerules                              |  5 ++++
 extra/Configs/Config.in                |  5 ++++
 libc/misc/internals/Makefile.in        |  1 +
 libc/misc/internals/reloc_static_pie.c | 39 ++++++++++++++++++++++++++
 libc/sysdeps/linux/arm/crt1.S          | 15 ++++++++++
 libc/sysdeps/linux/i386/crt1.S         | 20 +++++++++++++
 libc/sysdeps/linux/x86_64/crt1.S       | 16 ++++++++++-
 7 files changed, 100 insertions(+), 1 deletion(-)
 create mode 100644 libc/misc/internals/reloc_static_pie.c

diff --git a/Makerules b/Makerules
index fd40e6c7b..845d81897 100644
--- a/Makerules
+++ b/Makerules
@@ -405,8 +405,13 @@  else
 CRTS=$(top_builddir)lib/$(CRT).o
 endif
 
+ifeq ($(STATIC_PIE),y)
+CRTS+=$(top_builddir)lib/r$(CRT).o
+endif
+
 ASFLAGS-$(CRT).o := -DL_$(CRT)
 ASFLAGS-S$(CRT).o := $(PIEFLAG) -DL_S$(CRT)
+ASFLAGS-r$(CRT).o := $(PIEFLAG) -DL_r$(CRT)
 $(CRTS): $(top_srcdir)libc/sysdeps/linux/$(TARGET_ARCH)/$(CRT).S
 	$(compile.S)
 	$(Q)$(STRIPTOOL) -x -R .note -R .comment $@
diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in
index a58ceb265..e119c0126 100644
--- a/extra/Configs/Config.in
+++ b/extra/Configs/Config.in
@@ -301,6 +301,11 @@  config DOPIC
 	  If you wish to build all of uClibc as PIC objects, then answer Y here.
 	  If you are unsure, then you should answer N.
 
+config STATIC_PIE
+	bool "Add support for Static Position Independent Executables (PIE)"
+	default n
+	depends on DOPIC
+
 config ARCH_HAS_NO_SHARED
 	bool
 
diff --git a/libc/misc/internals/Makefile.in b/libc/misc/internals/Makefile.in
index a8e4e36f9..4a6e73d2d 100644
--- a/libc/misc/internals/Makefile.in
+++ b/libc/misc/internals/Makefile.in
@@ -34,6 +34,7 @@  libc-static-$(UCLIBC_FORMAT_FLAT_SEP_DATA) += \
 libc-static-$(UCLIBC_FORMAT_SHARED_FLAT) += \
   $(MISC_INTERNALS_OUT)/shared_flat_initfini.o \
   $(MISC_INTERNALS_OUT)/shared_flat_add_library.o
+libc-static-$(STATIC_PIE) += $(MISC_INTERNALS_OUT)/reloc_static_pie.o
 libc-shared-$(UCLIBC_FORMAT_SHARED_FLAT) += \
   $(MISC_INTERNALS_OUT)/shared_flat_initfini.os \
   $(MISC_INTERNALS_OUT)/shared_flat_add_library.os
diff --git a/libc/misc/internals/reloc_static_pie.c b/libc/misc/internals/reloc_static_pie.c
new file mode 100644
index 000000000..0736bc8a1
--- /dev/null
+++ b/libc/misc/internals/reloc_static_pie.c
@@ -0,0 +1,39 @@ 
+/* Support for relocating static PIE.
+   Copyright (C) 2017-2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <link.h>
+#include <elf.h>
+#include <dl-elf.h>
+
+void
+reloc_static_pie (ElfW(Addr) load_addr)
+{
+    /* Read our own dynamic section and fill in the info array.  */
+    ElfW(Dyn) * dyn_addr = ((void *) load_addr + elf_machine_dynamic ());
+
+    unsigned long dynamic_info[36] = {0};    
+
+    /* Use the underlying function to avoid TLS access before initialization */
+    __dl_parse_dynamic_info(dyn_addr, dynamic_info, NULL, load_addr);
+
+    ElfW(Word) relative_count = dynamic_info[DT_RELCONT_IDX];
+    ElfW(Addr) rel_addr = dynamic_info[DT_RELOC_TABLE_ADDR];
+    elf_machine_relative(load_addr, rel_addr, relative_count);
+
+    return;
+}
diff --git a/libc/sysdeps/linux/arm/crt1.S b/libc/sysdeps/linux/arm/crt1.S
index a1d7f0f23..adaf4b983 100644
--- a/libc/sysdeps/linux/arm/crt1.S
+++ b/libc/sysdeps/linux/arm/crt1.S
@@ -246,6 +246,18 @@  _start:
 	mov lr, #0
 
 #ifdef __ARCH_USE_MMU__
+#ifdef L_rcrt1
+	/* We don't need to save a1 since no dynamic linker should have run */
+	ldr a1, .L_GOT		/* Get value at .L_GOT + 0  (offset to GOT)*/
+	adr a2, .L_GOT		/* Get address of .L_GOT */
+	ldr a3, .L_GOT+16	/* get value of _start(GOT) stored in .L_GOT */
+	adr a4, _start		/* get address of _start after relocation (changes to pc - ~30 or so) */
+	add a1, a1, a2		/* calculate where the GOT is */
+	ldr a2, [a1, a3]	/* GOT + _start(GOT) = offset of _start from begin of file */
+	sub a1, a4, a2		/* current addr of _start - offset from beginning of file = load addr */
+	bl reloc_static_pie
+	mov a1, #0			/* Clean up a1 so that a random address won't get called at the end of program */
+#endif
 	/* Pop argc off the stack and save a pointer to argv */
 	ldr a2, [sp], #4
 	mov a3, sp
@@ -309,6 +321,9 @@  _start:
 	.word _fini(GOT)
 	.word _init(GOT)
 	.word main(GOT)
+#ifdef L_rcrt1
+	.word _start(GOT)
+#endif
 #endif
 #endif
 
diff --git a/libc/sysdeps/linux/i386/crt1.S b/libc/sysdeps/linux/i386/crt1.S
index 35a6552e8..4e4cef3ce 100644
--- a/libc/sysdeps/linux/i386/crt1.S
+++ b/libc/sysdeps/linux/i386/crt1.S
@@ -67,6 +67,9 @@ 
 #endif
 .type   main,%function
 .type   __uClibc_main,%function
+#ifdef L_rcrt1
+.type	reloc_static_pie,%function
+#endif
 _start:
 	/* Clear the frame pointer.  The ABI suggests this be done, to mark
 	   the outermost frame obviously.  */
@@ -100,6 +103,23 @@  _start:
 	pop %ebx
 	addl $_GLOBAL_OFFSET_TABLE_+[.-.L0],%ebx
 
+#ifdef L_rcrt1
+	/* We cannot rely on _DYNAMIC being usable here due to RELRO.
+	   Instead we calculate the load address based off a symbol
+	   that we know will exist, _start. */ 
+	pushl %ecx						/* Save ecx so it won't get clobbered */
+	pushl %ebx						/* Save ebx so it won't get clobbered */
+	xorl %ecx, %ecx					/* Clear ecx */
+	addl _start@GOT(%ebx), %ecx	/* Get the offset of _start */
+	movl _start@GOT(%ebx), %eax	/* Get the run time address of _start */
+	subl %ecx, %eax					/* Subtract to find the load address */
+	pushl %eax						/* Pass the load address */
+	call reloc_static_pie@PLT
+	popl %eax						/* Clean up from function call */
+	popl %ebx						/* Restore the GOT address */
+	popl %ecx						/* restore ecx */
+#endif
+
 	/* Push address of our own entry points to .fini and .init.  */
 	pushl _fini@GOT(%ebx)
 	pushl _init@GOT(%ebx)
diff --git a/libc/sysdeps/linux/x86_64/crt1.S b/libc/sysdeps/linux/x86_64/crt1.S
index 87777dd5d..04536d07f 100644
--- a/libc/sysdeps/linux/x86_64/crt1.S
+++ b/libc/sysdeps/linux/x86_64/crt1.S
@@ -80,6 +80,20 @@  _start:
 	   the outermost frame obviously.  */
 	xorl %ebp, %ebp
 
+#ifdef L_rcrt1
+	pushq %rdi							/* save rdi (but should be 0...) */
+	pushq %rdx							/* store rdx (rtld_fini) */
+	xorq %rcx, %rcx						/* ensure rcx is 0 */
+	addq _start@GOTPCREL(%rip), %rcx	/* get offset of _start from beginning of file */
+	movq _start@GOTPCREL(%rip), %rax	/* get run time address of _start */
+	subq %rcx, %rax						/* calculate run time load offset */
+	movq %rax, %rdi						/* load offset -> param 1 */
+	call reloc_static_pie				/* relocate dynamic addrs */
+	xorq %rax, %rax						/* cleanup */
+	popq %rdx
+	popq %rdi
+#endif
+
 	/* Extract the arguments as encoded on the stack and set up
 	   the arguments for __libc_start_main (int (*main) (int, char **, char **),
 		   int argc, char *argv,
@@ -107,7 +121,7 @@  _start:
 	   which grow downwards).  */
 	pushq %rsp
 
-#if defined(L_Scrt1)
+#if defined(L_Scrt1) || defined(L_rcrt1)
 	/* Give address for main() */
 	movq main@GOTPCREL(%rip), %rdi
 
-- 
2.34.1