1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // The entry point for all Mac Chromium processes, including the outer app
6 // bundle (browser) and helper app (renderer, plugin, and friends).
7
8 #include <dlfcn.h>
9 #include <errno.h>
10 #include <libgen.h>
11 #include <mach-o/dyld.h>
12 #include <os/availability.h>
13 #include <stdarg.h>
14 #include <stddef.h>
15 #include <stdint.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20
21 #include <memory>
22
23 #include "chrome/common/chrome_version.h"
24
25 #if defined(HELPER_EXECUTABLE)
26 #include "sandbox/mac/seatbelt_exec.h" // nogncheck
27 #endif // defined(HELPER_EXECUTABLE)
28
29 extern "C" {
30 // abort_report_np() records the message in a special section that both the
31 // system CrashReporter and Crashpad collect in crash reports. Using a Crashpad
32 // Annotation would be preferable, but this executable cannot depend on
33 // Crashpad directly.
34 void abort_report_np(const char* fmt, ...) API_AVAILABLE(macos(10.11));
35 }
36
37 namespace {
38
39 typedef int (*ChromeMainPtr)(int, char**);
40
FatalError(const char * format,...)41 [[noreturn]] void FatalError(const char* format, ...) {
42 va_list valist;
43 va_start(valist, format);
44 char message[4096];
45 if (vsnprintf(message, sizeof(message), format, valist) >= 0) {
46 if (__builtin_available(macOS 10.11, *)) {
47 abort_report_np("%s", message);
48 }
49 }
50 va_end(valist);
51 abort();
52 }
53
54 } // namespace
55
main(int argc,char * argv[])56 __attribute__((visibility("default"))) int main(int argc, char* argv[]) {
57 uint32_t exec_path_size = 0;
58 int rv = _NSGetExecutablePath(NULL, &exec_path_size);
59 if (rv != -1) {
60 FatalError("_NSGetExecutablePath: get length failed.");
61 }
62
63 std::unique_ptr<char[]> exec_path(new char[exec_path_size]);
64 rv = _NSGetExecutablePath(exec_path.get(), &exec_path_size);
65 if (rv != 0) {
66 FatalError("_NSGetExecutablePath: get path failed.");
67 }
68
69 #if defined(HELPER_EXECUTABLE)
70 sandbox::SeatbeltExecServer::CreateFromArgumentsResult seatbelt =
71 sandbox::SeatbeltExecServer::CreateFromArguments(exec_path.get(), argc,
72 argv);
73 if (seatbelt.sandbox_required) {
74 if (!seatbelt.server) {
75 FatalError("Failed to create seatbelt sandbox server.");
76 }
77 if (!seatbelt.server->InitializeSandbox()) {
78 FatalError("Failed to initialize sandbox.");
79 }
80 }
81
82 // The helper lives within the versioned framework directory, so simply
83 // go up to find the main dylib.
84 const char rel_path[] = "../../../../" PRODUCT_FULLNAME_STRING " Framework";
85 #else
86 const char rel_path[] = "../Frameworks/" PRODUCT_FULLNAME_STRING
87 " Framework.framework/Versions/" CHROME_VERSION_STRING
88 "/" PRODUCT_FULLNAME_STRING " Framework";
89 #endif // defined(HELPER_EXECUTABLE)
90
91 // Slice off the last part of the main executable path, and append the
92 // version framework information.
93 const char* parent_dir = dirname(exec_path.get());
94 if (!parent_dir) {
95 FatalError("dirname %s: %s.", exec_path.get(), strerror(errno));
96 }
97
98 const size_t parent_dir_len = strlen(parent_dir);
99 const size_t rel_path_len = strlen(rel_path);
100 // 2 accounts for a trailing NUL byte and the '/' in the middle of the paths.
101 const size_t framework_path_size = parent_dir_len + rel_path_len + 2;
102 std::unique_ptr<char[]> framework_path(new char[framework_path_size]);
103 snprintf(framework_path.get(), framework_path_size, "%s/%s", parent_dir,
104 rel_path);
105
106 void* library =
107 dlopen(framework_path.get(), RTLD_LAZY | RTLD_LOCAL | RTLD_FIRST);
108 if (!library) {
109 FatalError("dlopen %s: %s.", framework_path.get(), dlerror());
110 }
111
112 const ChromeMainPtr chrome_main =
113 reinterpret_cast<ChromeMainPtr>(dlsym(library, "ChromeMain"));
114 if (!chrome_main) {
115 FatalError("dlsym ChromeMain: %s.", dlerror());
116 }
117 rv = chrome_main(argc, argv);
118
119 // exit, don't return from main, to avoid the apparent removal of main from
120 // stack backtraces under tail call optimization.
121 exit(rv);
122 }
123