Bug 1079662 - Always enable PIE. r=froydnj
authorMike Hommey <mh+mozilla@glandium.org>
Thu, 06 Sep 2018 13:27:49 +0900
changeset 491031 3cbbfc5127e473345c8b0f040a0ed1b254d800ed
parent 491030 877c851a1b66348627379e9a7a7f4b1f9fd73dfb
child 491032 0e1dd163d6141129e8e58bc835efd2f0cc37be1d
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1079662
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1079662 - Always enable PIE. r=froydnj Last attempt, a few years ago, blatantly failed because nautilus (the GNOME file manager) can't start PIE executables, which look like shared libraries, and that it thus considers not being executables. Downstreams don't actually have the problem, because users won't be launching Firefox from a file manager, but for mozilla.org builds, it is a problem because users would download, then extract, and then likely try to run the Firefox executable from a file manager. So for mozilla.org builds, we still need to find a way around the nautilus problem. A .desktop file could be a solution, but .desktop files have not actually been designed for this use case, which leads to: - having to use an awful one-liner shell wrapper to derive the path to the executable from that of the .desktop file, - not even being able to associate an icon, - the .desktop file not being copiable to a location where .desktop files would normally go, because it would then fail to find the executable. Another possibility is to go back to using a shell wrapper, but that's not entirely appealing. What we chose here is similar, where we have a small `firefox` wrapper that launches the real `firefox-bin` (which is still leftover from those old times where we had a shell wrapper, for reasons). The small `firefox` wrapper is a minimalist C executable that just finds the path to the `firefox-bin` executable and executes it with the same args it was called with. The wrapper is only enabled when the MOZ_NO_PIE_COMPAT environment variable is set, which we only take into account on Linux. The variable is only really meant to be used for mozilla.org builds, for the nautilus problem. Downstreams will just pick the default, which is changed to build PIE. On other platforms, PIE was already enabled by default, so we just remove the --enable-pie configure flag. Differential Revision: https://phabricator.services.mozilla.com/D5109
browser/app/Makefile.in
browser/app/moz.build
browser/app/no-pie/NoPie.c
browser/app/no-pie/moz.build
browser/moz.configure
build/autoconf/compiler-opts.m4
build/moz.configure/old.configure
build/moz.configure/toolchain.configure
build/mozconfig.no-compile
build/unix/mozconfig.linux
build/unix/mozconfig.lto
build/unix/mozconfig.tsan
toolkit/crashreporter/tools/unit-symbolstore.py
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -36,19 +36,21 @@ endif
 
 PROGRAMS_DEST = $(DIST)/bin
 
 include $(topsrcdir)/config/rules.mk
 
 ifneq (,$(filter-out WINNT,$(OS_ARCH)))
 
 ifdef COMPILE_ENVIRONMENT
+ifndef MOZ_NO_PIE_COMPAT
 libs::
 	cp -p $(DIST)/bin/$(MOZ_APP_NAME)$(BIN_SUFFIX) $(DIST)/bin/$(MOZ_APP_NAME)-bin$(BIN_SUFFIX)
 endif
+endif
 
 GARBAGE += $(addprefix $(FINAL_TARGET)/defaults/pref/, firefox.js)
 
 endif
 
 # channel-prefs.js is handled separate from other prefs due to bug 756325
 # DO NOT change the content of channel-prefs.js without taking the appropriate
 # steps. See bug 1431342.
--- a/browser/app/moz.build
+++ b/browser/app/moz.build
@@ -24,17 +24,22 @@ with Files("moz.build"):
 with Files("Makefile.in"):
     BUG_COMPONENT = ("Firefox Build System", "General")
 
 with Files("profile/channel-prefs.js"):
     BUG_COMPONENT = ("Firefox", "Installer")
 with Files("profile/firefox.js"):
     BUG_COMPONENT = ("Firefox", "General")
 
-GeckoProgram(CONFIG['MOZ_APP_NAME'])
+if CONFIG['MOZ_NO_PIE_COMPAT']:
+    GeckoProgram(CONFIG['MOZ_APP_NAME'] + '-bin')
+
+    DIRS += ['no-pie']
+else:
+    GeckoProgram(CONFIG['MOZ_APP_NAME'])
 
 SOURCES += [
     'nsBrowserApp.cpp',
 ]
 
 # Neither channel-prefs.js nor firefox.exe want to end up in dist/bin/browser.
 DIST_SUBDIR = ""
 
