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