mac: Introduce libaperitif.dylib
Chrome currently has several .app executables packaged within its bundle and the the Framework. Each one of these executables statically links libc++, and in the helpers, a //sandbox target. Apéritif moves the C++ components of early app initialization into a shared library, reducing the size of each of the executables. The executable main file transitions back to being a plain C file rather than C++ to avoid linking in libc++. In order to support linking the library to multiple images at different bundle depths, the linker_driver.py gains the ability to run install_name_tool as part of the link step. Disk size changes for an x86_64, official, branded, stripped build: 17168 out/official/aperitif/Google Chrome.app/Contents/MacOS/Google Chrome 214512 out/official/pristine/Google Chrome.app/Contents/MacOS/Google Chrome 17240 out/official/aperitif/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Helpers/Google Chrome Helper (Alerts).app/Contents/MacOS/Google Chrome Helper (Alerts) 17240 out/official/aperitif/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Helpers/Google Chrome Helper (GPU).app/Contents/MacOS/Google Chrome Helper (GPU) 17240 out/official/aperitif/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Helpers/Google Chrome Helper (Plugin).app/Contents/MacOS/Google Chrome Helper (Plugin) 17240 out/official/aperitif/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Helpers/Google Chrome Helper (Renderer).app/Contents/MacOS/Google Chrome Helper (Renderer) 17240 out/official/aperitif/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Helpers/Google Chrome Helper.app/Contents/MacOS/Google Chrome Helper 264736 out/official/pristine/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Helpers/Google Chrome Helper (Alerts).app/Contents/MacOS/Google Chrome Helper (Alerts) 264736 out/official/pristine/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Helpers/Google Chrome Helper (GPU).app/Contents/MacOS/Google Chrome Helper (GPU) 264736 out/official/pristine/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Helpers/Google Chrome Helper (Plugin).app/Contents/MacOS/Google Chrome Helper (Plugin) 264736 out/official/pristine/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Helpers/Google Chrome Helper (Renderer).app/Contents/MacOS/Google Chrome Helper (Renderer) 264736 out/official/pristine/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Helpers/Google Chrome Helper.app/Contents/MacOS/Google Chrome Helper 338400 out/official/aperitif/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Libraries/libaperitif.dylib 0 (NA) out/official/pristine/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Libraries/libaperitif.dylib 179263608 out/official/aperitif/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Versions/Current/Google Chrome Framework 179263608 out/official/pristine/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Versions/Current/Google Chrome Framework As reported by `du -k`: 261464 out/official/aperitif/Google Chrome.app 262524 out/official/pristine/Google Chrome.app As reported by Finder Get Info: 267,309,919 bytes (267.7 MB on disk) out/official/aperitif 268,406,343 bytes (268.8 MB on disk) out/official/pristine Bug: 1255223 Change-Id: I4e3c0fa542f2f7f1eae5df9b2c71d6840bc4a30e Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3430220 Reviewed-by: Avi Drissman <avi@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> Reviewed-by: Andrew Grieve <agrieve@chromium.org> Commit-Queue: Robert Sesek <rsesek@chromium.org> Cr-Commit-Position: refs/heads/main@{#978773}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
90f5399806
commit
31576eb814
PRESUBMIT.py
build/toolchain/apple
chrome
content
app
public
shell
sandbox/mac
@ -2343,6 +2343,7 @@ def CheckSpamLogging(input_api, output_api):
|
||||
r"notification_event_dispatcher_impl\.cc$",
|
||||
r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
|
||||
r"gl_helper_benchmark\.cc$",
|
||||
r"^content[\\/]app[\\/]aperitif_mac\.cc$",
|
||||
r"^courgette[\\/]courgette_minimal_tool\.cc$",
|
||||
r"^courgette[\\/]courgette_tool\.cc$",
|
||||
r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
|
||||
|
@ -28,6 +28,15 @@ LINKER_DRIVER_ARG_PREFIX = '-Wcrl,'
|
||||
# removal of the special driver arguments, described below). Then the driver
|
||||
# performs additional actions, based on these arguments:
|
||||
#
|
||||
# -Wcrl,installnametoolpath,<install_name_tool_path>
|
||||
# Sets the path to the `install_name_tool` to run with
|
||||
# -Wcrl,installnametool, in which case `xcrun` is not used to invoke it.
|
||||
#
|
||||
# -Wcrl,installnametool,<arguments,...>
|
||||
# After invoking the linker, this will run install_name_tool on the linker's
|
||||
# output. |arguments| are comma-separated arguments to be passed to the
|
||||
# install_name_tool command.
|
||||
#
|
||||
# -Wcrl,dsym,<dsym_path_prefix>
|
||||
# After invoking the linker, this will run `dsymutil` on the linker's
|
||||
# output, producing a dSYM bundle, stored at dsym_path_prefix. As an
|
||||
@ -69,6 +78,8 @@ class LinkerDriver(object):
|
||||
# The first item in the tuple is the argument's -Wcrl,<sub_argument>
|
||||
# and the second is the function to invoke.
|
||||
self._actions = [
|
||||
('installnametoolpath,', self.set_install_name_tool_path),
|
||||
('installnametool,', self.run_install_name_tool),
|
||||
('dsymutilpath,', self.set_dsymutil_path),
|
||||
('dsym,', self.run_dsymutil),
|
||||
('unstripped,', self.run_save_unstripped),
|
||||
@ -77,6 +88,7 @@ class LinkerDriver(object):
|
||||
]
|
||||
|
||||
# Linker driver actions can modify the these values.
|
||||
self._install_name_tool_cmd = ['xcrun', 'install_name_tool']
|
||||
self._dsymutil_cmd = ['xcrun', 'dsymutil']
|
||||
self._strip_cmd = ['xcrun', 'strip']
|
||||
|
||||
@ -164,6 +176,40 @@ class LinkerDriver(object):
|
||||
|
||||
raise ValueError('Unknown linker driver argument: %s' % (arg, ))
|
||||
|
||||
def set_install_name_tool_path(self, install_name_tool_path):
|
||||
"""Linker driver action for -Wcrl,installnametoolpath,<path>.
|
||||
|
||||
Sets the invocation command for install_name_tool, which allows the
|
||||
caller to specify an alternate path. This action is always
|
||||
processed before the run_install_name_tool action.
|
||||
|
||||
Args:
|
||||
install_name_tool_path: string, The path to the install_name_tool
|
||||
binary to run
|
||||
|
||||
Returns:
|
||||
No output - this step is run purely for its side-effect.
|
||||
"""
|
||||
self._install_name_tool_cmd = [install_name_tool_path]
|
||||
return []
|
||||
|
||||
def run_install_name_tool(self, args_string):
|
||||
"""Linker driver action for -Wcrl,installnametool,<args>. Invokes
|
||||
install_name_tool on the linker's output.
|
||||
|
||||
Args:
|
||||
args_string: string, Comma-separated arguments for
|
||||
`install_name_tool`.
|
||||
|
||||
Returns:
|
||||
No output - this step is run purely for its side-effect.
|
||||
"""
|
||||
command = list(self._install_name_tool_cmd)
|
||||
command.extend(args_string.split(','))
|
||||
command.append(self._get_linker_output())
|
||||
subprocess.check_call(command)
|
||||
return []
|
||||
|
||||
def run_dsymutil(self, dsym_path_prefix):
|
||||
"""Linker driver action for -Wcrl,dsym,<dsym-path-prefix>. Invokes
|
||||
dsymutil on the linker's output and produces a dsym file at |dsym_file|
|
||||
|
@ -170,7 +170,8 @@ template("apple_toolchain") {
|
||||
|
||||
# Specify an explicit path for the strip binary.
|
||||
_strippath = invoker.bin_path + "strip"
|
||||
linker_driver += " -Wcrl,strippath," + _strippath
|
||||
_installnametoolpath = invoker.bin_path + "install_name_tool"
|
||||
linker_driver += " -Wcrl,strippath,${_strippath} -Wcrl,installnametoolpath,${_installnametoolpath}"
|
||||
|
||||
# On iOS, the final applications are assembled using lipo (to support fat
|
||||
# builds). The correct flags are passed to the linker_driver.py script
|
||||
|
@ -467,18 +467,27 @@ if (is_win) {
|
||||
"CHROMIUM_CREATOR=$chrome_mac_creator_code",
|
||||
]
|
||||
|
||||
sources = [ "app/chrome_exe_main_mac.cc" ]
|
||||
sources = [ "app/chrome_exe_main_mac.c" ]
|
||||
|
||||
extra_configs = [ "//build/config/compiler:wexit_time_destructors" ]
|
||||
|
||||
# No libc++ needed, there’s only C code in this module.
|
||||
no_default_deps = true
|
||||
|
||||
deps = [
|
||||
":chrome_app_strings_bundle_data",
|
||||
":chrome_resources",
|
||||
":chrome_versioned_bundle_data",
|
||||
"//base/allocator:early_zone_registration_mac",
|
||||
"//build:branding_buildflags",
|
||||
"//chrome/common:buildflags",
|
||||
"//chrome/common:version_header",
|
||||
"//content/public/app:aperitif",
|
||||
]
|
||||
|
||||
ldflags = [
|
||||
# Needed for lld: https://github.com/llvm/llvm-project/issues/53550.
|
||||
"-Wl,-headerpad_max_install_names",
|
||||
"-Wcrl,installnametool,-change,libaperitif.dylib,@executable_path/../Frameworks/$chrome_framework_name.framework/Versions/$chrome_version_full/Libraries/libaperitif.dylib",
|
||||
]
|
||||
|
||||
if (enable_stripping) {
|
||||
@ -486,8 +495,8 @@ if (is_win) {
|
||||
# file. All other global symbols will be marked as private. The default
|
||||
# //build/config/mac:strip_all config will then remove the remaining
|
||||
# local and debug symbols.
|
||||
ldflags = [ "-Wl,-exported_symbols_list," +
|
||||
rebase_path("app/app.exports", root_build_dir) ]
|
||||
ldflags += [ "-Wl,-exported_symbols_list," +
|
||||
rebase_path("app/app.exports", root_build_dir) ]
|
||||
}
|
||||
|
||||
if (is_component_build) {
|
||||
@ -495,7 +504,7 @@ if (is_win) {
|
||||
# executable because dlopen() and loading all the dependent dylibs
|
||||
# is time-consuming, see https://crbug.com/1197495.
|
||||
deps += [ ":chrome_framework+link" ]
|
||||
ldflags = [ "-Wl,-rpath,@executable_path/../Frameworks" ]
|
||||
ldflags += [ "-Wl,-rpath,@executable_path/../Frameworks" ]
|
||||
|
||||
# The Framework is packaged inside the .app bundle. But when using the
|
||||
# component build, all the dependent shared libraries of :chrome_dll are
|
||||
@ -511,6 +520,39 @@ if (is_win) {
|
||||
}
|
||||
}
|
||||
|
||||
if (verify_dynamic_libraries) {
|
||||
action("verify_libraries_aperitif") {
|
||||
script = "//chrome/tools/build/mac/verify_dynamic_libraries.py"
|
||||
inputs = [ "$root_out_dir/libaperitif.dylib" ]
|
||||
outputs = [ "$target_out_dir/run_$target_name.stamp" ]
|
||||
args = [
|
||||
"--stamp",
|
||||
rebase_path(outputs[0], root_out_dir),
|
||||
"-B",
|
||||
objdump_path,
|
||||
"--image",
|
||||
rebase_path(inputs[0], root_out_dir),
|
||||
|
||||
# Do not --allow more libraries here without consulting with the
|
||||
# security team (security-dev@chromium.org).
|
||||
"--allow",
|
||||
"/usr/lib/libsandbox.1.dylib",
|
||||
"--allow",
|
||||
"/usr/lib/libSystem.B.dylib",
|
||||
]
|
||||
deps = [ "//content/public/app:aperitif" ]
|
||||
}
|
||||
}
|
||||
|
||||
bundle_data("aperitif_library") {
|
||||
sources = [ "$root_out_dir/libaperitif.dylib" ]
|
||||
outputs = [ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}" ]
|
||||
public_deps = [ "//content/public/app:aperitif" ]
|
||||
if (verify_dynamic_libraries) {
|
||||
public_deps += [ ":verify_libraries_aperitif" ]
|
||||
}
|
||||
}
|
||||
|
||||
if (verify_dynamic_libraries) {
|
||||
action("verify_libraries_chrome_app") {
|
||||
script = "//chrome/tools/build/mac/verify_dynamic_libraries.py"
|
||||
@ -525,6 +567,8 @@ if (is_win) {
|
||||
rebase_path(inputs[0], root_out_dir),
|
||||
"--allow",
|
||||
"/usr/lib/libSystem.B.dylib",
|
||||
"--allow",
|
||||
"@executable_path/../Frameworks/$chrome_framework_name.framework/Versions/$chrome_version_full/Libraries/libaperitif.dylib",
|
||||
]
|
||||
deps = [ ":chrome_app" ]
|
||||
}
|
||||
@ -709,24 +753,30 @@ if (is_win) {
|
||||
"CHROMIUM_HELPER_BUNDLE_ID_SUFFIX=${invoker.helper_bundle_id_suffix}",
|
||||
]
|
||||
|
||||
sources = [ "app/chrome_exe_main_mac.cc" ]
|
||||
sources = [ "app/chrome_exe_main_mac.c" ]
|
||||
|
||||
extra_configs = [ "//build/config/compiler:wexit_time_destructors" ]
|
||||
|
||||
defines = [ "HELPER_EXECUTABLE" ]
|
||||
|
||||
# No libc++ needed, there’s only C code in this module.
|
||||
no_default_deps = true
|
||||
|
||||
deps = [
|
||||
"//base/allocator:early_zone_registration_mac",
|
||||
"//build:branding_buildflags",
|
||||
"//chrome/common:version_header",
|
||||
"//sandbox/mac:seatbelt",
|
||||
"//content/public/app:aperitif",
|
||||
]
|
||||
|
||||
if (defined(invoker.deps)) {
|
||||
deps += invoker.deps
|
||||
}
|
||||
|
||||
ldflags = []
|
||||
ldflags = [
|
||||
# Needed for lld: https://github.com/llvm/llvm-project/issues/53550.
|
||||
"-Wl,-headerpad_max_install_names",
|
||||
"-Wcrl,installnametool,-change,libaperitif.dylib,@executable_path/../../../../Libraries/libaperitif.dylib",
|
||||
]
|
||||
|
||||
if (is_component_build) {
|
||||
# In a component build, the framework is directly linked to the
|
||||
@ -841,9 +891,9 @@ if (is_win) {
|
||||
# Do not --allow more libraries here without consulting with the
|
||||
# security team (security-dev@chromium.org).
|
||||
"--allow",
|
||||
"/usr/lib/libsandbox.1.dylib",
|
||||
"--allow",
|
||||
"/usr/lib/libSystem.B.dylib",
|
||||
"--allow",
|
||||
"@executable_path/../../../../Libraries/libaperitif.dylib",
|
||||
]
|
||||
deps = [ ":chrome_helper_app_${_helper_target}" ]
|
||||
}
|
||||
@ -1176,6 +1226,7 @@ if (is_win) {
|
||||
|
||||
bundle_deps = [
|
||||
":angle_library",
|
||||
":aperitif_library",
|
||||
":chrome_framework_helpers",
|
||||
":chrome_framework_plugins",
|
||||
":chrome_framework_resources",
|
||||
@ -1199,9 +1250,12 @@ if (is_win) {
|
||||
]
|
||||
|
||||
if (!is_component_build) {
|
||||
# Specify a sensible install_name for static builds. The library is
|
||||
# dlopen()ed so this is not used to resolve the module.
|
||||
ldflags += [ "-Wl,-install_name,@executable_path/../Frameworks/$chrome_framework_name.framework/Versions/$chrome_version_full/$chrome_framework_name" ]
|
||||
ldflags += [
|
||||
# Specify a sensible install_name for static builds. The library is
|
||||
# dlopen()ed so this is not used to resolve the module.
|
||||
"-Wl,-install_name,@executable_path/../Frameworks/$chrome_framework_name.framework/Versions/$chrome_version_full/$chrome_framework_name",
|
||||
"-Wcrl,installnametool,-change,libaperitif.dylib,@loader_path/Libraries/libaperitif.dylib",
|
||||
]
|
||||
} else {
|
||||
# In the component build, both the :chrome_app and various
|
||||
# :chrome_helper* targets directly link to the Framework target. Use
|
||||
@ -1213,7 +1267,10 @@ if (is_win) {
|
||||
"-Wl,-reexport_library,libchrome_dll.dylib",
|
||||
]
|
||||
|
||||
data_deps = [ ":chrome_dll" ]
|
||||
data_deps = [
|
||||
":chrome_dll",
|
||||
"//content/public/app:aperitif",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1269,6 +1326,7 @@ if (is_win) {
|
||||
"$root_out_dir/chrome_crashpad_handler",
|
||||
"$root_out_dir/libEGL.dylib",
|
||||
"$root_out_dir/libGLESv2.dylib",
|
||||
"$root_out_dir/libaperitif.dylib",
|
||||
"$root_out_dir/libswiftshader_libEGL.dylib",
|
||||
"$root_out_dir/libswiftshader_libGLESv2.dylib",
|
||||
"$root_out_dir/libvk_swiftshader.dylib",
|
||||
@ -1305,6 +1363,7 @@ if (is_win) {
|
||||
":chrome_app",
|
||||
":chrome_framework",
|
||||
"//components/crash/core/app:chrome_crashpad_handler",
|
||||
"//content/public/app:aperitif",
|
||||
"//third_party/angle:libEGL",
|
||||
"//third_party/angle:libGLESv2",
|
||||
"//third_party/breakpad:dump_syms",
|
||||
@ -1332,6 +1391,7 @@ if (is_win) {
|
||||
"$root_out_dir/$chrome_framework_name.dSYM",
|
||||
"$root_out_dir/$chrome_product_full_name.dSYM",
|
||||
"$root_out_dir/chrome_crashpad_handler.dSYM",
|
||||
"$root_out_dir/libaperitif.dylib.dSYM",
|
||||
"$root_out_dir/libEGL.dylib.dSYM",
|
||||
"$root_out_dir/libGLESv2.dylib.dSYM",
|
||||
"$root_out_dir/libswiftshader_libEGL.dylib.dSYM",
|
||||
@ -1346,6 +1406,7 @@ if (is_win) {
|
||||
":chrome_app",
|
||||
":chrome_framework",
|
||||
"//components/crash/core/app:chrome_crashpad_handler",
|
||||
"//content/public/app:aperitif",
|
||||
"//third_party/angle:libEGL",
|
||||
"//third_party/angle:libGLESv2",
|
||||
"//third_party/swiftshader/src/OpenGL/libEGL:swiftshader_libEGL",
|
||||
|
@ -55,8 +55,9 @@ per-file *.plist=file://chrome/browser/ui/cocoa/OWNERS
|
||||
|
||||
per-file chrome_crash_reporter_client*=rsesek@chromium.org
|
||||
|
||||
per-file chrome_exe_main_mac.cc=kerrnel@chromium.org
|
||||
per-file chrome_exe_main_mac.cc=mark@chromium.org
|
||||
per-file chrome_exe_main_mac.c=kerrnel@chromium.org
|
||||
per-file chrome_exe_main_mac.c=mark@chromium.org
|
||||
per-file chrome_exe_main_mac.c=rsesek@chromium.org
|
||||
|
||||
per-file main_dll_loader_win.cc=brucedawson@chromium.org
|
||||
per-file main_dll_loader_win.cc=wfh@chromium.org
|
||||
|
@ -8,35 +8,17 @@
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/allocator/early_zone_registration_mac.h"
|
||||
#include "build/branding_buildflags.h"
|
||||
#include "build/build_config.h"
|
||||
#include "chrome/common/chrome_version.h"
|
||||
|
||||
#if defined(HELPER_EXECUTABLE)
|
||||
#include "sandbox/mac/seatbelt_exec.h" // nogncheck
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
// abort_report_np() records the message in a special section that both the
|
||||
// system CrashReporter and Crashpad collect in crash reports. Using a Crashpad
|
||||
// Annotation would be preferable, but this executable cannot depend on
|
||||
// Crashpad directly.
|
||||
void abort_report_np(const char* fmt, ...);
|
||||
}
|
||||
|
||||
namespace {
|
||||
#include "content/public/app/aperitif_mac.h"
|
||||
|
||||
typedef int (*ChromeMainPtr)(int, char**);
|
||||
|
||||
@ -125,85 +107,57 @@ typedef int (*ChromeMainPtr)(int, char**);
|
||||
// If the main executable has a significant change in size, this will need to be
|
||||
// revised. Hopefully a more elegant solution will become apparent before that's
|
||||
// required.
|
||||
__attribute__((used)) const char kGrossPaddingForCrbug1300598[68 * 1024] = {};
|
||||
static __attribute__((used))
|
||||
const char kGrossPaddingForCrbug1300598[68 * 1024] = {};
|
||||
#endif
|
||||
|
||||
[[noreturn]] void FatalError(const char* format, ...) {
|
||||
va_list valist;
|
||||
va_start(valist, format);
|
||||
char message[4096];
|
||||
if (vsnprintf(message, sizeof(message), format, valist) >= 0) {
|
||||
fputs(message, stderr);
|
||||
abort_report_np("%s", message);
|
||||
}
|
||||
va_end(valist);
|
||||
abort();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
__attribute__((visibility("default"))) int main(int argc, char* argv[]) {
|
||||
partition_alloc::EarlyMallocZoneRegistration();
|
||||
AperitifInitializePartitionAlloc();
|
||||
|
||||
uint32_t exec_path_size = 0;
|
||||
int rv = _NSGetExecutablePath(NULL, &exec_path_size);
|
||||
if (rv != -1) {
|
||||
FatalError("_NSGetExecutablePath: get length failed.");
|
||||
}
|
||||
|
||||
std::unique_ptr<char[]> exec_path(new char[exec_path_size]);
|
||||
rv = _NSGetExecutablePath(exec_path.get(), &exec_path_size);
|
||||
char exec_path[PATH_MAX];
|
||||
uint32_t exec_path_size = sizeof(exec_path);
|
||||
int rv = _NSGetExecutablePath(exec_path, &exec_path_size);
|
||||
if (rv != 0) {
|
||||
FatalError("_NSGetExecutablePath: get path failed.");
|
||||
AperitifFatalError("_NSGetExecutablePath: get path failed.");
|
||||
}
|
||||
|
||||
#if defined(HELPER_EXECUTABLE)
|
||||
sandbox::SeatbeltExecServer::CreateFromArgumentsResult seatbelt =
|
||||
sandbox::SeatbeltExecServer::CreateFromArguments(exec_path.get(), argc,
|
||||
argv);
|
||||
if (seatbelt.sandbox_required) {
|
||||
if (!seatbelt.server) {
|
||||
FatalError("Failed to create seatbelt sandbox server.");
|
||||
}
|
||||
if (!seatbelt.server->InitializeSandbox()) {
|
||||
FatalError("Failed to initialize sandbox.");
|
||||
}
|
||||
}
|
||||
// Start the sandbox before loading the framework.
|
||||
AperitifInitializeSandbox(exec_path, argc, (const char**)argv);
|
||||
|
||||
// The helper lives within the versioned framework directory, so simply
|
||||
// go up to find the main dylib.
|
||||
const char rel_path[] = "../../../../" PRODUCT_FULLNAME_STRING " Framework";
|
||||
static const char rel_path[] =
|
||||
"../../../../" PRODUCT_FULLNAME_STRING " Framework";
|
||||
#else
|
||||
const char rel_path[] = "../Frameworks/" PRODUCT_FULLNAME_STRING
|
||||
" Framework.framework/Versions/" CHROME_VERSION_STRING
|
||||
"/" PRODUCT_FULLNAME_STRING " Framework";
|
||||
static const char rel_path[] =
|
||||
"../Frameworks/" PRODUCT_FULLNAME_STRING
|
||||
" Framework.framework/Versions/" CHROME_VERSION_STRING
|
||||
"/" PRODUCT_FULLNAME_STRING " Framework";
|
||||
#endif // defined(HELPER_EXECUTABLE)
|
||||
|
||||
// Slice off the last part of the main executable path, and append the
|
||||
// version framework information.
|
||||
const char* parent_dir = dirname(exec_path.get());
|
||||
const char* parent_dir = dirname(exec_path);
|
||||
if (!parent_dir) {
|
||||
FatalError("dirname %s: %s.", exec_path.get(), strerror(errno));
|
||||
AperitifFatalError("dirname %s: %s.", exec_path, strerror(errno));
|
||||
}
|
||||
|
||||
const size_t parent_dir_len = strlen(parent_dir);
|
||||
const size_t rel_path_len = strlen(rel_path);
|
||||
// 2 accounts for a trailing NUL byte and the '/' in the middle of the paths.
|
||||
const size_t framework_path_size = parent_dir_len + rel_path_len + 2;
|
||||
std::unique_ptr<char[]> framework_path(new char[framework_path_size]);
|
||||
snprintf(framework_path.get(), framework_path_size, "%s/%s", parent_dir,
|
||||
rel_path);
|
||||
char framework_path[PATH_MAX];
|
||||
rv = snprintf(framework_path, sizeof(framework_path), "%s/%s", parent_dir,
|
||||
rel_path);
|
||||
if (rv < 0 || (size_t)rv >= sizeof(framework_path)) {
|
||||
AperitifFatalError("snprintf: %d.", rv);
|
||||
}
|
||||
|
||||
void* library =
|
||||
dlopen(framework_path.get(), RTLD_LAZY | RTLD_LOCAL | RTLD_FIRST);
|
||||
void* library = dlopen(framework_path, RTLD_LAZY | RTLD_LOCAL | RTLD_FIRST);
|
||||
if (!library) {
|
||||
FatalError("dlopen %s: %s.", framework_path.get(), dlerror());
|
||||
AperitifFatalError("dlopen %s: %s.", framework_path, dlerror());
|
||||
}
|
||||
|
||||
const ChromeMainPtr chrome_main =
|
||||
reinterpret_cast<ChromeMainPtr>(dlsym(library, "ChromeMain"));
|
||||
const ChromeMainPtr chrome_main = dlsym(library, "ChromeMain");
|
||||
if (!chrome_main) {
|
||||
FatalError("dlsym ChromeMain: %s.", dlerror());
|
||||
AperitifFatalError("dlsym ChromeMain: %s.", dlerror());
|
||||
}
|
||||
rv = chrome_main(argc, argv);
|
||||
|
@ -118,6 +118,7 @@ def get_parts(config):
|
||||
}
|
||||
|
||||
dylibs = [
|
||||
'libaperitif.dylib',
|
||||
'libEGL.dylib',
|
||||
'libGLESv2.dylib',
|
||||
'libswiftshader_libEGL.dylib',
|
||||
|
@ -27,6 +27,13 @@ def verify_image_libraries(image_path, allowed_libraries, binary_path):
|
||||
links against allowed libraries, and otherwise returns False with an error
|
||||
printed.
|
||||
"""
|
||||
# If |image_path| is a dynamic library, allow the LC_DYLIB_ID implicitly.
|
||||
output = subprocess.check_output(
|
||||
[binary_path + 'llvm-objdump', '--macho', '--dylib-id', image_path])
|
||||
dylib_id = output.decode('utf8').split('\n')[1]
|
||||
if dylib_id:
|
||||
allowed_libraries.append(dylib_id)
|
||||
|
||||
output = subprocess.check_output(
|
||||
[binary_path + 'llvm-objdump', '--macho', '--dylibs-used', image_path])
|
||||
output = output.decode('utf8').strip()
|
||||
|
@ -133,6 +133,17 @@ source_set("app") {
|
||||
}
|
||||
}
|
||||
|
||||
if (is_mac) {
|
||||
source_set("aperitif") {
|
||||
sources = [ "aperitif_mac.cc" ]
|
||||
deps = [
|
||||
"//base/allocator:early_zone_registration_mac",
|
||||
"//sandbox/mac:seatbelt",
|
||||
]
|
||||
visibility = [ "//content/public/app:aperitif" ]
|
||||
}
|
||||
}
|
||||
|
||||
# See comment at the top of //content/BUILD.gn for how this works.
|
||||
group("for_content_tests") {
|
||||
visibility = [ "//content/test/*" ]
|
||||
|
63
content/app/aperitif_mac.cc
Normal file
63
content/app/aperitif_mac.cc
Normal file
@ -0,0 +1,63 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
// Apéritif is by necessity linked to only a minimal number of libraries.
|
||||
// Code that executes in this context has the capability of compromising the
|
||||
// integrity of the sandbox by acquiring resources that would remain available
|
||||
// to an unprivileged process. Consult with security-dev@chromium.org before
|
||||
// adding new dependencies to Aperitif.
|
||||
|
||||
#include "content/public/app/aperitif_mac.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include "base/allocator/early_zone_registration_mac.h"
|
||||
#include "sandbox/mac/seatbelt_exec.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
// abort_report_np() records the message in a special section that both the
|
||||
// system CrashReporter and Crashpad collect in crash reports. Using a Crashpad
|
||||
// `Annotation` would be preferable, but this module cannot depend on Crashpad
|
||||
// directly.
|
||||
void abort_report_np(const char* fmt, ...) __abortlike __printflike(1, 2);
|
||||
|
||||
void AperitifFatalError(const char* format, ...) {
|
||||
va_list valist;
|
||||
va_start(valist, format);
|
||||
char message[4096];
|
||||
int rv = vsnprintf(message, sizeof(message), format, valist);
|
||||
va_end(valist);
|
||||
if (rv >= 0) {
|
||||
fprintf(stderr, "aperitif: %s\n", message);
|
||||
fflush(stderr);
|
||||
abort_report_np("aperitif: %s", message);
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
void AperitifInitializePartitionAlloc() {
|
||||
partition_alloc::EarlyMallocZoneRegistration();
|
||||
}
|
||||
|
||||
void AperitifInitializeSandbox(const char* executable_path,
|
||||
int argc,
|
||||
const char* const argv[]) {
|
||||
sandbox::SeatbeltExecServer::CreateFromArgumentsResult seatbelt =
|
||||
sandbox::SeatbeltExecServer::CreateFromArguments(executable_path, argc,
|
||||
argv);
|
||||
if (seatbelt.sandbox_required) {
|
||||
if (!seatbelt.server) {
|
||||
AperitifFatalError("Failed to create seatbelt sandbox server.");
|
||||
}
|
||||
if (!seatbelt.server->InitializeSandbox()) {
|
||||
AperitifFatalError("Failed to initialize sandbox.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // extern "C"
|
@ -95,3 +95,33 @@ if (is_component_build) {
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (is_mac) {
|
||||
import("//build/util/version.gni")
|
||||
shared_library("aperitif") {
|
||||
sources = [ "aperitif_mac.h" ]
|
||||
|
||||
public_deps = [ "//content/app:aperitif" ]
|
||||
|
||||
ldflags = [
|
||||
"-Wl,-install_name,libaperitif.dylib",
|
||||
"-compatibility_version",
|
||||
chrome_dylib_version,
|
||||
"-current_version",
|
||||
chrome_dylib_version,
|
||||
]
|
||||
|
||||
if (is_component_build) {
|
||||
# Typically packaged at Content Shell.app/Contents/Frameworks/Content
|
||||
# Shell Framework.framework/Versions/C/Libraries/libaperitif.dylib
|
||||
# so set rpath up to the root out directory.
|
||||
ldflags += [ "-Wl,-rpath,@loader_path/../../../../../../.." ]
|
||||
}
|
||||
|
||||
allow_circular_includes_from = [
|
||||
# This target is a pair with the non-public version. They always go
|
||||
# together and include headers from each other.
|
||||
"//content/app:aperitif",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
50
content/public/app/aperitif_mac.h
Normal file
50
content/public/app/aperitif_mac.h
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
#ifndef CONTENT_PUBLIC_APP_APERITIF_MAC_H_
|
||||
#define CONTENT_PUBLIC_APP_APERITIF_MAC_H_
|
||||
|
||||
// The macOS //content Apéritif dynamic library. The main and helper
|
||||
// executables, compiled from *main_mac.c are plain C files that do not
|
||||
// directly link to any C++ targets nor system libraries. Not linking to system
|
||||
// libraries is important for sandboxing (see
|
||||
// //sandbox/mac/seatbelt_sandbox_design.md), and not including C++ keeps the
|
||||
// executable size to a minimum, because the project uses its own version of
|
||||
// libc++. Minimizing the size of the executables is important because
|
||||
// //content embedders need to distribute several duplicate helper executables
|
||||
// that each have distinct codesigning entitlements (see
|
||||
// //content/public/app/mac_helpers.gni).
|
||||
//
|
||||
// Apéritif is a dynamic library that contains C++ functionality that needs to
|
||||
// run in the executable prior to loading the main Framework. This primary
|
||||
// purpose is to engage the sandbox in helper executables prior to any system
|
||||
// library static initializers running.
|
||||
|
||||
#define CONTENT_APERITIF_EXPORT __attribute__((visibility("default")))
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Helper function to record an error message and abort.
|
||||
void CONTENT_APERITIF_EXPORT __attribute__((noreturn, format(printf, 1, 2)))
|
||||
AperitifFatalError(const char* format, ...);
|
||||
|
||||
// Performs early initialization of the Mac allocator zone.
|
||||
void CONTENT_APERITIF_EXPORT AperitifInitializePartitionAlloc();
|
||||
|
||||
// Engages the sandbox if the command line arguments specify that the process
|
||||
// is to be sandboxed.
|
||||
void CONTENT_APERITIF_EXPORT
|
||||
AperitifInitializeSandbox(const char* executable_path,
|
||||
int argc,
|
||||
const char* const argv[]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#undef CONTENT_APERITIF_EXPORT
|
||||
|
||||
#endif // CONTENT_PUBLIC_APP_APERITIF_MAC_H_
|
@ -358,7 +358,8 @@ int LaunchTests(TestLauncherDelegate* launcher_delegate,
|
||||
#elif BUILDFLAG(IS_MAC)
|
||||
sandbox::SeatbeltExecServer::CreateFromArgumentsResult seatbelt =
|
||||
sandbox::SeatbeltExecServer::CreateFromArguments(
|
||||
command_line->GetProgram().value().c_str(), argc, argv);
|
||||
command_line->GetProgram().value().c_str(), argc,
|
||||
const_cast<const char**>(argv));
|
||||
if (seatbelt.sandbox_required) {
|
||||
CHECK(seatbelt.server->InitializeSandbox());
|
||||
}
|
||||
|
@ -480,39 +480,9 @@ if (is_android) {
|
||||
deps = [ "//content/shell/android:content_shell_apk" ]
|
||||
}
|
||||
} else if (is_mac) {
|
||||
tweak_info_plist("content_shell_plist") {
|
||||
group("content_shell") {
|
||||
testonly = true
|
||||
info_plist = "app/app-Info.plist"
|
||||
args = [
|
||||
"--scm=1",
|
||||
"--version",
|
||||
content_shell_version,
|
||||
]
|
||||
}
|
||||
mac_app_bundle("content_shell") {
|
||||
testonly = true
|
||||
output_name = content_shell_product_name
|
||||
sources = [ "app/shell_main_mac.cc" ]
|
||||
defines = [ "SHELL_PRODUCT_NAME=\"$content_shell_product_name\"" ]
|
||||
|
||||
# Must have minimal dependencies. In particular cannot depend on //base.
|
||||
# Depending on //base leads to loading //base twice (once in the exe, once
|
||||
# in the main framework).
|
||||
deps = [
|
||||
":content_shell_framework_bundle_data",
|
||||
":content_shell_resources_bundle_data",
|
||||
|
||||
# Despite its path, this does not add a //base dependency, see comments in
|
||||
# the .cc file.
|
||||
"//base/allocator:early_zone_registration_mac",
|
||||
"//sandbox/mac:seatbelt",
|
||||
]
|
||||
info_plist_target = ":content_shell_plist"
|
||||
data_deps = [ ":content_shell_app" ]
|
||||
|
||||
if (is_component_build) {
|
||||
ldflags = [ "-Wl,-rpath,@executable_path/../Frameworks" ]
|
||||
}
|
||||
deps = [ ":content_shell_mac_app" ]
|
||||
}
|
||||
} else {
|
||||
executable("content_shell") {
|
||||
@ -589,6 +559,51 @@ if (is_android) {
|
||||
}
|
||||
|
||||
if (is_mac) {
|
||||
content_shell_framework_name = "$content_shell_product_name Framework"
|
||||
content_shell_helper_name = "$content_shell_product_name Helper"
|
||||
|
||||
tweak_info_plist("content_shell_plist") {
|
||||
testonly = true
|
||||
info_plist = "app/app-Info.plist"
|
||||
args = [
|
||||
"--scm=1",
|
||||
"--version",
|
||||
content_shell_version,
|
||||
]
|
||||
}
|
||||
|
||||
mac_app_bundle("content_shell_mac_app") {
|
||||
testonly = true
|
||||
output_name = content_shell_product_name
|
||||
sources = [ "app/shell_main_mac.c" ]
|
||||
defines = [ "SHELL_PRODUCT_NAME=\"$content_shell_product_name\"" ]
|
||||
|
||||
# No libc++ needed, there’s only C code in this module.
|
||||
no_default_deps = true
|
||||
|
||||
# Must have minimal dependencies. In particular cannot depend on //base.
|
||||
# Depending on //base leads to loading //base twice (once in the exe, once
|
||||
# in the main framework).
|
||||
deps = [
|
||||
":content_shell_framework_bundle_data",
|
||||
":content_shell_resources_bundle_data",
|
||||
"//content/public/app:aperitif",
|
||||
]
|
||||
info_plist_target = ":content_shell_plist"
|
||||
data_deps = [ ":content_shell_app" ]
|
||||
|
||||
ldflags = [
|
||||
# Needed for lld: https://github.com/llvm/llvm-project/issues/53550.
|
||||
"-Wl,-headerpad_max_install_names",
|
||||
"-Wcrl,installnametool,-change,libaperitif.dylib,@executable_path/../Frameworks/$content_shell_framework_name.framework/Libraries/libaperitif.dylib",
|
||||
]
|
||||
|
||||
if (is_component_build) {
|
||||
ldflags += [ "-Wl,-rpath,@executable_path/../Frameworks" ]
|
||||
data_deps += [ "//content/public/app:aperitif" ]
|
||||
}
|
||||
}
|
||||
|
||||
bundle_data("content_shell_framework_resources") {
|
||||
testonly = true
|
||||
sources = [ "$root_out_dir/content_shell.pak" ]
|
||||
@ -629,9 +644,6 @@ if (is_mac) {
|
||||
}
|
||||
}
|
||||
|
||||
content_shell_framework_name = "$content_shell_product_name Framework"
|
||||
content_shell_helper_name = "$content_shell_product_name Helper"
|
||||
|
||||
bundle_data("content_shell_framework_helpers") {
|
||||
testonly = true
|
||||
sources = [ "$root_out_dir/chrome_crashpad_handler" ]
|
||||
@ -681,11 +693,13 @@ if (is_mac) {
|
||||
":content_shell_angle_library",
|
||||
":content_shell_app",
|
||||
"//content/public/app",
|
||||
"//content/public/app:aperitif",
|
||||
"//content/public/common",
|
||||
"//third_party/icu:icudata",
|
||||
]
|
||||
|
||||
bundle_deps = [
|
||||
":content_shell_aperitif_library",
|
||||
":content_shell_framework_helpers",
|
||||
":content_shell_framework_resources",
|
||||
":content_shell_swiftshader_library",
|
||||
@ -695,10 +709,12 @@ if (is_mac) {
|
||||
deps += [ ":content_shell_framework_plugins" ]
|
||||
}
|
||||
|
||||
ldflags = [ "-Wcrl,installnametool,-change,libaperitif.dylib,@loader_path/Libraries/libaperitif.dylib" ]
|
||||
|
||||
if (!is_component_build) {
|
||||
# Specify a sensible install_name for static builds. The library is
|
||||
# dlopen()ed so this is not used to resolve the module.
|
||||
ldflags = [ "-Wl,-install_name,@executable_path/../Frameworks/$output_name.framework/$output_name" ]
|
||||
ldflags += [ "-Wl,-install_name,@executable_path/../Frameworks/$output_name.framework/$output_name" ]
|
||||
} else {
|
||||
# Both the main :content_shell and :content_shell_helper_app executables
|
||||
# need to link the framework. Because they are at different directory
|
||||
@ -706,7 +722,7 @@ if (is_mac) {
|
||||
# install_name_tool on one of the executables. However install_name_tool
|
||||
# only operates in-place, which is problematic to express in GN. Instead,
|
||||
# use rpath-based loading.
|
||||
ldflags =
|
||||
ldflags +=
|
||||
[ "-Wl,-install_name,@rpath/$output_name.framework/$output_name" ]
|
||||
|
||||
# Set up the rpath for the framework so that it can find dylibs in the
|
||||
@ -740,7 +756,7 @@ if (is_mac) {
|
||||
|
||||
output_name = content_shell_helper_name + invoker.helper_name_suffix
|
||||
|
||||
sources = [ "app/shell_main_mac.cc" ]
|
||||
sources = [ "app/shell_main_mac.c" ]
|
||||
defines = [
|
||||
"HELPER_EXECUTABLE",
|
||||
"SHELL_PRODUCT_NAME=\"$content_shell_product_name\"",
|
||||
@ -749,15 +765,21 @@ if (is_mac) {
|
||||
"CONTENT_SHELL_HELPER_SUFFIX=${invoker.helper_name_suffix}",
|
||||
"CONTENT_SHELL_HELPER_BUNDLE_ID_SUFFIX=${invoker.helper_bundle_id_suffix}",
|
||||
]
|
||||
deps = [
|
||||
"//base/allocator:early_zone_registration_mac",
|
||||
"//sandbox/mac:seatbelt",
|
||||
]
|
||||
deps = [ "//content/public/app:aperitif" ]
|
||||
|
||||
# No libc++ needed, there’s only C code in this module.
|
||||
no_default_deps = true
|
||||
|
||||
info_plist_target = ":content_shell_helper_plist"
|
||||
|
||||
ldflags = [
|
||||
# Needed for lld: https://github.com/llvm/llvm-project/issues/53550.
|
||||
"-Wl,-headerpad_max_install_names",
|
||||
"-Wcrl,installnametool,-change,libaperitif.dylib,@executable_path/../../../../Libraries/libaperitif.dylib",
|
||||
]
|
||||
|
||||
if (is_component_build) {
|
||||
ldflags = [
|
||||
ldflags += [
|
||||
# The helper is in Content Shell.app/Contents/Frameworks/
|
||||
# Content Shell Framework.framework/Versions/C/Helpers/
|
||||
# Content Shell Helper.app/Contents/MacOS/
|
||||
@ -844,6 +866,12 @@ if (is_mac) {
|
||||
deps = [ ":content_shell_swiftshader_binaries" ]
|
||||
}
|
||||
}
|
||||
|
||||
bundle_data("content_shell_aperitif_library") {
|
||||
sources = [ "$root_out_dir/libaperitif.dylib" ]
|
||||
outputs = [ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}" ]
|
||||
public_deps = [ "//content/public/app:aperitif" ]
|
||||
}
|
||||
}
|
||||
|
||||
mojom("content_browsertests_mojom") {
|
||||
|
68
content/shell/app/shell_main_mac.c
Normal file
68
content/shell/app/shell_main_mac.c
Normal file
@ -0,0 +1,68 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "content/public/app/aperitif_mac.h"
|
||||
|
||||
typedef int (*ContentMainPtr)(int, char**);
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
AperitifInitializePartitionAlloc();
|
||||
|
||||
char exec_path[PATH_MAX];
|
||||
uint32_t exec_path_size = sizeof(exec_path);
|
||||
int rv = _NSGetExecutablePath(exec_path, &exec_path_size);
|
||||
if (rv != 0) {
|
||||
AperitifFatalError("_NSGetExecutablePath: get path failed.");
|
||||
}
|
||||
|
||||
#if defined(HELPER_EXECUTABLE)
|
||||
AperitifInitializeSandbox(exec_path, argc, (const char**)argv);
|
||||
|
||||
// The Helper app is in the versioned framework directory, so just go up to
|
||||
// the version folder to locate the dylib.
|
||||
static const char rel_path[] = "../../../../" SHELL_PRODUCT_NAME " Framework";
|
||||
#else
|
||||
static const char rel_path[] =
|
||||
"../Frameworks/" SHELL_PRODUCT_NAME
|
||||
" Framework.framework/" SHELL_PRODUCT_NAME " Framework";
|
||||
#endif // defined(HELPER_EXECUTABLE)
|
||||
|
||||
// Slice off the last part of the main executable path, and append the
|
||||
// version framework information.
|
||||
const char* parent_dir = dirname(exec_path);
|
||||
if (!parent_dir) {
|
||||
AperitifFatalError("dirname %s: %s", exec_path, strerror(errno));
|
||||
}
|
||||
|
||||
char framework_path[PATH_MAX];
|
||||
rv = snprintf(framework_path, sizeof(framework_path), "%s/%s", parent_dir,
|
||||
rel_path);
|
||||
if (rv < 0 || (size_t)rv >= sizeof(framework_path)) {
|
||||
AperitifFatalError("snprintf: %d", rv);
|
||||
}
|
||||
|
||||
void* library = dlopen(framework_path, RTLD_LAZY | RTLD_LOCAL | RTLD_FIRST);
|
||||
if (!library) {
|
||||
AperitifFatalError("dlopen %s: %s", framework_path, dlerror());
|
||||
}
|
||||
|
||||
const ContentMainPtr content_main = dlsym(library, "ContentMain");
|
||||
if (!content_main) {
|
||||
AperitifFatalError("dlsym ContentMain: %s", dlerror());
|
||||
}
|
||||
rv = content_main(argc, argv);
|
||||
|
||||
// exit, don't return from main, to avoid the apparent removal of main from
|
||||
// stack backtraces under tail call optimization.
|
||||
exit(rv);
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/allocator/early_zone_registration_mac.h"
|
||||
|
||||
#if defined(HELPER_EXECUTABLE)
|
||||
#include "sandbox/mac/seatbelt_exec.h" // nogncheck
|
||||
#endif // defined(HELPER_EXECUTABLE)
|
||||
|
||||
namespace {
|
||||
|
||||
using ContentMainPtr = int (*)(int, char**);
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
partition_alloc::EarlyMallocZoneRegistration();
|
||||
|
||||
uint32_t exec_path_size = 0;
|
||||
int rv = _NSGetExecutablePath(NULL, &exec_path_size);
|
||||
if (rv != -1) {
|
||||
fprintf(stderr, "_NSGetExecutablePath: get length failed\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
std::unique_ptr<char[]> exec_path(new char[exec_path_size]);
|
||||
rv = _NSGetExecutablePath(exec_path.get(), &exec_path_size);
|
||||
if (rv != 0) {
|
||||
fprintf(stderr, "_NSGetExecutablePath: get path failed\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
#if defined(HELPER_EXECUTABLE)
|
||||
sandbox::SeatbeltExecServer::CreateFromArgumentsResult seatbelt =
|
||||
sandbox::SeatbeltExecServer::CreateFromArguments(exec_path.get(), argc,
|
||||
argv);
|
||||
if (seatbelt.sandbox_required) {
|
||||
if (!seatbelt.server) {
|
||||
fprintf(stderr, "Failed to create seatbelt sandbox server.\n");
|
||||
abort();
|
||||
}
|
||||
if (!seatbelt.server->InitializeSandbox()) {
|
||||
fprintf(stderr, "Failed to initialize sandbox.\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
// The Helper app is in the versioned framework directory, so just go up to
|
||||
// the version folder to locate the dylib.
|
||||
const char rel_path[] = "../../../../" SHELL_PRODUCT_NAME " Framework";
|
||||
#else
|
||||
const char rel_path[] =
|
||||
"../Frameworks/" SHELL_PRODUCT_NAME
|
||||
" Framework.framework/" SHELL_PRODUCT_NAME " Framework";
|
||||
#endif // defined(HELPER_EXECUTABLE)
|
||||
|
||||
// Slice off the last part of the main executable path, and append the
|
||||
// version framework information.
|
||||
const char* parent_dir = dirname(exec_path.get());
|
||||
if (!parent_dir) {
|
||||
fprintf(stderr, "dirname %s: %s\n", exec_path.get(), strerror(errno));
|
||||
abort();
|
||||
}
|
||||
|
||||
const size_t parent_dir_len = strlen(parent_dir);
|
||||
const size_t rel_path_len = strlen(rel_path);
|
||||
// 2 accounts for a trailing NUL byte and the '/' in the middle of the paths.
|
||||
const size_t framework_path_size = parent_dir_len + rel_path_len + 2;
|
||||
std::unique_ptr<char[]> framework_path(new char[framework_path_size]);
|
||||
snprintf(framework_path.get(), framework_path_size, "%s/%s", parent_dir,
|
||||
rel_path);
|
||||
|
||||
void* library =
|
||||
dlopen(framework_path.get(), RTLD_LAZY | RTLD_LOCAL | RTLD_FIRST);
|
||||
if (!library) {
|
||||
fprintf(stderr, "dlopen %s: %s\n", framework_path.get(), dlerror());
|
||||
abort();
|
||||
}
|
||||
|
||||
const ContentMainPtr content_main =
|
||||
reinterpret_cast<ContentMainPtr>(dlsym(library, "ContentMain"));
|
||||
if (!content_main) {
|
||||
fprintf(stderr, "dlsym ContentMain: %s\n", dlerror());
|
||||
abort();
|
||||
}
|
||||
rv = content_main(argc, argv);
|
||||
|
||||
// exit, don't return from main, to avoid the apparent removal of main from
|
||||
// stack backtraces under tail call optimization.
|
||||
exit(rv);
|
||||
}
|
@ -169,7 +169,7 @@ sandbox::SeatbeltExecServer::CreateFromArgumentsResult::
|
||||
sandbox::SeatbeltExecServer::CreateFromArgumentsResult
|
||||
SeatbeltExecServer::CreateFromArguments(const char* executable_path,
|
||||
int argc,
|
||||
char** argv) {
|
||||
const char* const* argv) {
|
||||
CreateFromArgumentsResult result;
|
||||
int seatbelt_client_fd = -1;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
|
@ -97,8 +97,10 @@ class SEATBELT_EXPORT SeatbeltExecServer {
|
||||
bool sandbox_required = false;
|
||||
std::unique_ptr<SeatbeltExecServer> server;
|
||||
};
|
||||
static CreateFromArgumentsResult
|
||||
CreateFromArguments(const char* executable_path, int argc, char** argv);
|
||||
static CreateFromArgumentsResult CreateFromArguments(
|
||||
const char* executable_path,
|
||||
int argc,
|
||||
const char* const* argv);
|
||||
|
||||
// Reads the policy from the client, applies the profile, and returns whether
|
||||
// or not the operation succeeds.
|
||||
|
Reference in New Issue
Block a user