new file mode 100644
--- /dev/null
+++ b/browser/app/no-pie/NoPie.c
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int main(int argc, char* argv[])
+{
+  // Ideally, we'd use mozilla::BinaryPath, but that pulls in stdc++compat,
+  // and further causes trouble linking with LTO.
+  char path[PATH_MAX + 4];
+  ssize_t len = readlink("/proc/self/exe", path, PATH_MAX - 1);
+  if (len < 0) {
+    fprintf(stderr, "Couldn't find the application directory.\n");
+    return 255;
+  }
+  strcpy(path + len, "-bin");
+  execv(path, argv);
+  // execv never returns. If it did, there was an error.
+  fprintf(stderr, "Exec failed with error: %s\n", strerror(errno));
+  return 255;
+}
new file mode 100644
--- /dev/null
+++ b/browser/app/no-pie/moz.build
@@ -0,0 +1,22 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Program(CONFIG['MOZ_APP_NAME'])
+
+SOURCES += [
+    'NoPie.c',
+]
+
+# For some reason, LTO messes things up. We don't care anyways.
+CFLAGS += [
+    '-fno-lto',
+]
+
+# Use OS_LIBS instead of LDFLAGS to "force" the flag to come after -pie
+# from MOZ_PROGRAM_LDFLAGS.
+OS_LIBS += [
+    '-no-pie'
+]
--- a/browser/moz.configure
+++ b/browser/moz.configure
@@ -3,9 +3,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 imply_option('MOZ_PLACES', True)
 imply_option('MOZ_SERVICES_HEALTHREPORT', True)
 imply_option('MOZ_SERVICES_SYNC', True)
 
+with only_when(target_is_linux & compile_environment):
+    option(env='MOZ_NO_PIE_COMPAT',
+           help='Enable non-PIE wrapper')
+
+    set_config('MOZ_NO_PIE_COMPAT',
+               depends_if('MOZ_NO_PIE_COMPAT')(lambda _: True))
+
 include('../toolkit/moz.configure')
--- a/build/autoconf/compiler-opts.m4
+++ b/build/autoconf/compiler-opts.m4
@@ -203,39 +203,18 @@ if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -
          if test "$GC_SECTIONS_BREAKS_DEBUG_RANGES" = no; then
              DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
          fi
     else
         DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
     fi
 fi
 
-# On OSX, the linker defaults to building PIE programs when targeting OSX 10.7.
-# On other Unix systems, some file managers (Nautilus) can't start PIE programs
-if test "$OS_TARGET" = Android; then
-    # bionic in Android >= 4.1 supports PIE, and we target those versions.
-    MOZ_PIE=1
-else
-    MOZ_PIE=
-fi
-
-MOZ_ARG_ENABLE_BOOL(pie,
-[  --enable-pie           Enable Position Independent Executables],
-    MOZ_PIE=1,
-    MOZ_PIE= )
-
-if test "$GNU_CC$CLANG_CC" -a -n "$MOZ_PIE"; then
-    AC_MSG_CHECKING([for PIE support])
-    _SAVE_LDFLAGS=$LDFLAGS
-    LDFLAGS="$LDFLAGS $DSO_PIC_CFLAGS -pie"
-    AC_TRY_LINK(,,AC_MSG_RESULT([yes])
-                  [MOZ_PROGRAM_LDFLAGS="$MOZ_PROGRAM_LDFLAGS -pie"],
-                  AC_MSG_RESULT([no])
-                  AC_MSG_ERROR([--enable-pie requires PIE support from the linker.]))
-    LDFLAGS=$_SAVE_LDFLAGS
+if test "$GNU_CC$CLANG_CC"; then
+    MOZ_PROGRAM_LDFLAGS="$MOZ_PROGRAM_LDFLAGS -pie"
 fi
 
 AC_SUBST(MOZ_PROGRAM_LDFLAGS)
 
 dnl ASan assumes no symbols are being interposed, and when that happens,
 dnl it's not happy with it. Unconveniently, since Firefox is exporting
 dnl libffi symbols and Gtk+3 pulls system libffi via libwayland-client,
 dnl system libffi interposes libffi symbols that ASan assumes are in
