diff --git a/ChangeLog b/ChangeLog index 852043e5211..e9f203fd372 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,75 @@ +2017-12-15 H.J. Lu + + [BZ #19574] + * INSTALL: Regenerated. + * Makeconfig (real-static-start-installed-name): New. + (pic-default): Updated for --enable-static-pie. + (pie-default): New for --enable-static-pie. + (default-pie-ldflag): Likewise. + (+link-static-before-libc): Replace $(DEFAULT-LDFLAGS-$(@F)) + with $(if $($(@F)-no-pie),$(no-pie-ldflag),$(default-pie-ldflag)). + Replace $(static-start-installed-name) with + $(real-static-start-installed-name). + (+prectorT): Updated for --enable-static-pie. + (+postctorT): Likewise. + (CFLAGS-.o): Add $(pie-default). + (CFLAGS-.op): Likewise. + * NEWS: Mention --enable-static-pie. + * config.h.in (ENABLE_STATIC_PIE): New. + * configure.ac (--enable-static-pie): New configure option. + (have-no-dynamic-linker): New LIBC_CONFIG_VAR. + (have-static-pie): Likewise. + Enable static PIE if linker supports --no-dynamic-linker. + (ENABLE_STATIC_PIE): New AC_DEFINE. + (enable-static-pie): New LIBC_CONFIG_VAR. + * configure: Regenerated. + * csu/Makefile (omit-deps): Add r$(start-installed-name) and + gr$(start-installed-name) for --enable-static-pie. + (extra-objs): Likewise. + (install-lib): Likewise. + (extra-objs): Add static-reloc.o and static-reloc.os + ($(objpfx)$(start-installed-name)): Also depend on + $(objpfx)static-reloc.o. + ($(objpfx)r$(start-installed-name)): New. + ($(objpfx)g$(start-installed-name)): Also depend on + $(objpfx)static-reloc.os. + ($(objpfx)gr$(start-installed-name)): New. + * csu/libc-start.c (LIBC_START_MAIN): Call _dl_relocate_static_pie + in libc.a. + * csu/libc-tls.c (__libc_setup_tls): Add main_map->l_addr to + initimage. + * csu/static-reloc.c: New file. + * elf/Makefile (routines): Add dl-reloc-static-pie. + (elide-routines.os): Likewise. + (DEFAULT-LDFLAGS-tst-tls1-static-non-pie): Removed. + (tst-tls1-static-non-pie-no-pie): New. + * elf/dl-reloc-static-pie.c: New file. + * elf/dl-support.c (_dl_get_dl_main_map): New function. + * elf/dynamic-link.h (ELF_DURING_STARTUP): Also check + STATIC_PIE_BOOTSTRAP. + * elf/get-dynamic-info.h (elf_get_dynamic_info): Likewise. + * gmon/Makefile (tests): Add tst-gmon-static-pie. + (tests-static): Likewise. + (DEFAULT-LDFLAGS-tst-gmon-static): Removed. + (tst-gmon-static-no-pie): New. + (CFLAGS-tst-gmon-static-pie.c): Likewise. + (CRT-tst-gmon-static-pie): Likewise. + (tst-gmon-static-pie-ENV): Likewise. + (tests-special): Likewise. + ($(objpfx)tst-gmon-static-pie.out): Likewise. + (clean-tst-gmon-static-pie-data): Likewise. + ($(objpfx)tst-gmon-static-pie-gprof.out): Likewise. + * gmon/tst-gmon-static-pie.c: New file. + * manual/install.texi: Document --enable-static-pie. + * sysdeps/generic/ldsodefs.h (_dl_relocate_static_pie): New. + (_dl_get_dl_main_map): Likewise. + * sysdeps/i386/configure.ac: Check if linker supports static PIE. + * sysdeps/x86_64/configure.ac: Likewise. + * sysdeps/i386/configure: Regenerated. + * sysdeps/x86_64/configure: Likewise. + * sysdeps/mips/Makefile (ASFLAGS-.o): Add $(pie-default). + (ASFLAGS-.op): Likewise. + 2017-12-15 Joseph Myers * io/Makefile (tst-open-tmpfile-ARGS): New variable. diff --git a/INSTALL b/INSTALL index 80306de35c5..9a1404bd3c1 100644 --- a/INSTALL +++ b/INSTALL @@ -86,6 +86,15 @@ will be used, and CFLAGS sets optimization options for the compiler. systems support shared libraries; you need ELF support and (currently) the GNU linker. +'--enable-static-pie' + Enable static position independent executable (static PIE) support. + Static PIE is similar to static executable, but can be loaded at + any address without help from a dynamic linker. All static + programs as well as static tests are built as static PIE, except + for those marked with no-pie. The resulting glibc can be used with + the GCC option, -static-pie, which is available with GCC 8 or + above, to create static PIE. + '--disable-profile' Don't build libraries with profiling information. You may want to use this option if you don't plan to do profiling. diff --git a/Makeconfig b/Makeconfig index 1346109ac0a..99cc136bfa3 100644 --- a/Makeconfig +++ b/Makeconfig @@ -352,6 +352,14 @@ ifndef static-start-installed-name static-start-installed-name = $(start-installed-name) endif +ifeq (yes,$(enable-static-pie)) +# Link with rcrt1.o, instead of crt1.o, to call _dl_relocate_static_pie +# to relocate static PIE. +real-static-start-installed-name = r$(static-start-installed-name) +else +real-static-start-installed-name = $(static-start-installed-name) +endif + ifeq (yesyes,$(build-shared)$(have-z-combreloc)) combreloc-LDFLAGS = -Wl,-z,combreloc LDFLAGS.so += $(combreloc-LDFLAGS) @@ -371,6 +379,20 @@ LDFLAGS.so += $(hashstyle-LDFLAGS) LDFLAGS-rtld += $(hashstyle-LDFLAGS) endif +ifeq (yes,$(enable-static-pie)) +pic-default = -DPIC +# Compile libc.a and libc_p.a with -fPIE/-fpie for static PIE. +pie-default = $(pie-ccflag) +ifeq (yes,$(have-static-pie)) +default-pie-ldflag = -static-pie +else +# Static PIE can't have dynamic relocations in read-only segments since +# static PIE is mapped into memory by kernel. --eh-frame-hdr is needed +# for PIE to support exception. +default-pie-ldflag = -Wl,-pie,--no-dynamic-linker,--eh-frame-hdr,-z,text +endif +endif + # If lazy relocations are disabled, add the -z now flag. Use # LDFLAGS-lib.so instead of LDFLAGS.so, to avoid adding the flag to # test modules. @@ -420,9 +442,9 @@ endif # Command for statically linking programs with the C library. ifndef +link-static +link-static-before-libc = $(CC) -nostdlib -nostartfiles -static -o $@ \ - $(DEFAULT-LDFLAGS-$(@F)) \ + $(if $($(@F)-no-pie),$(no-pie-ldflag),$(default-pie-ldflag)) \ $(sysdep-LDFLAGS) $(LDFLAGS) $(LDFLAGS-$(@F)) \ - $(firstword $(CRT-$(@F)) $(csu-objpfx)$(static-start-installed-name)) \ + $(firstword $(CRT-$(@F)) $(csu-objpfx)$(real-static-start-installed-name)) \ $(+preinit) $(+prectorT) \ $(filter-out $(addprefix $(csu-objpfx),start.o \ $(start-installed-name))\ @@ -637,8 +659,14 @@ endif +prectorS = `$(CC) $(sysdep-LDFLAGS) --print-file-name=crtbeginS.o` +postctorS = `$(CC) $(sysdep-LDFLAGS) --print-file-name=crtendS.o` # Variants of the two previous definitions for statically linking programs. +ifeq (yes,$(enable-static-pie)) +# Static PIE must use PIE variants. ++prectorT = $(+prectorS) ++postctorT = $(+postctorS) +else +prectorT = `$(CC) $(sysdep-LDFLAGS) --print-file-name=crtbeginT.o` +postctorT = `$(CC) $(sysdep-LDFLAGS) --print-file-name=crtend.o` +endif csu-objpfx = $(common-objpfx)csu/ elf-objpfx = $(common-objpfx)elf/ @@ -959,7 +987,8 @@ libtypes = $(foreach o,$(object-suffixes-for-libc),$(libtype$o)) all-object-suffixes := .o .os .oS object-suffixes := CPPFLAGS-.o = $(pic-default) -CFLAGS-.o = $(filter %frame-pointer,$(+cflags)) +# libc.a must be compiled with -fPIE/-fpie for static PIE. +CFLAGS-.o = $(filter %frame-pointer,$(+cflags)) $(pie-default) libtype.o := lib%.a object-suffixes += .o ifeq (yes,$(build-shared)) @@ -984,7 +1013,8 @@ ifeq (yes,$(build-profile)) all-object-suffixes += .op object-suffixes += .op CPPFLAGS-.op = -DPROF $(pic-default) -CFLAGS-.op = -pg +# libc_p.a must be compiled with -fPIE/-fpie for static PIE. +CFLAGS-.op = -pg $(pie-default) libtype.op = lib%_p.a endif diff --git a/NEWS b/NEWS index c5607c855fb..61fed654d89 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,15 @@ Version 2.27 Major new features: +* The GNU C Library can now be compiled with support for building static + PIE executables (See --enable-static-pie in INSTALL). These static PIE + exectuables are like static executables but can be loaded at any address + and provide additional security hardening benefits at the cost of some + memory and performance. When the library is built with --enable-static-pie + the resulting libc.a is usable with GCC 8 and above to create static PIE + executables using the GCC option '-static-pie'. This feature is currently + supported on i386, x86_64 and x32. + * Optimized x86-64 asin, atan2, exp, expf, log, pow, atan, sin, cosf, sinf and tan with FMA, contributed by Arjan van de Ven and H.J. Lu from Intel. diff --git a/config.h.in b/config.h.in index 3c91d597ff4..d928e7dd867 100644 --- a/config.h.in +++ b/config.h.in @@ -238,6 +238,9 @@ /* Build glibc with tunables support. */ #define HAVE_TUNABLES 0 +/* Define if static PIE is enabled. */ +#define ENABLE_STATIC_PIE 0 + /* Some compiler options may now allow to use ebp in __asm__ (used mainly in i386 6 argument syscall issue). */ #define CAN_USE_REGISTER_ASM_EBP 0 diff --git a/configure b/configure index 4a857068622..9da9fb2736f 100755 --- a/configure +++ b/configure @@ -763,6 +763,7 @@ with_default_link enable_sanity_checks enable_shared enable_profile +enable_static_pie enable_timezone_tools enable_hardcoded_path_in_tests enable_stackguard_randomization @@ -1417,6 +1418,8 @@ Optional Features: in special situations) [default=yes] --enable-shared build shared library [default=yes if GNU ld] --enable-profile build profiled library [default=no] + --enable-static-pie enable static PIE support and use it in the + testsuite [default=no] --disable-timezone-tools do not install timezone tools [default=install] --enable-hardcoded-path-in-tests @@ -3350,6 +3353,13 @@ else profile=no fi +# Check whether --enable-static-pie was given. +if test "${enable_static_pie+set}" = set; then : + enableval=$enable_static_pie; static_pie=$enableval +else + static_pie=no +fi + # Check whether --enable-timezone-tools was given. if test "${enable_timezone_tools+set}" = set; then : enableval=$enable_timezone_tools; enable_timezone_tools=$enableval @@ -5806,6 +5816,62 @@ fi $as_echo "$libc_linker_feature" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker that supports --no-dynamic-linker" >&5 +$as_echo_n "checking for linker that supports --no-dynamic-linker... " >&6; } +libc_linker_feature=no +if test x"$gnu_ld" = x"yes"; then + libc_linker_check=`$LD -v --help 2>/dev/null | grep "\--no-dynamic-linker"` + if test -n "$libc_linker_check"; then + cat > conftest.c <&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } + then + libc_linker_feature=yes + fi + rm -f conftest* + fi +fi +if test $libc_linker_feature = yes; then + libc_cv_no_dynamic_linker=yes +else + libc_cv_no_dynamic_linker=no +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_linker_feature" >&5 +$as_echo "$libc_linker_feature" >&6; } +config_vars="$config_vars +have-no-dynamic-linker = $libc_cv_no_dynamic_linker" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -static-pie" >&5 +$as_echo_n "checking for -static-pie... " >&6; } +if ${libc_cv_static_pie+:} false; then : + $as_echo_n "(cached) " >&6 +else + if { ac_try='${CC-cc} -static-pie -xc /dev/null -S -o /dev/null' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + libc_cv_static_pie=yes +else + libc_cv_static_pie=no +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_static_pie" >&5 +$as_echo "$libc_cv_static_pie" >&6; } +config_vars="$config_vars +have-static-pie = $libc_cv_static_pie" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fpie" >&5 $as_echo_n "checking for -fpie... " >&6; } if ${libc_cv_fpie+:} false; then : @@ -6705,6 +6771,19 @@ $as_echo "$libc_cv_pie_default" >&6; } libc_cv_multidir=`${CC-cc} $CFLAGS $CPPFLAGS -print-multi-directory` +if test "$static_pie" = yes; then + # The linker must support --no-dynamic-linker. + if test "$libc_cv_no_dynamic_linker" != yes; then + as_fn_error $? "linker support for --no-dynamic-linker needed" "$LINENO" 5 + fi + # Default to PIE. + libc_cv_pie_default=yes + $as_echo "#define ENABLE_STATIC_PIE 1" >>confdefs.h + +fi +config_vars="$config_vars +enable-static-pie = $static_pie" + diff --git a/configure.ac b/configure.ac index edf662715b6..8e4006f0a99 100644 --- a/configure.ac +++ b/configure.ac @@ -170,6 +170,11 @@ AC_ARG_ENABLE([profile], [build profiled library @<:@default=no@:>@]), [profile=$enableval], [profile=no]) +AC_ARG_ENABLE([static-pie], + AC_HELP_STRING([--enable-static-pie], + [enable static PIE support and use it in the testsuite @<:@default=no@:>@]), + [static_pie=$enableval], + [static_pie=no]) AC_ARG_ENABLE([timezone-tools], AC_HELP_STRING([--disable-timezone-tools], [do not install timezone tools @<:@default=install@:>@]), @@ -1287,6 +1292,19 @@ LIBC_LINKER_FEATURE([-z execstack], [-Wl,-z,execstack], [libc_cv_z_execstack=yes], [libc_cv_z_execstack=no]) AC_SUBST(libc_cv_z_execstack) +LIBC_LINKER_FEATURE([--no-dynamic-linker], + [-Wl,--no-dynamic-linker], + [libc_cv_no_dynamic_linker=yes], + [libc_cv_no_dynamic_linker=no]) +LIBC_CONFIG_VAR([have-no-dynamic-linker], [$libc_cv_no_dynamic_linker]) + +AC_CACHE_CHECK(for -static-pie, libc_cv_static_pie, [dnl +LIBC_TRY_CC_OPTION([-static-pie], + [libc_cv_static_pie=yes], + [libc_cv_static_pie=no]) +]) +LIBC_CONFIG_VAR([have-static-pie], [$libc_cv_static_pie]) + AC_CACHE_CHECK(for -fpie, libc_cv_fpie, [dnl LIBC_TRY_CC_OPTION([-fpie], [libc_cv_fpie=yes], [libc_cv_fpie=no]) ]) @@ -1794,6 +1812,17 @@ AC_SUBST(libc_cv_pie_default) libc_cv_multidir=`${CC-cc} $CFLAGS $CPPFLAGS -print-multi-directory` AC_SUBST(libc_cv_multidir) +if test "$static_pie" = yes; then + # The linker must support --no-dynamic-linker. + if test "$libc_cv_no_dynamic_linker" != yes; then + AC_MSG_ERROR([linker support for --no-dynamic-linker needed]) + fi + # Default to PIE. + libc_cv_pie_default=yes + AC_DEFINE(ENABLE_STATIC_PIE) +fi +LIBC_CONFIG_VAR([enable-static-pie], [$static_pie]) + AC_SUBST(profile) AC_SUBST(static_nss) diff --git a/csu/Makefile b/csu/Makefile index e42a32b3eb3..86b95a97597 100644 --- a/csu/Makefile +++ b/csu/Makefile @@ -37,7 +37,9 @@ extra-objs = start.o \ S$(start-installed-name) omit-deps = $(patsubst %.o,%,$(start-installed-name) g$(start-installed-name) \ b$(start-installed-name) $(csu-dummies) \ - S$(start-installed-name)) + S$(start-installed-name) \ + r$(start-installed-name) \ + gr$(start-installed-name)) install-lib = $(start-installed-name) g$(start-installed-name) $(csu-dummies) # No tests are allowed in the csu/ subdirectory because the startup @@ -60,10 +62,17 @@ extra-objs += gmon-start.o endif ifneq ($(start-installed-name),$(static-start-installed-name)) +# FIXME: Only Hurd defines static-start-installed-name. Hurd needs to +# provide special rules to support static PIE. extra-objs += $(static-start-installed-name) g$(static-start-installed-name) omit-deps += $(patsubst %.o,%,$(static-start-installed-name) \ g$(static-start-installed-name)) install-lib += $(static-start-installed-name) g$(static-start-installed-name) +else +ifeq (yes,$(enable-static-pie)) +extra-objs += r$(start-installed-name) gr$(start-installed-name) +install-lib += r$(start-installed-name) gr$(start-installed-name) +endif endif before-compile += $(objpfx)abi-tag.h @@ -82,7 +91,10 @@ multilib-extra-objs = $(addprefix $(multidir)/, $(install-lib)) extra-objs += $(multilib-extra-objs) endif -extra-objs += abi-note.o init.o +extra-objs += abi-note.o init.o static-reloc.o +ifeq (yes,$(build-shared)) +extra-objs += static-reloc.os +endif asm-CPPFLAGS += -I$(objpfx). # Enable unwinding so backtrace unwinds to __libc_start_main @@ -101,6 +113,9 @@ ifndef start-installed-name-rule # We link the ELF startfile along with a SHT_NOTE section indicating # the kernel ABI the binaries linked with this library will require. $(objpfx)$(start-installed-name): $(objpfx)start.o $(objpfx)abi-note.o \ + $(objpfx)init.o $(objpfx)static-reloc.o + $(link-relocatable) +$(objpfx)r$(start-installed-name): $(objpfx)start.o $(objpfx)abi-note.o \ $(objpfx)init.o $(link-relocatable) $(objpfx)S$(start-installed-name): $(objpfx)start.os $(objpfx)abi-note.o \ @@ -113,7 +128,10 @@ endif # to turn on profiling code at startup. ifeq (yes,$(build-shared)) $(objpfx)g$(start-installed-name): \ - $(objpfx)g%: $(objpfx)S% $(objpfx)gmon-start.os + $(objpfx)g%: $(objpfx)S% $(objpfx)gmon-start.os $(objpfx)static-reloc.os + $(link-relocatable) +$(objpfx)gr$(start-installed-name): \ + $(objpfx)gr%: $(objpfx)r% $(objpfx)gmon-start.o $(link-relocatable) ifneq ($(start-installed-name),$(static-start-installed-name)) $(objpfx)g$(static-start-installed-name): \ diff --git a/csu/libc-start.c b/csu/libc-start.c index 24c63be02f0..34dd1252605 100644 --- a/csu/libc-start.c +++ b/csu/libc-start.c @@ -141,6 +141,8 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), __libc_multiple_libcs = &_dl_starting_up && !_dl_starting_up; #ifndef SHARED + _dl_relocate_static_pie (); + char **ev = &argv[argc + 1]; __environ = ev; diff --git a/csu/libc-tls.c b/csu/libc-tls.c index 00138eb43ad..1f8ddaf5430 100644 --- a/csu/libc-tls.c +++ b/csu/libc-tls.c @@ -114,6 +114,8 @@ __libc_setup_tls (void) size_t tcb_offset; const ElfW(Phdr) *phdr; + struct link_map *main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded; + /* Look through the TLS segment if there is any. */ if (_dl_phdr != NULL) for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr) @@ -122,7 +124,7 @@ __libc_setup_tls (void) /* Remember the values we need. */ memsz = phdr->p_memsz; filesz = phdr->p_filesz; - initimage = (void *) phdr->p_vaddr; + initimage = (void *) phdr->p_vaddr + main_map->l_addr; align = phdr->p_align; if (phdr->p_align > max_align) max_align = phdr->p_align; @@ -163,8 +165,6 @@ __libc_setup_tls (void) _dl_static_dtv[0].counter = (sizeof (_dl_static_dtv) / sizeof (_dl_static_dtv[0])) - 2; // _dl_static_dtv[1].counter = 0; would be needed if not already done - struct link_map *main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded; - /* Initialize the TLS block. */ #if TLS_TCB_AT_TP _dl_static_dtv[2].pointer.val = ((char *) tlsblock + tcb_offset diff --git a/csu/static-reloc.c b/csu/static-reloc.c new file mode 100644 index 00000000000..37be72c8ea8 --- /dev/null +++ b/csu/static-reloc.c @@ -0,0 +1,26 @@ +/* Special startup support for non-PIE static executables. + Copyright (C) 2017 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 + . */ + +#if ENABLE_STATIC_PIE +#include + +void +_dl_relocate_static_pie (void) +{ +} +#endif diff --git a/elf/Makefile b/elf/Makefile index 85635550796..47c3d23ed8a 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -24,7 +24,8 @@ include ../Makeconfig headers = elf.h bits/elfclass.h link.h bits/link.h routines = $(all-dl-routines) dl-support dl-iteratephdr \ dl-addr dl-addr-obj enbl-secure dl-profstub \ - dl-origin dl-libc dl-sym dl-sysdep dl-error + dl-origin dl-libc dl-sym dl-sysdep dl-error \ + dl-reloc-static-pie # The core dynamic linking functions are in libc for the static and # profiled libraries. @@ -52,7 +53,7 @@ endif all-dl-routines = $(dl-routines) $(sysdep-dl-routines) # But they are absent from the shared libc, because that code is in ld.so. elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \ - dl-sysdep dl-exception + dl-sysdep dl-exception dl-reloc-static-pie shared-only-routines += dl-caller # ld.so uses those routines, plus some special stuff for being the program @@ -153,7 +154,7 @@ tests-static-internal := tst-tls1-static tst-tls2-static \ tst-tls1-static-non-pie CRT-tst-tls1-static-non-pie := $(csu-objpfx)crt1.o -DEFAULT-LDFLAGS-tst-tls1-static-non-pie = $(no-pie-ldflag) +tst-tls1-static-non-pie-no-pie = yes tests := tst-tls9 tst-leaks1 \ tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 \ diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c new file mode 100644 index 00000000000..6e43aea76ab --- /dev/null +++ b/elf/dl-reloc-static-pie.c @@ -0,0 +1,52 @@ +/* Support for relocating static PIE. + Copyright (C) 2017 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 + . */ + +#if ENABLE_STATIC_PIE +#include +#include +#include "dynamic-link.h" + +/* Relocate static executable with PIE. */ + +void +_dl_relocate_static_pie (void) +{ + struct link_map *main_map = _dl_get_dl_main_map (); + +# define STATIC_PIE_BOOTSTRAP +# define BOOTSTRAP_MAP (main_map) +# define RESOLVE_MAP(sym, version, flags) BOOTSTRAP_MAP +# include "dynamic-link.h" + + /* Figure out the run-time load address of static PIE. */ + main_map->l_addr = elf_machine_load_address (); + + /* Read our own dynamic section and fill in the info array. */ + main_map->l_ld = ((void *) main_map->l_addr + elf_machine_dynamic ()); + elf_get_dynamic_info (main_map, NULL); + +# ifdef ELF_MACHINE_BEFORE_RTLD_RELOC + ELF_MACHINE_BEFORE_RTLD_RELOC (main_map->l_info); +# endif + + /* Relocate ourselves so we can do normal function calls and + data access using the global offset table. */ + ELF_DYNAMIC_RELOCATE (main_map, 0, 0, 0); + main_map->l_relocated = 1; +} +#endif diff --git a/elf/dl-support.c b/elf/dl-support.c index 235d3a7f463..b9fc1a66fe9 100644 --- a/elf/dl-support.c +++ b/elf/dl-support.c @@ -385,3 +385,14 @@ _dl_non_dynamic_init (void) #ifdef DL_SYSINFO_IMPLEMENTATION DL_SYSINFO_IMPLEMENTATION #endif + +#if ENABLE_STATIC_PIE +/* Since relocation to hidden _dl_main_map causes relocation overflow on + aarch64, a function is used to get the address of _dl_main_map. */ + +struct link_map * +_dl_get_dl_main_map (void) +{ + return &_dl_main_map; +} +#endif diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h index ebea7567cd3..6278649711b 100644 --- a/elf/dynamic-link.h +++ b/elf/dynamic-link.h @@ -94,7 +94,7 @@ elf_machine_lazy_rel (struct link_map *map, #ifdef RESOLVE_MAP -# ifdef RTLD_BOOTSTRAP +# if defined RTLD_BOOTSTRAP || defined STATIC_PIE_BOOTSTRAP # define ELF_DURING_STARTUP (1) # else # define ELF_DURING_STARTUP (0) diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h index 7525c3a5b20..eb26d23649d 100644 --- a/elf/get-dynamic-info.h +++ b/elf/get-dynamic-info.h @@ -38,7 +38,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) typedef Elf64_Xword d_tag_utype; #endif -#ifndef RTLD_BOOTSTRAP +#if !defined RTLD_BOOTSTRAP && !defined STATIC_PIE_BOOTSTRAP if (dyn == NULL) return; #endif @@ -139,9 +139,11 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) /* Only the bind now flags are allowed. */ assert (info[VERSYMIDX (DT_FLAGS_1)] == NULL || (info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val & ~DF_1_NOW) == 0); + /* Flags must not be set for ld.so. */ assert (info[DT_FLAGS] == NULL || (info[DT_FLAGS]->d_un.d_val & ~DF_BIND_NOW) == 0); - /* Flags must not be set for ld.so. */ +#endif +#if defined RTLD_BOOTSTRAP || defined STATIC_PIE_BOOTSTRAP assert (info[DT_RUNPATH] == NULL); assert (info[DT_RPATH] == NULL); #else diff --git a/gmon/Makefile b/gmon/Makefile index 89ab3fc7dac..29e746723e8 100644 --- a/gmon/Makefile +++ b/gmon/Makefile @@ -39,6 +39,10 @@ tests-static += tst-gmon-static ifeq (yesyes,$(have-fpie)$(build-shared)) tests += tst-gmon-pie tests-pie += tst-gmon-pie +ifeq (yes,$(enable-static-pie)) +tests += tst-gmon-static-pie +tests-static += tst-gmon-static-pie +endif endif # The mcount code won't work without a frame pointer. @@ -54,7 +58,7 @@ endif CFLAGS-tst-gmon-static.c := $(PIE-ccflag) -fno-omit-frame-pointer -pg CRT-tst-gmon-static := $(csu-objpfx)gcrt1.o -DEFAULT-LDFLAGS-tst-gmon-static = $(no-pie-ldflag) +tst-gmon-static-no-pie = yes tst-gmon-static-ENV := GMON_OUT_PREFIX=$(objpfx)tst-gmon-static.data ifeq ($(run-built-tests),yes) tests-special += $(objpfx)tst-gmon-static-gprof.out @@ -67,6 +71,15 @@ ifeq ($(run-built-tests),yes) tests-special += $(objpfx)tst-gmon-pie-gprof.out endif +ifeq (yes,$(enable-static-pie)) +CFLAGS-tst-gmon-static-pie.c := $(PIE-ccflag) -fno-omit-frame-pointer -pg +CRT-tst-gmon-static-pie := $(csu-objpfx)grcrt1.o +tst-gmon-static-pie-ENV := GMON_OUT_PREFIX=$(objpfx)tst-gmon-static-pie.data +ifeq ($(run-built-tests),yes) +tests-special += $(objpfx)tst-gmon-static-pie-gprof.out +endif +endif + include ../Rules @@ -111,3 +124,13 @@ clean-tst-gmon-pie-data: $(objpfx)tst-gmon-pie-gprof.out: tst-gmon-gprof.sh $(objpfx)tst-gmon-pie.out $(SHELL) $< $(GPROF) $(objpfx)tst-gmon-pie $(objpfx)tst-gmon-pie.data.* > $@; \ $(evaluate-test) + +$(objpfx)tst-gmon-static-pie.out: clean-tst-gmon-static-pie-data +clean-tst-gmon-static-pie-data: + rm -f $(objpfx)tst-gmon-static-pie.data.* + +$(objpfx)tst-gmon-static-pie-gprof.out: tst-gmon-static-gprof.sh \ + $(objpfx)tst-gmon-static-pie.out + $(SHELL) $< $(GPROF) $(objpfx)tst-gmon-static-pie \ + $(objpfx)tst-gmon-static-pie.data.* > $@; \ + $(evaluate-test) diff --git a/gmon/tst-gmon-static-pie.c b/gmon/tst-gmon-static-pie.c new file mode 100644 index 00000000000..1eef2583b61 --- /dev/null +++ b/gmon/tst-gmon-static-pie.c @@ -0,0 +1 @@ +#include "tst-gmon.c" diff --git a/manual/install.texi b/manual/install.texi index e81f1c50c38..fb956b5d6a2 100644 --- a/manual/install.texi +++ b/manual/install.texi @@ -116,6 +116,15 @@ Don't build shared libraries even if it is possible. Not all systems support shared libraries; you need ELF support and (currently) the GNU linker. +@item --enable-static-pie +Enable static position independent executable (static PIE) support. +Static PIE is similar to static executable, but can be loaded at any +address without help from a dynamic linker. All static programs as +well as static tests are built as static PIE, except for those marked +with no-pie. The resulting glibc can be used with the GCC option, +-static-pie, which is available with GCC 8 or above, to create static +PIE. + @item --disable-profile Don't build libraries with profiling information. You may want to use this option if you don't plan to do profiling. diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index 7a65dc641ce..196513851f5 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -1051,6 +1051,17 @@ extern void _dl_determine_tlsoffset (void) attribute_hidden; stack protector, among other things). */ void __libc_setup_tls (void); +# if ENABLE_STATIC_PIE +/* Relocate static executable with PIE. */ +extern void _dl_relocate_static_pie (void) attribute_hidden; + +/* Get a pointer to _dl_main_map. */ +extern struct link_map * _dl_get_dl_main_map (void) + __attribute__ ((visibility ("hidden"))); +# else +# define _dl_relocate_static_pie() +# endif + /* Initialization of libpthread for statically linked applications. If libpthread is not linked in, this is an empty function. */ void __pthread_initialize_minimal (void) weak_function; diff --git a/sysdeps/i386/configure b/sysdeps/i386/configure index 4cf968d8bc2..90c63caf351 100644 --- a/sysdeps/i386/configure +++ b/sysdeps/i386/configure @@ -50,6 +50,39 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_compiler_builtin_inlined" >&5 $as_echo "$libc_compiler_builtin_inlined" >&6; } +if test "$static_pie" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker static PIE support" >&5 +$as_echo_n "checking for linker static PIE support... " >&6; } +if ${libc_cv_ld_static_pie+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat > conftest.s <<\EOF + .text + .global _start +_start: + movl _start@GOT(%ebx), %eax +EOF + libc_cv_pie_option="-Wl,-pie" + libc_cv_ld_static_pie=no + if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -nostartfiles -nostdlib $no_ssp $libc_cv_pie_option -o conftest conftest.s 1>&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + if $READELF -r conftest | grep 'There are no relocations in this file.' > /dev/null; then + libc_cv_ld_static_pie=yes + fi + fi +rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_ld_static_pie" >&5 +$as_echo "$libc_cv_ld_static_pie" >&6; } + if test "$libc_cv_ld_static_pie" != yes; then + as_fn_error $? "linker support for static PIE needed" "$LINENO" 5 + fi +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Intel MPX support" >&5 $as_echo_n "checking for Intel MPX support... " >&6; } if ${libc_cv_asm_mpx+:} false; then : diff --git a/sysdeps/i386/configure.ac b/sysdeps/i386/configure.ac index b598b120bcd..6d2068d2b3e 100644 --- a/sysdeps/i386/configure.ac +++ b/sysdeps/i386/configure.ac @@ -30,6 +30,29 @@ LIBC_COMPILER_BUILTIN_INLINED( *** Please use host i786, i686, i586, or i486. *** For example: /source/glibc/configure CFLAGS='-O2 -march=i686' ...])]) +dnl Check if linker can convert "movl main@GOT(%ebx), %eax" to +dnl "leal main@GOTOFF(%ebx), %eax" for static PIE. +if test "$static_pie" = yes; then + AC_CACHE_CHECK(for linker static PIE support, libc_cv_ld_static_pie, [dnl +cat > conftest.s <<\EOF + .text + .global _start +_start: + movl _start@GOT(%ebx), %eax +EOF + libc_cv_pie_option="-Wl,-pie" + libc_cv_ld_static_pie=no + if AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -nostartfiles -nostdlib $no_ssp $libc_cv_pie_option -o conftest conftest.s 1>&AS_MESSAGE_LOG_FD); then + if $READELF -r conftest | grep 'There are no relocations in this file.' > /dev/null; then + libc_cv_ld_static_pie=yes + fi + fi +rm -f conftest*]) + if test "$libc_cv_ld_static_pie" != yes; then + AC_MSG_ERROR([linker support for static PIE needed]) + fi +fi + dnl Check whether asm supports Intel MPX AC_CACHE_CHECK(for Intel MPX support, libc_cv_asm_mpx, [dnl cat > conftest.s <<\EOF diff --git a/sysdeps/mips/Makefile b/sysdeps/mips/Makefile index fd891ddf098..7ac6fa50311 100644 --- a/sysdeps/mips/Makefile +++ b/sysdeps/mips/Makefile @@ -23,6 +23,9 @@ CPPFLAGS-crtn.S += $(pic-ccflag) endif ASFLAGS-.os += $(pic-ccflag) +# libc.a and libc_p.a must be compiled with -fPIE/-fpie for static PIE. +ASFLAGS-.o += $(pie-default) +ASFLAGS-.op += $(pie-default) ifeq ($(subdir),elf) ifneq ($(o32-fpabi),) diff --git a/sysdeps/x86_64/configure b/sysdeps/x86_64/configure index efef46b1b7f..8674d145695 100644 --- a/sysdeps/x86_64/configure +++ b/sysdeps/x86_64/configure @@ -85,6 +85,39 @@ if test x"$build_mathvec" = xnotset; then build_mathvec=yes fi +if test "$static_pie" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker static PIE support" >&5 +$as_echo_n "checking for linker static PIE support... " >&6; } +if ${libc_cv_ld_static_pie+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat > conftest.s <<\EOF + .text + .global _start + .weak foo +_start: + leaq foo(%rip), %rax +EOF + libc_cv_pie_option="-Wl,-pie" + if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -nostartfiles -nostdlib $no_ssp $libc_cv_pie_option -o conftest conftest.s 1>&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + libc_cv_ld_static_pie=yes + else + libc_cv_ld_static_pie=no + fi +rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_ld_static_pie" >&5 +$as_echo "$libc_cv_ld_static_pie" >&6; } + if test "$libc_cv_ld_static_pie" != yes; then + as_fn_error $? "linker support for static PIE needed" "$LINENO" 5 + fi +fi + $as_echo "#define PI_STATIC_AND_HIDDEN 1" >>confdefs.h diff --git a/sysdeps/x86_64/configure.ac b/sysdeps/x86_64/configure.ac index fa86e953ee4..b7d2c0124fb 100644 --- a/sysdeps/x86_64/configure.ac +++ b/sysdeps/x86_64/configure.ac @@ -44,6 +44,31 @@ if test x"$build_mathvec" = xnotset; then build_mathvec=yes fi +dnl Check if linker supports static PIE with the fix for +dnl +dnl https://sourceware.org/bugzilla/show_bug.cgi?id=21782 +dnl +if test "$static_pie" = yes; then + AC_CACHE_CHECK(for linker static PIE support, libc_cv_ld_static_pie, [dnl +cat > conftest.s <<\EOF + .text + .global _start + .weak foo +_start: + leaq foo(%rip), %rax +EOF + libc_cv_pie_option="-Wl,-pie" + if AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -nostartfiles -nostdlib $no_ssp $libc_cv_pie_option -o conftest conftest.s 1>&AS_MESSAGE_LOG_FD); then + libc_cv_ld_static_pie=yes + else + libc_cv_ld_static_pie=no + fi +rm -f conftest*]) + if test "$libc_cv_ld_static_pie" != yes; then + AC_MSG_ERROR([linker support for static PIE needed]) + fi +fi + dnl It is always possible to access static and hidden symbols in an dnl position independent way. AC_DEFINE(PI_STATIC_AND_HIDDEN)