diff options
author | mark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-24 03:33:36 +0000 |
---|---|---|
committer | mark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-24 03:33:36 +0000 |
commit | 8c40f3212b62b828f3cfbe151fb3ecd2294e44ca (patch) | |
tree | ea582d6c5b274418ff853eb67bc8bbbe2ed2d619 | |
parent | 06ead8788ef8d9ea7e5db736d563a7fb25df059d (diff) | |
download | chromium_src-8c40f3212b62b828f3cfbe151fb3ecd2294e44ca.zip chromium_src-8c40f3212b62b828f3cfbe151fb3ecd2294e44ca.tar.gz chromium_src-8c40f3212b62b828f3cfbe151fb3ecd2294e44ca.tar.bz2 |
Give plug-in processes an executable heap and disable PIE/ASLR for Native
Client loader processes.
Some plug-ins depend on having an executable heap. They write code to data
pages and attempt to execute it without calling mprotect to mark this code
as executable.
Native Client needs to allocate a contiguous 1GB of address space. ASLR may
interfere with there being a "hole" this large in the address space by the
time NaCl makes its request.
Non-executable heaps are only available in 10.7 and later for 32-bit
processes.
PIE/ASLR was formerly disabled for all processes other than the browser
process. This change reenables it for all processes other than the NaCl
loader. PIE/ASLR is available on 10.5 and later, although the implementation
is stronger in 10.7 than in earlier releases.
This change results in two new helpers in addition to the existing
Chromium Helper.app: Chromium Helper EH.app (for executable heaps) and
Chromium Helper NP.app (for no PIE). libplugin_carbon_interpose.dylib moves
out of the helper .app and directly into the versioned directory. The
InfoPlist.strings have been removed from the helper app, but empty .lproj
directories remain.
BUG=90221, 93551
TEST=everything
Review URL: http://codereview.chromium.org/7714018
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@97984 0039d316-1c4b-4281-b951-d872f2087c98
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 |