Remove EWK_BRINGUPS for M120 #3
[platform/framework/web/chromium-efl.git] / chrome / app / chrome_exe_main_mac.cc
1 // Copyright 2015 The Chromium Authors
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 <stdarg.h>
13 #include <stddef.h>
14 #include <stdint.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19
20 #include <memory>
21
22 #include "base/allocator/early_zone_registration_apple.h"
23 #include "build/branding_buildflags.h"
24 #include "build/build_config.h"
25 #include "chrome/common/chrome_version.h"
26
27 #if defined(HELPER_EXECUTABLE)
28 #include "sandbox/mac/seatbelt_exec.h"  // nogncheck
29 #endif
30
31 extern "C" {
32 // abort_report_np() records the message in a special section that both the
33 // system CrashReporter and Crashpad collect in crash reports. Using a Crashpad
34 // Annotation would be preferable, but this executable cannot depend on
35 // Crashpad directly.
36 void abort_report_np(const char* fmt, ...);
37 }
38
39 namespace {
40
41 typedef int (*ChromeMainPtr)(int, char**);
42
43 #if !defined(HELPER_EXECUTABLE) && defined(OFFICIAL_BUILD) && \
44     BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(ARCH_CPU_X86_64)
45 // This is for https://crbug.com/1300598, and more generally,
46 // https://crbug.com/1297588 (and all of the associated bugs). It's horrible!
47 //
48 // When the main executable is updated on disk while the application is running,
49 // and the offset of the Mach-O image at the main executable's path changes from
50 // the offset that was determined when the executable was loaded, SecCode ceases
51 // to be able to work with the executable. This may be triggered when the
52 // product is updated on disk but the application has not yet relaunched. This
53 // affects SecCodeCopySelf and SecCodeCopyGuestWithAttributes. Bugs are evident
54 // even when validation (SecCodeCheckValidity) is not attempted.
55 //
56 // Practically, this is only a concern for fat (universal) files, because the
57 // offset of a Mach-O image in a thin (single-architecture) file is always 0.
58 // The branded product always ships a fat executable, and because some uses of
59 // SecCode are in OS code beyond Chrome's control, an effort is made to freeze
60 // the geometry of the branded (BUILDFLAG(GOOGLE_CHROME_BRANDING))
61 // for-public-release (defined(OFFICIAL_BUILD)) main executable.
62 //
63 // The fat file is produced by installer/mac/universalizer.py. The x86_64 slice
64 // always precedes the arm64 slice: lipo, as used by universalizer.py, always
65 // places the arm64 slice last. See Xcode 12.0
66 // https://github.com/apple-oss-distributions/cctools/blob/cctools-973.0.1/misc/lipo.c#L2672
67 // cmp_qsort, used by create_fat at #L962. universalizer.py ensures that the
68 // first slice in the file is located at a constant offset (16kB since
69 // 98.0.4758.80), but if the first slice's size changes, it can affect the
70 // offset of the second slice, the arm64 one, triggering SecCode-related bugs
71 // for arm64 users across updates.
72 //
73 // As quite a hack of a workaround, the offset of the arm64 slice within the fat
74 // main executable is influenced to land at the desired location by introducing
75 // padding to the x86_64 slice that precedes it. The arm64 slice needs to remain
76 // at offset 272kB (since 106.0.5249.61). The signed x86_64 slice has size
77 // 260704 bytes (including 68kB of padding) in 106.0.5249.61, but has grown
78 // since then, and before the introduction of any padding, would now be 194412
79 // bytes long. It needs to be padded to be in the range (245760, 262144] so that
80 // the arm64 slice that follows it begins at offset 272kB. To allow for the
81 // possibility of small-scale (up to +/-8kB) size changes, the target size for
82 // the padded x86_64 slice is 253952 bytes. To make up the 59540-byte
83 // difference, 56kB (57344 bytes) of padding is added to the x86_64 slice. to
84 // ensure that its size is stable, causing the arm64 slice to land where it
85 // needs to be when universalized. This padding needs to be added to the thin
86 // form of the x86_64 image before being fed to universalizer.py. Why 57344
87 // bytes and not 59540? To keep it an even multiple of linker pages (not machine
88 // pages: linker pages are 4kB for lld targeting x86_64 and 16kB for ld64
89 // targeting x86_64, but Chrome uses lld). In any case, I'll make up some of the
90 // 2196-byte difference with one more weird trick below.
91 //
92 // There are several terrible ways to insert this padding into the x86_64 image.
93 // Best would be something that considers the size of the x86_64 image without
94 // padding, and inserts the precise amount required. It may be possible to do
95 // this after linking, but the options that have been attempted so far were not
96 // successful. So this quick and very dirty 56kB buffer is added to increase the
97 // size of __TEXT,__const in a way that no tool could possibly see as suspicious
98 // after link time. The variable is marked with the "used" attribute to prevent
99 // the compiler from issuing warnings about the referenced variable, to prevent
100 // the compiler from removing it under optimization, and to set the
101 // S_ATTR_NO_DEAD_STRIP section attribute to prevent the linker from removing it
102 // under -dead_strip. Note that the standardized [[maybe_unused]] attribute only
103 // suppresses the warning, but does not prevent the compiler or linker from
104 // removing it.
105 //
106 // The introduction of this fixed 56kB of padding causes the unsigned linker
107 // output to grow by 56kB precisely, but the signed output will grow by slightly
108 // more. This is because the code signature's code directory contains SHA-1 and
109 // SHA-256 hashes of each 4kB code signing page (note, not machine pages or
110 // linker pages) in the image, adding 20 and 32 bytes each (macOS 12.0.1
111 // https://github.com/apple-oss-distributions/Security/blob/main/OSX/libsecurity_codesigning/lib/signer.cpp#L298
112 // Security::CodeSigning::SecCodeSigner::Signer::prepare). For the 56kB
113 // addition, the code signature grows by (56 / 4) * (20 + 32) = 728 bytes, thus
114 // the total size of the linker output grows by 56kB + 728 = 58072 bytes. It is
115 // not possible to control this any more granularly: if the buffer were sized at
116 // 56kB - 728 = 56616 bytes, it would either cause no change in the space
117 // allocated to the __TEXT segment (due to padding for alignment) or would cause
118 // the segment to shrink by a linker page (note, not a code signing or machine
119 // page) which would which would cause the linker output to shrink by the same
120 // amount and would be absolutely undesirable. Luckily, the net growth of 58072
121 // bytes is almost at the target of 59540. In any event, having the signed
122 // x86_64 slice sized at 252484 bytes instead of 253952 should not be a problem.
123 // So long as the size is in the proper 16kB range, the 16kB alignment for the
124 // arm64 slice that follows it in the fat file will cause it to appear at the
125 // desired 272kB.
126 //
127 // If the main executable has a significant change in size, this will need to be
128 // revised. Hopefully a more elegant solution will become apparent before that's
129 // required.
130 #if !defined(DCHECK_ALWAYS_ON)
131 __attribute__((used)) const char kGrossPaddingForCrbug1300598[56 * 1024] = {};
132 #else
133 // DCHECK builds are larger and therefore require less padding. See
134 // https://crbug.com/1394196 for the calculations.
135 __attribute__((used)) const char kGrossPaddingForCrbug1300598[36 * 1024] = {};
136 #endif  // !defined(DCHECK_ALWAYS_ON)
137 #endif
138
139 [[noreturn]] void FatalError(const char* format, ...) {
140   va_list valist;
141   va_start(valist, format);
142   char message[4096];
143   if (vsnprintf(message, sizeof(message), format, valist) >= 0) {
144     fputs(message, stderr);
145     abort_report_np("%s", message);
146   }
147   va_end(valist);
148   abort();
149 }
150
151 }  // namespace
152
153 __attribute__((visibility("default"))) int main(int argc, char* argv[]) {
154   partition_alloc::EarlyMallocZoneRegistration();
155
156   uint32_t exec_path_size = 0;
157   int rv = _NSGetExecutablePath(NULL, &exec_path_size);
158   if (rv != -1) {
159     FatalError("_NSGetExecutablePath: get length failed.");
160   }
161
162   std::unique_ptr<char[]> exec_path(new char[exec_path_size]);
163   rv = _NSGetExecutablePath(exec_path.get(), &exec_path_size);
164   if (rv != 0) {
165     FatalError("_NSGetExecutablePath: get path failed.");
166   }
167
168 #if defined(HELPER_EXECUTABLE)
169   sandbox::SeatbeltExecServer::CreateFromArgumentsResult seatbelt =
170       sandbox::SeatbeltExecServer::CreateFromArguments(exec_path.get(), argc,
171                                                        argv);
172   if (seatbelt.sandbox_required) {
173     if (!seatbelt.server) {
174       FatalError("Failed to create seatbelt sandbox server.");
175     }
176     if (!seatbelt.server->InitializeSandbox()) {
177       FatalError("Failed to initialize sandbox.");
178     }
179   }
180
181   // The helper lives within the versioned framework directory, so simply
182   // go up to find the main dylib.
183   const char rel_path[] = "../../../../" PRODUCT_FULLNAME_STRING " Framework";
184 #else
185   const char rel_path[] = "../Frameworks/" PRODUCT_FULLNAME_STRING
186                           " Framework.framework/Versions/" CHROME_VERSION_STRING
187                           "/" PRODUCT_FULLNAME_STRING " Framework";
188 #endif  // defined(HELPER_EXECUTABLE)
189
190   // Slice off the last part of the main executable path, and append the
191   // version framework information.
192   const char* parent_dir = dirname(exec_path.get());
193   if (!parent_dir) {
194     FatalError("dirname %s: %s.", exec_path.get(), strerror(errno));
195   }
196
197   const size_t parent_dir_len = strlen(parent_dir);
198   const size_t rel_path_len = strlen(rel_path);
199   // 2 accounts for a trailing NUL byte and the '/' in the middle of the paths.
200   const size_t framework_path_size = parent_dir_len + rel_path_len + 2;
201   std::unique_ptr<char[]> framework_path(new char[framework_path_size]);
202   snprintf(framework_path.get(), framework_path_size, "%s/%s", parent_dir,
203            rel_path);
204
205   void* library =
206       dlopen(framework_path.get(), RTLD_LAZY | RTLD_LOCAL | RTLD_FIRST);
207   if (!library) {
208     FatalError("dlopen %s: %s.", framework_path.get(), dlerror());
209   }
210
211   const ChromeMainPtr chrome_main =
212       reinterpret_cast<ChromeMainPtr>(dlsym(library, "ChromeMain"));
213   if (!chrome_main) {
214     FatalError("dlsym ChromeMain: %s.", dlerror());
215   }
216   rv = chrome_main(argc, argv);
217
218   // exit, don't return from main, to avoid the apparent removal of main from
219   // stack backtraces under tail call optimization.
220   exit(rv);
221 }