--- a/build/moz.configure/old.configure
+++ b/build/moz.configure/old.configure
@@ -197,17 +197,16 @@ def old_configure_options(*options):
     '--enable-memory-sanitizer',
     '--enable-mobile-optimize',
     '--enable-necko-wifi',
     '--enable-negotiateauth',
     '--enable-nfc',
     '--enable-nspr-build',
     '--enable-official-branding',
     '--enable-parental-controls',
-    '--enable-pie',
     '--enable-posix-nspr-emulation',
     '--enable-pref-extensions',
     '--enable-raw',
     '--enable-readline',
     '--enable-reflow-perf',
     '--enable-sandbox',
     '--enable-signmar',
     '--enable-startup-notification',
--- a/build/moz.configure/toolchain.configure
+++ b/build/moz.configure/toolchain.configure
@@ -1474,17 +1474,16 @@ def security_hardening_cflags(hardening_
     return namespace(
         flags=flags,
         js_flags=js_flags,
     )
 
 
 add_old_configure_assignment('MOZ_HARDENING_CFLAGS', security_hardening_cflags.flags)
 add_old_configure_assignment('MOZ_HARDENING_CFLAGS_JS', security_hardening_cflags.js_flags)
-imply_option('--enable-pie', depends_if('--enable-hardening')(lambda v: v))
 
 # Code Coverage
 # ==============================================================
 
 js_option('--enable-coverage', env='MOZ_CODE_COVERAGE',
           help='Enable code coverage')
 
 
--- a/build/mozconfig.no-compile
+++ b/build/mozconfig.no-compile
@@ -21,8 +21,9 @@ unset MAKECAB
 unset TOOLCHAIN_PREFIX
 unset BINDGEN_CFLAGS
 unset LLVM_CONFIG
 unset WIN64_LINK
 unset WIN64_LIB
 unset ENABLE_CLANG_PLUGIN
 
 unset MOZ_STDCXX_COMPAT
+unset MOZ_NO_PIE_COMPAT
--- a/build/unix/mozconfig.linux
+++ b/build/unix/mozconfig.linux
@@ -1,1 +1,3 @@
 . "$topsrcdir/build/unix/mozconfig.unix"
+
+export MOZ_NO_PIE_COMPAT=1
--- a/build/unix/mozconfig.lto
+++ b/build/unix/mozconfig.lto
@@ -3,11 +3,8 @@ MOZ_AUTOMATION_L10N_CHECK=0
 . "$topsrcdir/build/unix/mozconfig.linux"
 
 # Use Clang as specified in manifest
 export AR="$topsrcdir/clang/bin/llvm-ar"
 export NM="$topsrcdir/clang/bin/llvm-nm"
 export RANLIB="$topsrcdir/clang/bin/llvm-ranlib"
 
 ac_add_options --enable-lto
-# Until it's either made the default or we figure a way to remove the
-# copy locations that LTO induces in non-PIE executables.
-ac_add_options --enable-pie
--- a/build/unix/mozconfig.tsan
+++ b/build/unix/mozconfig.tsan
@@ -10,14 +10,13 @@ ac_add_options --enable-thread-sanitizer
 # The ThreadSanitizer is not compatible with sandboxing
 # (see bug 1182565)
 ac_add_options --disable-sandbox
 
 # These are required by TSan
 ac_add_options --disable-jemalloc
 ac_add_options --disable-crashreporter
 ac_add_options --disable-elf-hack
-ac_add_options --enable-pie
 
 # Keep symbols to symbolize TSan traces
 ac_add_options --disable-install-strip
 # -gline-tables-only results in significantly smaller binaries.
 ac_add_options --enable-debug-symbols="-gline-tables-only"
--- a/toolkit/crashreporter/tools/unit-symbolstore.py
+++ b/toolkit/crashreporter/tools/unit-symbolstore.py
@@ -486,17 +486,17 @@ class TestFunctional(HelperMixin, unitte
             self.target_bin = os.path.join(buildconfig.topobjdir,
                                            'dist', 'bin',
                                            'firefox.exe')
         else:
             self.dump_syms = os.path.join(buildconfig.topobjdir,
                                           'dist', 'host', 'bin',
                                           'dump_syms')
             self.target_bin = os.path.join(buildconfig.topobjdir,
-                                           'dist', 'bin', 'firefox')
+                                           'dist', 'bin', 'firefox-bin')
 
 
     def tearDown(self):
         HelperMixin.tearDown(self)
 
     def testSymbolstore(self):
         if self.skip_test:
             raise unittest.SkipTest('Skipping test in non-Firefox product')