summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/common.gypi20
-rwxr-xr-xbuild/mac/change_mach_o_flags.py (renamed from build/mac/make_heap_non_executable.py)79
-rwxr-xr-xbuild/mac/change_mach_o_flags_from_xcode.sh14
-rwxr-xr-xbuild/mac/make_heap_non_executable_from_xcode.sh15
-rw-r--r--chrome/app/chrome_main.cc32
-rw-r--r--chrome/app/helper-Info.plist2
-rw-r--r--chrome/browser/automation/testing_automation_provider.cc10
-rw-r--r--chrome/browser/importer/profile_import_process_host.cc7
-rw-r--r--chrome/browser/memory_details_mac.cc19
-rw-r--r--chrome/browser/nacl_host/nacl_process_host.cc17
-rw-r--r--chrome/browser/service/service_process_control.cc9
-rw-r--r--chrome/chrome.gyp69
-rw-r--r--chrome/chrome_exe.gypi34
-rw-r--r--chrome/common/chrome_constants.cc6
-rw-r--r--chrome/common/chrome_constants.h12
-rw-r--r--chrome/common/service_process_util.cc3
-rw-r--r--chrome/installer/mac/sign_app.sh.in8
-rw-r--r--chrome/installer/mac/sign_versioned_dir.sh.in8
-rw-r--r--chrome/service/service_utility_process_host.cc7
-rw-r--r--chrome/test/base/chrome_process_util.cc46
-rwxr-xr-xchrome/tools/build/mac/make_locale_dirs.sh39
-rwxr-xr-xchrome/tools/build/mac/make_more_helpers.sh89
-rw-r--r--content/browser/gpu/gpu_process_host.cc9
-rw-r--r--content/browser/plugin_process_host.cc14
-rw-r--r--content/browser/ppapi_broker_process_host.cc9
-rw-r--r--content/browser/renderer_host/browser_render_process_host.cc10
-rw-r--r--content/browser/utility_process_host.cc7
-rw-r--r--content/browser/worker_host/worker_process_host.cc8
-rw-r--r--content/common/child_process_host.cc71
-rw-r--r--content/common/child_process_host.h48
-rw-r--r--content/common/plugin_carbon_interpose_constants_mac.cc2
31 files changed, 579 insertions, 144 deletions
diff --git a/build/common.gypi b/build/common.gypi
index 89824b3..b6b179a 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -1679,16 +1679,20 @@
'postbuilds': [
{
# Arranges for data (heap) pages to be protected against
- # code execution when running on Mac OS X 10.7 ("Lion").
+ # code execution when running on Mac OS X 10.7 ("Lion"), and
+ # ensures that the position-independent executable (PIE) bit
+ # is set for ASLR when running on Mac OS X 10.5 ("Leopard").
'variables': {
- # Define make_heap_non_executable in a variable ending in
- # _path so that gyp understands it's a path and performs
- # proper relativization during dict merging.
- 'make_heap_non_executable_path':
- 'mac/make_heap_non_executable_from_xcode.sh',
+ # Define change_mach_o_flags in a variable ending in _path
+ # so that GYP understands it's a path and performs proper
+ # relativization during dict merging.
+ 'change_mach_o_flags_path':
+ 'mac/change_mach_o_flags_from_xcode.sh',
},
- 'postbuild_name': 'Make Heap Non-Executable',
- 'action': ['<(make_heap_non_executable_path)'],
+ 'postbuild_name': 'Change Mach-O Flags',
+ 'action': [
+ '<(change_mach_o_flags_path)',
+ ],
},
],
}],
diff --git a/build/mac/make_heap_non_executable.py b/build/mac/change_mach_o_flags.py
index 507403a..1dfe07f 100755
--- a/build/mac/make_heap_non_executable.py
+++ b/build/mac/change_mach_o_flags.py
@@ -4,10 +4,20 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# Usage: make_heap_non_executable.py <executable_path>
+# Usage: change_mach_o_flags.py [--executable-heap] [--no-pie] <executable_path>
#
# Arranges for the executable at |executable_path| to have its data (heap)
-# pages protected to prevent execution on Mac OS X 10.7 ("Lion").
+# pages protected to prevent execution on Mac OS X 10.7 ("Lion"), and to have
+# the PIE (position independent executable) bit set to enable ASLR (address
+# space layout randomization). With --executable-heap or --no-pie, the
+# respective bits are cleared instead of set, making the heap executable or
+# disabling PIE/ASLR.
+#
+# This script is able to operate on thin (single-architecture) Mach-O files
+# and fat (universal, multi-architecture) files. When operating on fat files,
+# it will set or clear the bits for each architecture contained therein.
+#
+# NON-EXECUTABLE HEAP
#
# Traditionally in Mac OS X, 32-bit processes did not have data pages set to
# prohibit execution. Although user programs could call mprotect and
@@ -47,12 +57,24 @@
# with appropriate protection even when vm.allow_data_exec has been tampered
# with.
#
-# This script is able to operate on thin (single-architecture) Mach-O files
-# and fat (universal, multi-architecture) files. When operating on fat files,
-# it will set the MH_NO_HEAP_EXECUTION bit for each architecture contained
-# therein.
+# POSITION-INDEPENDENT EXECUTABLES/ADDRESS SPACE LAYOUT RANDOMIZATION
+#
+# This script sets or clears the MH_PIE bit in an executable's Mach-O header,
+# enabling or disabling position independence on Mac OS X 10.5 and later.
+# Processes running position-independent executables have varying levels of
+# ASLR protection depending on the OS release. The main executable's load
+# address, shared library load addresess, and the heap and stack base
+# addresses may be randomized. Position-independent executables are produced
+# by supplying the -pie flag to the linker (or defeated by supplying -no_pie).
+# Executables linked with a deployment target of 10.7 or higher have PIE on
+# by default.
+#
+# This script is never strictly needed during the build to enable PIE, as all
+# linkers used are recent enough to support -pie. However, it's used to
+# disable the PIE bit as needed on already-linked executables.
+import optparse
import os
import struct
import sys
@@ -68,7 +90,8 @@ MH_CIGAM = 0xcefaedfe
MH_MAGIC_64 = 0xfeedfacf
MH_CIGAM_64 = 0xcffaedfe
MH_EXECUTE = 0x2
-MH_NO_HEAP_EXECUTION = 0x1000000
+MH_PIE = 0x00200000
+MH_NO_HEAP_EXECUTION = 0x01000000
class MachOError(Exception):
@@ -150,14 +173,15 @@ def WriteUInt32(file, uint32, endian):
file.write(bytes)
-def HandleMachOFile(file, offset=0):
+def HandleMachOFile(file, options, offset=0):
"""Seeks the file-like |file| object to |offset|, reads its |mach_header|,
and rewrites the header's |flags| field if appropriate. The header's
endianness is detected. Both 32-bit and 64-bit Mach-O headers are supported
(mach_header and mach_header_64). Raises MachOError if used on a header that
does not have a known magic number or is not of type MH_EXECUTE. The
- MH_NO_HEAP_EXECUTION is set in the |flags| field and written to |file| if
- not already set. If already set, nothing is written."""
+ MH_PIE and MH_NO_HEAP_EXECUTION bits are set or cleared in the |flags| field
+ according to |options| and written to |file| if any changes need to be made.
+ If already set or clear as specified by |options|, nothing is written."""
CheckedSeek(file, offset)
magic = ReadUInt32(file, '<')
@@ -178,13 +202,24 @@ def HandleMachOFile(file, offset=0):
'Mach-O file at offset %d is type 0x%x, expected MH_EXECUTE' % \
(offset, filetype)
- if not flags & MH_NO_HEAP_EXECUTION:
+ original_flags = flags
+
+ if options.no_heap_execution:
flags |= MH_NO_HEAP_EXECUTION
+ else:
+ flags &= ~MH_NO_HEAP_EXECUTION
+
+ if options.pie:
+ flags |= MH_PIE
+ else:
+ flags &= ~MH_PIE
+
+ if flags != original_flags:
CheckedSeek(file, offset + 24)
WriteUInt32(file, flags, endian)
-def HandleFatFile(file, fat_offset=0):
+def HandleFatFile(file, options, fat_offset=0):
"""Seeks the file-like |file| object to |offset| and loops over its
|fat_header| entries, calling HandleMachOFile for each."""
@@ -201,25 +236,33 @@ def HandleFatFile(file, fat_offset=0):
# HandleMachOFile will seek around. Come back here after calling it, in
# case it sought.
fat_arch_offset = file.tell()
- HandleMachOFile(file, offset)
+ HandleMachOFile(file, options, offset)
CheckedSeek(file, fat_arch_offset)
def main(me, args):
- if len(args) != 1:
- print >>sys.stderr, 'usage: %s <executable_path>' % me
+ parser = optparse.OptionParser('%prog [options] <executable_path>')
+ parser.add_option('--executable-heap', action='store_false',
+ dest='no_heap_execution', default=True,
+ help='Clear the MH_NO_HEAP_EXECUTION bit')
+ parser.add_option('--no-pie', action='store_false',
+ dest='pie', default=True,
+ help='Clear the MH_PIE bit')
+ (options, loose_args) = parser.parse_args(args)
+ if len(loose_args) != 1:
+ parser.print_usage()
return 1
- executable_path = args[0]
+ executable_path = loose_args[0]
executable_file = open(executable_path, 'rb+')
magic = ReadUInt32(executable_file, '<')
if magic == FAT_CIGAM:
# Check FAT_CIGAM and not FAT_MAGIC because the read was little-endian.
- HandleFatFile(executable_file)
+ HandleFatFile(executable_file, options)
elif magic == MH_MAGIC or magic == MH_CIGAM or \
magic == MH_MAGIC_64 or magic == MH_CIGAM_64:
- HandleMachOFile(executable_file)
+ HandleMachOFile(executable_file, options)
else:
raise MachOError, '%s is not a Mach-O or fat file' % executable_file
diff --git a/build/mac/change_mach_o_flags_from_xcode.sh b/build/mac/change_mach_o_flags_from_xcode.sh
new file mode 100755
index 0000000..ab3ee49
--- /dev/null
+++ b/build/mac/change_mach_o_flags_from_xcode.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This is a small wrapper script around change_mach_o_flags.py allowing it to
+# be invoked easily from Xcode. change_mach_o_flags.py expects its arguments
+# on the command line, but Xcode puts its parameters in the environment.
+
+set -e
+
+exec "$(dirname "${0}")/change_mach_o_flags.py" \
+ "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}"
diff --git a/build/mac/make_heap_non_executable_from_xcode.sh b/build/mac/make_heap_non_executable_from_xcode.sh
deleted file mode 100755
index adfc25d..0000000
--- a/build/mac/make_heap_non_executable_from_xcode.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/sh
-
-# Copyright (c) 2011 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is a small wrapper script around make_heap_non_executable.py allowing
-# it to be invoked easily from Xcode. make_heap_non_executable.py expects its
-# argument on the command line, and Xcode puts all of its parameters in the
-# environment.
-
-set -e
-
-exec "$(dirname "${0}")/make_heap_non_executable.py" \
- "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}"
diff --git a/chrome/app/chrome_main.cc b/chrome/app/chrome_main.cc
index a1d635e..9c680df 100644
--- a/chrome/app/chrome_main.cc
+++ b/chrome/app/chrome_main.cc
@@ -764,11 +764,37 @@ int ChromeMain(int argc, char** argv) {
// The helper's Info.plist marks it as a background only app.
if (base::mac::IsBackgroundOnlyProcess()) {
- CHECK(command_line.HasSwitch(switches::kProcessType))
+ CHECK(command_line.HasSwitch(switches::kProcessType) &&
+ !process_type.empty())
<< "Helper application requires --type.";
+
+ // In addition, some helper flavors only work with certain process types.
+ FilePath executable;
+ if (PathService::Get(base::FILE_EXE, &executable) &&
+ executable.value().size() >= 3) {
+ std::string last_three =
+ executable.value().substr(executable.value().size() - 3);
+
+ if (last_three == " EH") {
+ CHECK_EQ(switches::kPluginProcess, process_type)
+ << "Executable-heap process requires --type="
+ << switches::kPluginProcess << ", saw " << process_type;
+ } else if (last_three == " NP") {
+ CHECK_EQ(switches::kNaClLoaderProcess, process_type)
+ << "Non-PIE process requires --type="
+ << switches::kNaClLoaderProcess << ", saw " << process_type;
+ } else {
+ CHECK(process_type != switches::kPluginProcess &&
+ process_type != switches::kNaClLoaderProcess)
+ << "Non-executable-heap PIE process is intolerant of --type="
+ << switches::kPluginProcess << " and "
+ << switches::kNaClLoaderProcess << ", saw " << process_type;
+ }
+ }
} else {
- CHECK(!command_line.HasSwitch(switches::kProcessType))
- << "Main application forbids --type, saw \"" << process_type << "\".";
+ CHECK(!command_line.HasSwitch(switches::kProcessType) &&
+ process_type.empty())
+ << "Main application forbids --type, saw " << process_type;
}
if (IsCrashReporterEnabled())
diff --git a/chrome/app/helper-Info.plist b/chrome/app/helper-Info.plist
index 3e057b1..86f2f05 100644
--- a/chrome/app/helper-Info.plist
+++ b/chrome/app/helper-Info.plist
@@ -20,8 +20,6 @@
<string>????</string>
<key>LSFileQuarantineEnabled</key>
<true/>
- <key>LSHasLocalizedDisplayName</key>
- <string>1</string>
<key>LSMinimumSystemVersion</key>
<string>10.5.0</string>
<key>LSUIElement</key>
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc
index 233cc0e..32aa04d 100644
--- a/chrome/browser/automation/testing_automation_provider.cc
+++ b/chrome/browser/automation/testing_automation_provider.cc
@@ -2774,8 +2774,14 @@ void TestingAutomationProvider::GetBrowserInfo(
}
return_value->Set("windows", windows);
+#if defined(OS_LINUX)
+ int flags = ChildProcessHost::CHILD_ALLOW_SELF;
+#else
+ int flags = ChildProcessHost::CHILD_NORMAL;
+#endif
+
return_value->SetString("child_process_path",
- ChildProcessHost::GetChildPath(true).value());
+ ChildProcessHost::GetChildPath(flags).value());
// Child processes are the processes for plugins and other workers.
// Add all child processes in a list of dictionaries, one dictionary item
// per child process.
@@ -5818,7 +5824,7 @@ void TestingAutomationProvider::ExecuteJavascriptInRenderView(
RenderViewHost* rvh = RenderViewHost::FromID(render_process_id,
render_view_id);
- if(!rvh) {
+ if (!rvh) {
AutomationJSONReply(this, reply_message).SendError(
"A RenderViewHost object was not found with the given view ID.");
return;
diff --git a/chrome/browser/importer/profile_import_process_host.cc b/chrome/browser/importer/profile_import_process_host.cc
index 745b5f3..70350cf 100644
--- a/chrome/browser/importer/profile_import_process_host.cc
+++ b/chrome/browser/importer/profile_import_process_host.cc
@@ -76,7 +76,12 @@ bool ProfileImportProcessHost::ReportImportItemFinished(
}
FilePath ProfileImportProcessHost::GetProfileImportProcessCmd() {
- return GetChildPath(true);
+#if defined(OS_LINUX)
+ int flags = CHILD_ALLOW_SELF;
+#else
+ int flags = CHILD_NORMAL;
+#endif
+ return GetChildPath(flags);
}
bool ProfileImportProcessHost::StartProcess() {
diff --git a/chrome/browser/memory_details_mac.cc b/chrome/browser/memory_details_mac.cc
index c03c8c9..037d527 100644
--- a/chrome/browser/memory_details_mac.cc
+++ b/chrome/browser/memory_details_mac.cc
@@ -113,11 +113,24 @@ void MemoryDetails::CollectProcessData(
}
}
+ // The helper might show up as these different flavors depending on the
+ // executable flags required.
+ std::vector<std::string> helper_names;
+ helper_names.push_back(chrome::kHelperProcessExecutableName);
+ for (const char* const* suffix = chrome::kHelperFlavorSuffixes;
+ *suffix;
+ ++suffix) {
+ std::string helper_name = chrome::kHelperProcessExecutableName;
+ helper_name.append(1, ' ');
+ helper_name.append(*suffix);
+ helper_names.push_back(helper_name);
+ }
+
// Get PIDs of helpers.
std::vector<base::ProcessId> helper_pids;
- {
- base::NamedProcessIterator helper_it(chrome::kHelperProcessExecutableName,
- NULL);
+ for (size_t i = 0; i < helper_names.size(); ++i) {
+ std::string helper_name = helper_names[i];
+ base::NamedProcessIterator helper_it(helper_name, NULL);
while (const base::ProcessEntry* entry = helper_it.NextProcessEntry()) {
helper_pids.push_back(entry->pid());
all_pids.push_back(entry->pid());
diff --git a/chrome/browser/nacl_host/nacl_process_host.cc b/chrome/browser/nacl_host/nacl_process_host.cc
index 39a2f37..cb2f3a9 100644
--- a/chrome/browser/nacl_host/nacl_process_host.cc
+++ b/chrome/browser/nacl_host/nacl_process_host.cc
@@ -145,7 +145,22 @@ bool NaClProcessHost::LaunchSelLdr() {
#endif // defined(OS_POSIX)
// Build command line for nacl.
- FilePath exe_path = GetChildPath(nacl_loader_prefix.empty());
+
+#if defined(OS_MACOSX)
+ // The Native Client process needs to be able to allocate a 1GB contiguous
+ // region to use as the client environment's virtual address space. ASLR
+ // (PIE) interferes with this by making it possible that no gap large enough
+ // to accomodate this request will exist in the child process' address
+ // space. Disable PIE for NaCl processes. See http://crbug.com/90221 and
+ // http://code.google.com/p/nativeclient/issues/detail?id=2043.
+ int flags = CHILD_NO_PIE;
+#elif defined(OS_LINUX)
+ int flags = nacl_loader_prefix.empty() ? CHILD_ALLOW_SELF : CHILD_NORMAL;
+#else
+ int flags = CHILD_NORMAL;
+#endif
+
+ FilePath exe_path = GetChildPath(flags);
if (exe_path.empty())
return false;
diff --git a/chrome/browser/service/service_process_control.cc b/chrome/browser/service/service_process_control.cc
index 9557af2..40de028 100644
--- a/chrome/browser/service/service_process_control.cc
+++ b/chrome/browser/service/service_process_control.cc
@@ -118,7 +118,14 @@ void ServiceProcessControl::Launch(Task* success_task, Task* failure_task) {
// A service process should have a different mechanism for starting, but now
// we start it as if it is a child process.
- FilePath exe_path = ChildProcessHost::GetChildPath(true);
+
+#if defined(OS_LINUX)
+ int flags = ChildProcessHost::CHILD_ALLOW_SELF;
+#else
+ int flags = ChildProcessHost::CHILD_NORMAL;
+#endif
+
+ FilePath exe_path = ChildProcessHost::GetChildPath(flags);
if (exe_path.empty()) {
NOTREACHED() << "Unable to get service process binary name.";
}
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 42540b1..3195abf 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -940,7 +940,6 @@
'mac_bundle': 1,
'dependencies': [
'chrome_dll',
- 'interpose_dependency_shim',
'infoplist_strings_tool',
],
'sources': [
@@ -972,68 +971,24 @@
'CHROMIUM_SHORT_NAME': '<(branding)',
'CHROMIUM_STRIP_SAVE_FILE': 'app/app.saves',
'INFOPLIST_FILE': 'app/helper-Info.plist',
- # Stop the helper executable from being position-independent
- # since that turns on ASLR, which breaks NaCl. ASLR breaks
- # NaCl's ability to reliably allocate 1GB of address space for
- # untrusted code to run in.
- # See http://code.google.com/p/nativeclient/issues/detail?id=2043
- # TODO(mseaborn): Create a separate helper executable for NaCl
- # so that the renderer process can still use ASLR.
- 'OTHER_LDFLAGS!': ['-Wl,-pie'],
},
- 'copies': [
- {
- 'destination': '<(PRODUCT_DIR)/<(mac_product_name) Helper.app/Contents/MacOS',
- 'files': [
- '<(PRODUCT_DIR)/libplugin_carbon_interpose.dylib',
- ],
- },
- ],
- 'actions': [
+ 'postbuilds': [
{
- # Generate the InfoPlist.strings file
- 'action_name': 'Generate InfoPlist.strings files',
+ # The helper doesn't have real localizations, it just has
+ # empty .lproj directories, which is enough to convince Cocoa
+ # that anything running out of the helper .app supports those
+ # languages.
+ 'postbuild_name': 'Make Empty Localizations',
'variables': {
- 'tool_path': '<(PRODUCT_DIR)/infoplist_strings_tool',
- # Unique dir to write to so the [lang].lproj/InfoPlist.strings
- # for the main app and the helper app don't name collide.
- 'output_path': '<(INTERMEDIATE_DIR)/helper_infoplist_strings',
+ 'locale_dirs': [
+ '>!@(<(apply_locales_cmd) -d ZZLOCALE.lproj <(locales))',
+ ],
},
- 'conditions': [
- [ 'branding == "Chrome"', {
- 'variables': {
- 'branding_name': 'google_chrome_strings',
- },
- }, { # else branding!="Chrome"
- 'variables': {
- 'branding_name': 'chromium_strings',
- },
- }],
- ],
- 'inputs': [
- '<(tool_path)',
- '<(version_path)',
- # TODO: remove this helper when we have loops in GYP
- '>!@(<(apply_locales_cmd) \'<(grit_out_dir)/<(branding_name)_ZZLOCALE.pak\' <(locales))',
- ],
- 'outputs': [
- # TODO: remove this helper when we have loops in GYP
- '>!@(<(apply_locales_cmd) -d \'<(output_path)/ZZLOCALE.lproj/InfoPlist.strings\' <(locales))',
- ],
'action': [
- '<(tool_path)',
- '-b', '<(branding_name)',
- '-v', '<(version_path)',
- '-g', '<(grit_out_dir)',
- '-o', '<(output_path)',
- '-t', 'helper',
- '<@(locales)',
+ 'tools/build/mac/make_locale_dirs.sh',
+ '<@(locale_dirs)',
],
- 'message': 'Generating the language InfoPlist.strings files',
- 'process_outputs_as_mac_bundle_resources': 1,
},
- ],
- 'postbuilds': [
{
# The framework (chrome_dll) defines its load-time path
# (DYLIB_INSTALL_NAME_BASE) relative to the main executable
@@ -1170,7 +1125,7 @@
'xcode_settings': {
'DYLIB_COMPATIBILITY_VERSION': '<(version_mac_dylib)',
'DYLIB_CURRENT_VERSION': '<(version_mac_dylib)',
- 'DYLIB_INSTALL_NAME_BASE': '@executable_path',
+ 'DYLIB_INSTALL_NAME_BASE': '@executable_path/../../..',
},
'postbuilds': [
{
diff --git a/chrome/chrome_exe.gypi b/chrome/chrome_exe.gypi
index 83b6e98..79d98f7 100644
--- a/chrome/chrome_exe.gypi
+++ b/chrome/chrome_exe.gypi
@@ -273,6 +273,7 @@
'dependencies': [
'helper_app',
'infoplist_strings_tool',
+ 'interpose_dependency_shim',
'chrome_manifest_bundle',
],
'mac_bundle_resources': [
@@ -327,6 +328,7 @@
'destination': '<(PRODUCT_DIR)/<(mac_product_name).app/Contents/Versions/<(version_full)',
'files': [
'<(PRODUCT_DIR)/<(mac_product_name) Helper.app',
+ '<(PRODUCT_DIR)/libplugin_carbon_interpose.dylib',
],
},
],
@@ -366,6 +368,38 @@
'<(version_full)'
],
},
+ {
+ # This postbuid step is responsible for creating the following
+ # helpers:
+ #
+ # For unofficial Chromium branding, Chromium Helper EH.app and
+ # Chromium Helper NP.app are created from Chromium Helper.app.
+ # For official Google Chrome branding, Google Chrome Helper
+ # EH.app and Google Chrome Helper NP.app are created from
+ # Google Chrome Helper.app.
+ #
+ # The EH helper is marked for an executable heap. The NP helper
+ # is marked for no PIE (ASLR).
+ #
+ # Normally, applications shipping as part of offical builds with
+ # Google Chrome branding have dsymutil (dwarf-with-dsym,
+ # mac_real_dsym) and dump_syms (mac_breakpad) run on them to
+ # produce a .dSYM bundle and a Breakpad .sym file. This is
+ # unnecessary for the "More Helpers" because they're identical
+ # to the original helper except for the bits in their Mach-O
+ # headers that change to enable or disable special features.
+ # Each .dSYM and Breakpad symbol file is identified by UUID
+ # stored in a Mach-O file's LC_UUID load command. Because the
+ # "More Helpers" share a UUID with the original helper, there's
+ # no need to run dsymutil or dump_syms again. All helpers can
+ # share the same .dSYM and Breakpad symbol file.
+ 'postbuild_name': 'Make More Helpers',
+ 'action': [
+ 'tools/build/mac/make_more_helpers.sh',
+ '<(version_full)',
+ '<(mac_product_name)',
+ ],
+ },
], # postbuilds
}],
['OS=="linux"', {
diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc
index 844ef3b..731739e 100644
--- a/chrome/common/chrome_constants.cc
+++ b/chrome/common/chrome_constants.cc
@@ -93,6 +93,12 @@ const FilePath::CharType kHelperProcessExecutablePath[] = FPL("chrome");
#if defined(OS_MACOSX)
const FilePath::CharType kFrameworkName[] =
FPL(PRODUCT_STRING " Framework.framework");
+
+const char* const kHelperFlavorSuffixes[] = {
+ FPL("EH"), // Executable heap
+ FPL("NP"), // No PIE
+ NULL
+};
#endif // OS_MACOSX
const wchar_t kNaClAppName[] = L"nacl64";
diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h
index fb05878..ca0b456 100644
--- a/chrome/common/chrome_constants.h
+++ b/chrome/common/chrome_constants.h
@@ -26,7 +26,17 @@ extern const FilePath::CharType kBrowserProcessExecutablePathChromium[];
extern const FilePath::CharType kHelperProcessExecutablePathChromium[];
#if defined(OS_MACOSX)
extern const FilePath::CharType kFrameworkName[];
-#endif
+
+// The helper .app bundle name and executable name may have one of these
+// suffixes to identify specific features, or it may have no suffix at all.
+// This is a NULL-terminated array of strings. If kHelperFlavorSuffixes
+// contains "EN", "MF", and NULL, it indicates that if the normal helper is
+// named Chromium Helper.app, helper executables could show up at any of
+// Chromium Helper.app/Contents/MacOS/Chromium Helper,
+// Chromium Helper EN.app/Contents/MacOS/Chromium Helper EN, and
+// Chromium Helper MF.app/Contents/MacOS/Chromium Helper MF.
+extern const FilePath::CharType* const kHelperFlavorSuffixes[];
+#endif // OS_MACOSX
extern const wchar_t kBrowserAppName[];
#if defined(OS_WIN)
extern const wchar_t kStatusTrayWindowClass[];
diff --git a/chrome/common/service_process_util.cc b/chrome/common/service_process_util.cc
index 636b1ea..de9d013 100644
--- a/chrome/common/service_process_util.cc
+++ b/chrome/common/service_process_util.cc
@@ -252,7 +252,8 @@ IPC::ChannelHandle ServiceProcessState::GetServiceProcessChannel() {
#endif // !OS_MACOSX
void ServiceProcessState::CreateAutoRunCommandLine() {
- FilePath exe_path = ChildProcessHost::GetChildPath(false);
+ FilePath exe_path =
+ ChildProcessHost::GetChildPath(ChildProcessHost::CHILD_NORMAL);
if (exe_path.empty()) {
NOTREACHED() << "Unable to get service process binary name.";
}
diff --git a/chrome/installer/mac/sign_app.sh.in b/chrome/installer/mac/sign_app.sh.in
index 64ab064..3023806 100644
--- a/chrome/installer/mac/sign_app.sh.in
+++ b/chrome/installer/mac/sign_app.sh.in
@@ -1,6 +1,6 @@
#!/bin/bash -p
-# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -42,12 +42,16 @@ versioned_dir="${app_path}/Contents/Versions/@VERSION@"
browser_app="${app_path}"
framework="${versioned_dir}/@MAC_PRODUCT_NAME@ Framework.framework"
helper_app="${versioned_dir}/@MAC_PRODUCT_NAME@ Helper.app"
+helper_eh_app="${versioned_dir}/@MAC_PRODUCT_NAME@ Helper EH.app"
+helper_np_app="${versioned_dir}/@MAC_PRODUCT_NAME@ Helper NP.app"
codesign -s "${codesign_id}" --keychain "${codesign_keychain}" \
"${browser_app}" --resource-rules "${browser_app_rules}"
-# Verify everything. Check the framework and helper app to make sure that the
+# Verify everything. Check the framework and helper apps to make sure that the
# signatures are present and weren't altered by the signing process.
codesign -v "${framework}"
codesign -v "${helper_app}"
+codesign -v "${helper_eh_app}"
+codesign -v "${helper_np_app}"
codesign -v "${browser_app}"
diff --git a/chrome/installer/mac/sign_versioned_dir.sh.in b/chrome/installer/mac/sign_versioned_dir.sh.in
index 4affd5e..82c7fb7 100644
--- a/chrome/installer/mac/sign_versioned_dir.sh.in
+++ b/chrome/installer/mac/sign_versioned_dir.sh.in
@@ -42,10 +42,18 @@ versioned_dir="${app_path}/Contents/Versions/@VERSION@"
framework="${versioned_dir}/@MAC_PRODUCT_NAME@ Framework.framework"
helper_app="${versioned_dir}/@MAC_PRODUCT_NAME@ Helper.app"
+helper_eh_app="${versioned_dir}/@MAC_PRODUCT_NAME@ Helper EH.app"
+helper_np_app="${versioned_dir}/@MAC_PRODUCT_NAME@ Helper NP.app"
codesign -s "${codesign_id}" --keychain "${codesign_keychain}" "${framework}"
codesign -s "${codesign_id}" --keychain "${codesign_keychain}" "${helper_app}"
+codesign -s "${codesign_id}" --keychain "${codesign_keychain}" \
+ "${helper_eh_app}"
+codesign -s "${codesign_id}" --keychain "${codesign_keychain}" \
+ "${helper_np_app}"
# Verify everything.
codesign -v "${framework}"
codesign -v "${helper_app}"
+codesign -v "${helper_eh_app}"
+codesign -v "${helper_np_app}"
diff --git a/chrome/service/service_utility_process_host.cc b/chrome/service/service_utility_process_host.cc
index c633773..0c4e88c 100644
--- a/chrome/service/service_utility_process_host.cc
+++ b/chrome/service/service_utility_process_host.cc
@@ -116,7 +116,12 @@ bool ServiceUtilityProcessHost::StartProcess(bool no_sandbox,
}
FilePath ServiceUtilityProcessHost::GetUtilityProcessCmd() {
- return GetChildPath(true);
+#if defined(OS_LINUX)
+ int flags = CHILD_ALLOW_SELF;
+#else
+ int flags = CHILD_NORMAL;
+#endif
+ return GetChildPath(flags);
}
bool ServiceUtilityProcessHost::CanShutdown() {
diff --git a/chrome/test/base/chrome_process_util.cc b/chrome/test/base/chrome_process_util.cc
index 7bb93f7..4c046e2 100644
--- a/chrome/test/base/chrome_process_util.cc
+++ b/chrome/test/base/chrome_process_util.cc
@@ -4,8 +4,9 @@
#include "chrome/test/base/chrome_process_util.h"
-#include <vector>
#include <set>
+#include <string>
+#include <vector>
#include "base/command_line.h"
#include "base/process_util.h"
@@ -59,11 +60,32 @@ const FilePath::CharType* GetRunningBrowserExecutableName() {
return chrome::kBrowserProcessExecutableName;
}
-const FilePath::CharType* GetRunningHelperExecutableName() {
+std::vector<FilePath::StringType> GetRunningHelperExecutableNames() {
+ FilePath::StringType name;
const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
- if (cmd_line->HasSwitch(switches::kEnableChromiumBranding))
- return chrome::kHelperProcessExecutableNameChromium;
- return chrome::kHelperProcessExecutableName;
+ if (cmd_line->HasSwitch(switches::kEnableChromiumBranding)) {
+ name = chrome::kHelperProcessExecutableNameChromium;
+ } else {
+ name = chrome::kHelperProcessExecutableName;
+ }
+
+ std::vector<FilePath::StringType> names;
+ names.push_back(name);
+
+#if defined(OS_MACOSX)
+ // The helper might show up as these different flavors depending on the
+ // executable flags required.
+ for (const char* const* suffix = chrome::kHelperFlavorSuffixes;
+ *suffix;
+ ++suffix) {
+ std::string flavor_name(name);
+ flavor_name.append(1, ' ');
+ flavor_name.append(*suffix);
+ names.push_back(flavor_name);
+ }
+#endif
+
+ return names;
}
ChromeProcessList GetRunningChromeProcesses(base::ProcessId browser_pid) {
@@ -95,12 +117,16 @@ ChromeProcessList GetRunningChromeProcesses(base::ProcessId browser_pid) {
// on Linux via /proc/self/exe, so they end up with a different
// name. We must collect them in a second pass.
{
- ChildProcessFilter filter(browser_pid);
- base::NamedProcessIterator it(GetRunningHelperExecutableName(), &filter);
- while (const base::ProcessEntry* process_entry = it.NextProcessEntry())
- result.push_back(process_entry->pid());
+ std::vector<FilePath::StringType> names = GetRunningHelperExecutableNames();
+ for (size_t i = 0; i < names.size(); ++i) {
+ FilePath::StringType name = names[i];
+ ChildProcessFilter filter(browser_pid);
+ base::NamedProcessIterator it(name, &filter);
+ while (const base::ProcessEntry* process_entry = it.NextProcessEntry())
+ result.push_back(process_entry->pid());
+ }
}
-#endif // defined(OS_MACOSX)
+#endif // defined(OS_POSIX)
result.push_back(browser_pid);
diff --git a/chrome/tools/build/mac/make_locale_dirs.sh b/chrome/tools/build/mac/make_locale_dirs.sh
new file mode 100755
index 0000000..7636b15
--- /dev/null
+++ b/chrome/tools/build/mac/make_locale_dirs.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# usage: make_locale_dirs.sh locale_dir [...]
+#
+# This script creates the Resources directory for the bundle being built by
+# the Xcode target that calls it if the directory does not yet exist. It then
+# changes to that directory and creates subdirectories for each locale_dir
+# passed on the command line.
+#
+# This script is intended to create empty locale directories (.lproj) in a
+# Cocoa .app bundle. The presence of these empty directories is sufficient to
+# convince Cocoa that the application supports the named localization, even if
+# an InfoPlist.strings file is not provided. Chrome uses these empty locale
+# directoires for its helper executable bundles, which do not otherwise
+# require any direct Cocoa locale support.
+
+set -eu
+
+if [[ ${#} -eq 0 ]]; then
+ echo "usage: ${0} locale_dir [...]" >& 2
+ exit 1
+fi
+
+RESOURCES_DIR="${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+if [[ ! -d "${RESOURCES_DIR}" ]]; then
+ mkdir "${RESOURCES_DIR}"
+fi
+
+cd "${RESOURCES_DIR}"
+
+for dir in "${@}"; do
+ if [[ ! -d "${dir}" ]]; then
+ mkdir "${dir}"
+ fi
+done
diff --git a/chrome/tools/build/mac/make_more_helpers.sh b/chrome/tools/build/mac/make_more_helpers.sh
new file mode 100755
index 0000000..631c11b
--- /dev/null
+++ b/chrome/tools/build/mac/make_more_helpers.sh
@@ -0,0 +1,89 @@
+#!/bin/bash
+
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Usage: make_more_helpers.sh <version> <app_name>
+#
+# This script creates additional helper .app bundles for Chromium, based on
+# the existing helper .app bundle, changing their Mach-O header's flags to
+# enable and disable various features. Based on Chromium Helper.app, it will
+# create Chromium Helper EH.app, which has the MH_NO_HEAP_EXECUTION bit
+# cleared to support Chromium child processes that require an executable heap,
+# and Chromium Helper NP.app, which has the MH_PIE bit cleared to support
+# Chromium child processes that cannot tolerate ASLR.
+#
+# This script expects to be called from the chrome_exe target as a postbuild,
+# and operates directly within the built-up browser app's versioned directory.
+#
+# Each helper is adjusted by giving it the proper bundle name, renaming the
+# executable, adjusting several Info.plist keys, and changing the executable's
+# Mach-O flags.
+
+set -eu
+
+make_helper() {
+ local versioned_dir="${1}"
+ local app_name="${2}"
+ local feature="${3}"
+ local flags="${4}"
+
+ local helper_name="${app_name} Helper"
+ local helper_stem="${versioned_dir}/${helper_name}"
+ local original_helper="${helper_stem}.app"
+ if [[ ! -d "${original_helper}" ]]; then
+ echo "${0}: error: ${original_helper} is a required directory" >& 2
+ exit 1
+ fi
+ local original_helper_exe="${original_helper}/Contents/MacOS/${helper_name}"
+ if [[ ! -f "${original_helper_exe}" ]]; then
+ echo "${0}: error: ${original_helper_exe} is a required file" >& 2
+ exit 1
+ fi
+
+ local feature_helper="${helper_stem} ${feature}.app"
+
+ rsync -acC --delete --include '*.so' "${original_helper}/" "${feature_helper}"
+
+ local helper_feature="${helper_name} ${feature}"
+ local helper_feature_exe="${feature_helper}/Contents/MacOS/${helper_feature}"
+ mv "${feature_helper}/Contents/MacOS/${helper_name}" "${helper_feature_exe}"
+
+ local change_flags="\
+$(dirname "${0}")/../../../../build/mac/change_mach_o_flags.py"
+ "${change_flags}" ${flags} "${helper_feature_exe}"
+
+ local feature_info="${feature_helper}/Contents/Info"
+ local feature_info_plist="${feature_info}.plist"
+
+ defaults write "${feature_info}" "CFBundleDisplayName" "${helper_feature}"
+ defaults write "${feature_info}" "CFBundleExecutable" "${helper_feature}"
+
+ cfbundleid="$(defaults read "${feature_info}" "CFBundleIdentifier")"
+ feature_cfbundleid="${cfbundleid}.${feature}"
+ defaults write "${feature_info}" "CFBundleIdentifier" "${feature_cfbundleid}"
+
+ cfbundlename="$(defaults read "${feature_info}" "CFBundleName")"
+ feature_cfbundlename="${cfbundlename} ${feature}"
+ defaults write "${feature_info}" "CFBundleName" "${feature_cfbundlename}"
+
+ # As usual, defaults might have put the plist into whatever format excites
+ # it, but Info.plists get converted back to the expected XML format.
+ plutil -convert xml1 "${feature_info_plist}"
+}
+
+if [[ ${#} -ne 2 ]]; then
+ echo "usage: ${0} <version> <app_name>" >& 2
+ exit 1
+fi
+
+VERSION="${1}"
+APP_NAME="${2}"
+
+CONTENTS_DIR="${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}"
+VERSIONED_DIR="${CONTENTS_DIR}/Versions"
+CURRENT_VERSIONED_DIR="${VERSIONED_DIR}/${VERSION}"
+
+make_helper "${CURRENT_VERSIONED_DIR}" "${APP_NAME}" "EH" "--executable-heap"
+make_helper "${CURRENT_VERSIONED_DIR}" "${APP_NAME}" "NP" "--no-pie"
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 73184dd..48f3a74 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -519,7 +519,14 @@ bool GpuProcessHost::LaunchGpuProcess() {
CommandLine::StringType gpu_launcher =
browser_command_line.GetSwitchValueNative(switches::kGpuLauncher);
- FilePath exe_path = ChildProcessHost::GetChildPath(gpu_launcher.empty());
+#if defined(OS_LINUX)
+ int child_flags = gpu_launcher.empty() ? ChildProcessHost::CHILD_ALLOW_SELF :
+ ChildProcessHost::CHILD_NORMAL;
+#else
+ int child_flags = ChildProcessHost::CHILD_NORMAL;
+#endif
+
+ FilePath exe_path = ChildProcessHost::GetChildPath(child_flags);
if (exe_path.empty())
return false;
diff --git a/content/browser/plugin_process_host.cc b/content/browser/plugin_process_host.cc
index 722f046..c8fa8a4 100644
--- a/content/browser/plugin_process_host.cc
+++ b/content/browser/plugin_process_host.cc
@@ -175,7 +175,19 @@ bool PluginProcessHost::Init(const webkit::WebPluginInfo& info,
const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
CommandLine::StringType plugin_launcher =
browser_command_line.GetSwitchValueNative(switches::kPluginLauncher);
- FilePath exe_path = GetChildPath(plugin_launcher.empty());
+
+#if defined(OS_MACOSX)
+ // Run the plug-in process in a mode tolerant of heap execution without
+ // explicit mprotect calls. Some plug-ins still rely on this quaint and
+ // archaic "feature." See http://crbug.com/93551.
+ int flags = CHILD_ALLOW_HEAP_EXECUTION;
+#elif defined(OS_LINUX)
+ int flags = plugin_launcher.empty() ? CHILD_ALLOW_SELF : CHILD_NORMAL;
+#else
+ int flags = CHILD_NORMAL;
+#endif
+
+ FilePath exe_path = GetChildPath(flags);
if (exe_path.empty())
return false;
diff --git a/content/browser/ppapi_broker_process_host.cc b/content/browser/ppapi_broker_process_host.cc
index 387f943..9f94a67 100644
--- a/content/browser/ppapi_broker_process_host.cc
+++ b/content/browser/ppapi_broker_process_host.cc
@@ -36,7 +36,14 @@ bool PpapiBrokerProcessHost::Init(const PepperPluginInfo& info) {
CommandLine::StringType plugin_launcher =
browser_command_line.GetSwitchValueNative(switches::kPpapiPluginLauncher);
- FilePath exe_path = ChildProcessHost::GetChildPath(plugin_launcher.empty());
+#if defined(OS_LINUX)
+ int flags = plugin_launcher.empty() ? ChildProcessHost::CHILD_ALLOW_SELF :
+ ChildProcessHost::CHILD_NORMAL;
+#else
+ int flags = ChildProcessHost::CHILD_NORMAL;
+#endif
+
+ FilePath exe_path = ChildProcessHost::GetChildPath(flags);
if (exe_path.empty())
return false;
diff --git a/content/browser/renderer_host/browser_render_process_host.cc b/content/browser/renderer_host/browser_render_process_host.cc
index 256fb91..493ddc8 100644
--- a/content/browser/renderer_host/browser_render_process_host.cc
+++ b/content/browser/renderer_host/browser_render_process_host.cc
@@ -270,10 +270,16 @@ bool BrowserRenderProcessHost::Init(bool is_accessibility_enabled) {
browser_command_line.GetSwitchValueNative(switches::kRendererCmdPrefix);
#endif // defined(OS_POSIX)
+#if defined(OS_LINUX)
+ int flags = renderer_prefix.empty() ? ChildProcessHost::CHILD_ALLOW_SELF :
+ ChildProcessHost::CHILD_NORMAL;
+#else
+ int flags = ChildProcessHost::CHILD_NORMAL;
+#endif
+
// Find the renderer before creating the channel so if this fails early we
// return without creating the channel.
- FilePath renderer_path =
- ChildProcessHost::GetChildPath(renderer_prefix.empty());
+ FilePath renderer_path = ChildProcessHost::GetChildPath(flags);
if (renderer_path.empty())
return false;
diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc
index 44a7ef5..c62ec3e 100644
--- a/content/browser/utility_process_host.cc
+++ b/content/browser/utility_process_host.cc
@@ -61,7 +61,12 @@ void UtilityProcessHost::EndBatchMode() {
}
FilePath UtilityProcessHost::GetUtilityProcessCmd() {
- return GetChildPath(true);
+#if defined(OS_LINUX)
+ int flags = CHILD_ALLOW_SELF;
+#else
+ int flags = CHILD_NORMAL;
+#endif
+ return GetChildPath(flags);
}
bool UtilityProcessHost::StartProcess() {
diff --git a/content/browser/worker_host/worker_process_host.cc b/content/browser/worker_host/worker_process_host.cc
index f51aed6..6e47140 100644
--- a/content/browser/worker_host/worker_process_host.cc
+++ b/content/browser/worker_host/worker_process_host.cc
@@ -118,7 +118,13 @@ bool WorkerProcessHost::Init(int render_process_id) {
if (!CreateChannel())
return false;
- FilePath exe_path = GetChildPath(true);
+#if defined(OS_LINUX)
+ int flags = CHILD_ALLOW_SELF;
+#else
+ int flags = CHILD_NORMAL;
+#endif
+
+ FilePath exe_path = GetChildPath(flags);
if (exe_path.empty())
return false;
diff --git a/content/common/child_process_host.cc b/content/common/child_process_host.cc
index 6a14750..02a5bd6 100644
--- a/content/common/child_process_host.cc
+++ b/content/common/child_process_host.cc
@@ -6,6 +6,7 @@
#include "base/command_line.h"
#include "base/file_path.h"
+#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/path_service.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
@@ -19,6 +20,52 @@
#include "base/linux_util.h"
#endif // OS_LINUX
+#if defined(OS_MACOSX)
+namespace {
+
+// Given |path| identifying a Mac-style child process executable path, adjusts
+// it to correspond to |feature|. For a child process path such as
+// ".../Chromium Helper.app/Contents/MacOS/Chromium Helper", the transformed
+// path for feature "NP" would be
+// ".../Chromium Helper NP.app/Contents/MacOS/Chromium Helper NP". The new
+// path is returned.
+FilePath TransformPathForFeature(const FilePath& path,
+ const std::string& feature) {
+ std::string basename = path.BaseName().value();
+
+ FilePath macos_path = path.DirName();
+ const char kMacOSName[] = "MacOS";
+ DCHECK_EQ(kMacOSName, macos_path.BaseName().value());
+
+ FilePath contents_path = macos_path.DirName();
+ const char kContentsName[] = "Contents";
+ DCHECK_EQ(kContentsName, contents_path.BaseName().value());
+
+ FilePath helper_app_path = contents_path.DirName();
+ const char kAppExtension[] = ".app";
+ std::string basename_app = basename;
+ basename_app.append(kAppExtension);
+ DCHECK_EQ(basename_app, helper_app_path.BaseName().value());
+
+ FilePath root_path = helper_app_path.DirName();
+
+ std::string new_basename = basename;
+ new_basename.append(1, ' ');
+ new_basename.append(feature);
+ std::string new_basename_app = new_basename;
+ new_basename_app.append(kAppExtension);
+
+ FilePath new_path = root_path.Append(new_basename_app)
+ .Append(kContentsName)
+ .Append(kMacOSName)
+ .Append(new_basename);
+
+ return new_path;
+}
+
+} // namespace
+#endif // OS_MACOSX
+
ChildProcessHost::ChildProcessHost()
: ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)),
opening_channel_(false) {
@@ -39,7 +86,7 @@ void ChildProcessHost::AddFilter(IPC::ChannelProxy::MessageFilter* filter) {
}
// static
-FilePath ChildProcessHost::GetChildPath(bool allow_self) {
+FilePath ChildProcessHost::GetChildPath(int flags) {
FilePath child_path;
child_path = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
@@ -53,13 +100,33 @@ FilePath ChildProcessHost::GetChildPath(bool allow_self) {
// When running under Valgrind, forking /proc/self/exe ends up forking the
// Valgrind executable, which then crashes. However, it's almost safe to
// assume that the updates won't happen while testing with Valgrind tools.
- if (allow_self && !RunningOnValgrind())
+ if (flags & CHILD_ALLOW_SELF && !RunningOnValgrind())
return FilePath("/proc/self/exe");
#endif
// On most platforms, the child executable is the same as the current
// executable.
PathService::Get(content::CHILD_PROCESS_EXE, &child_path);
+
+#if defined(OS_MACOSX)
+ DCHECK(!(flags & CHILD_NO_PIE && flags & CHILD_ALLOW_HEAP_EXECUTION));
+
+ // If needed, choose an executable with special flags set that inform the
+ // kernel to enable or disable specific optional process-wide features.
+ if (flags & CHILD_NO_PIE) {
+ // "NP" is "No PIE". This results in Chromium Helper NP.app or
+ // Google Chrome Helper NP.app.
+ child_path = TransformPathForFeature(child_path, "NP");
+ } else if (flags & CHILD_ALLOW_HEAP_EXECUTION) {
+ // "EH" is "Executable Heap". A non-executable heap is only available to
+ // 32-bit processes on Mac OS X 10.7. Most code can and should run with a
+ // non-executable heap, but the "EH" feature is provided to allow code
+ // intolerant of a non-executable heap to work properly on 10.7. This
+ // results in Chromium Helper EH.app or Google Chrome Helper EH.app.
+ child_path = TransformPathForFeature(child_path, "EH");
+ }
+#endif
+
return child_path;
}
diff --git a/content/common/child_process_host.h b/content/common/child_process_host.h
index 7fd7082..8637c18 100644
--- a/content/common/child_process_host.h
+++ b/content/common/child_process_host.h
@@ -33,6 +33,42 @@ class Message;
class ChildProcessHost : public IPC::Channel::Listener,
public IPC::Message::Sender {
public:
+
+ // These flags may be passed to GetChildPath in order to alter its behavior,
+ // causing it to return a child path more suited to a specific task.
+ enum {
+ // No special behavior requested.
+ CHILD_NORMAL = 0,
+
+#if defined(OS_LINUX)
+ // Indicates that the child execed after forking may be execced from
+ // /proc/self/exe rather than using the "real" app path. This prevents
+ // autoupdate from confusing us if it changes the file out from under us.
+ // You will generally want to set this on Linux, except when there is an
+ // override to the command line (for example, we're forking a renderer in
+ // gdb). In this case, you'd use GetChildPath to get the real executable
+ // file name, and then prepend the GDB command to the command line.
+ CHILD_ALLOW_SELF = 1 << 0,
+#elif defined(OS_MACOSX)
+
+ // Requests that the child run in a process that does not have the
+ // PIE (position-independent executable) bit set, effectively disabling
+ // ASLR. For process types that need to allocate a large contiguous
+ // region, ASLR may not leave a large enough "hole" for the purpose. This
+ // option should be used sparingly, and only when absolutely necessary.
+ // This option is currently incompatible with CHILD_ALLOW_HEAP_EXECUTION.
+ CHILD_NO_PIE = 1 << 1,
+
+ // Requests that the child run in a process that does not protect the
+ // heap against execution. Normally, heap pages may be made executable
+ // with mprotect, so this mode should be used sparingly. It is intended
+ // for processes that may host plug-ins that expect an executable heap
+ // without having to call mprotect. This option is currently incompatible
+ // with CHILD_NO_PIE.
+ CHILD_ALLOW_HEAP_EXECUTION = 1 << 2,
+#endif
+ };
+
virtual ~ChildProcessHost();
// Returns the pathname to be used for a child process. If a subprocess
@@ -40,16 +76,12 @@ class ChildProcessHost : public IPC::Channel::Listener,
// the default child process pathname will be returned. On most platforms,
// this will be the same as the currently-executing process.
//
- // The argument allow_self is used on Linux to indicate that we allow us to
- // fork from /proc/self/exe rather than using the "real" app path. This
- // prevents autoupdate from confusing us if it changes the file out from
- // under us. You will generally want to set this to true, except when there
- // is an override to the command line (for example, we're forking a renderer
- // in gdb). In this case, you'd use GetChildPath to get the real executable
- // file name, and then prepend the GDB command to the command line.
+ // The |flags| argument accepts one or more flags such as CHILD_ALLOW_SELF
+ // and CHILD_ALLOW_HEAP_EXECUTION as defined above. Pass only CHILD_NORMAL
+ // if none of these special behaviors are required.
//
// On failure, returns an empty FilePath.
- static FilePath GetChildPath(bool allow_self);
+ static FilePath GetChildPath(int flags);
#if defined(OS_WIN)
// See comments in the cc file. This is a common hack needed for a process
diff --git a/content/common/plugin_carbon_interpose_constants_mac.cc b/content/common/plugin_carbon_interpose_constants_mac.cc
index 956d6fc..2ff5dd0 100644
--- a/content/common/plugin_carbon_interpose_constants_mac.cc
+++ b/content/common/plugin_carbon_interpose_constants_mac.cc
@@ -10,7 +10,7 @@ namespace plugin_interpose_strings {
const char kDYLDInsertLibrariesKey[] = "DYLD_INSERT_LIBRARIES";
const char kInterposeLibraryPath[] =
- "@executable_path/libplugin_carbon_interpose.dylib";
+ "@executable_path/../../../libplugin_carbon_interpose.dylib";
} // namespace plugin_interpose_strings