Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "nsXULAppAPI.h"
7 : #include "mozilla/XREAppData.h"
8 : #include "application.ini.h"
9 : #include "mozilla/Bootstrap.h"
10 : #if defined(XP_WIN)
11 : #include <windows.h>
12 : #include <stdlib.h>
13 : #elif defined(XP_UNIX)
14 : #include <sys/resource.h>
15 : #include <unistd.h>
16 : #endif
17 :
18 : #include <stdio.h>
19 : #include <stdarg.h>
20 : #include <time.h>
21 :
22 : #include "nsCOMPtr.h"
23 : #include "nsIFile.h"
24 :
25 : #ifdef XP_WIN
26 : #include "LauncherProcessWin.h"
27 :
28 : #define XRE_WANT_ENVIRON
29 : #define strcasecmp _stricmp
30 : #ifdef MOZ_SANDBOX
31 : #include "mozilla/sandboxing/SandboxInitialization.h"
32 : #endif
33 : #endif
34 : #include "BinaryPath.h"
35 :
36 : #include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL
37 :
38 : #include "mozilla/Sprintf.h"
39 : #include "mozilla/StartupTimeline.h"
40 : #include "mozilla/WindowsDllBlocklist.h"
41 :
42 : #ifdef LIBFUZZER
43 : #include "FuzzerDefs.h"
44 : #endif
45 :
46 : #ifdef MOZ_LINUX_32_SSE2_STARTUP_ERROR
47 : #include <cpuid.h>
48 : #include "mozilla/Unused.h"
49 :
50 : static bool
51 : IsSSE2Available()
52 : {
53 : // The rest of the app has been compiled to assume that SSE2 is present
54 : // unconditionally, so we can't use the normal copy of SSE.cpp here.
55 : // Since SSE.cpp caches the results and we need them only transiently,
56 : // instead of #including SSE.cpp here, let's just inline the specific check
57 : // that's needed.
58 : unsigned int level = 1u;
59 : unsigned int eax, ebx, ecx, edx;
60 : unsigned int bits = (1u<<26);
61 : unsigned int max = __get_cpuid_max(0, nullptr);
62 : if (level > max) {
63 : return false;
64 : }
65 : __cpuid_count(level, 0, eax, ebx, ecx, edx);
66 : return (edx & bits) == bits;
67 : }
68 :
69 : static const char sSSE2Message[] =
70 : "This browser version requires a processor with the SSE2 instruction "
71 : "set extension.\nYou may be able to obtain a version that does not "
72 : "require SSE2 from your Linux distribution.\n";
73 :
74 : __attribute__((constructor))
75 : static void
76 : SSE2Check()
77 : {
78 : if (IsSSE2Available()) {
79 : return;
80 : }
81 : // Using write() in order to avoid jemalloc-based buffering. Ignoring return
82 : // values, since there isn't much we could do on failure and there is no
83 : // point in trying to recover from errors.
84 : MOZ_UNUSED(write(STDERR_FILENO,
85 : sSSE2Message,
86 : MOZ_ARRAY_LENGTH(sSSE2Message) - 1));
87 : // _exit() instead of exit() to avoid running the usual "at exit" code.
88 : _exit(255);
89 : }
90 : #endif
91 :
92 : #if !defined(MOZ_WIDGET_COCOA) && !defined(MOZ_WIDGET_ANDROID)
93 : #define MOZ_BROWSER_CAN_BE_CONTENTPROC
94 : #include "../../ipc/contentproc/plugin-container.cpp"
95 : #endif
96 :
97 : using namespace mozilla;
98 :
99 : #ifdef XP_MACOSX
100 : #define kOSXResourcesFolder "Resources"
101 : #endif
102 : #define kDesktopFolder "browser"
103 :
104 0 : static MOZ_FORMAT_PRINTF(1, 2) void Output(const char *fmt, ... )
105 : {
106 : va_list ap;
107 0 : va_start(ap, fmt);
108 :
109 : #ifndef XP_WIN
110 0 : vfprintf(stderr, fmt, ap);
111 : #else
112 : char msg[2048];
113 : vsnprintf_s(msg, _countof(msg), _TRUNCATE, fmt, ap);
114 :
115 : wchar_t wide_msg[2048];
116 : MultiByteToWideChar(CP_UTF8,
117 : 0,
118 : msg,
119 : -1,
120 : wide_msg,
121 : _countof(wide_msg));
122 : #if MOZ_WINCONSOLE
123 : fwprintf_s(stderr, wide_msg);
124 : #else
125 : // Linking user32 at load-time interferes with the DLL blocklist (bug 932100).
126 : // This is a rare codepath, so we can load user32 at run-time instead.
127 : HMODULE user32 = LoadLibraryW(L"user32.dll");
128 : if (user32) {
129 : decltype(MessageBoxW)* messageBoxW =
130 : (decltype(MessageBoxW)*) GetProcAddress(user32, "MessageBoxW");
131 : if (messageBoxW) {
132 : messageBoxW(nullptr, wide_msg, L"Firefox", MB_OK
133 : | MB_ICONERROR
134 : | MB_SETFOREGROUND);
135 : }
136 : FreeLibrary(user32);
137 : }
138 : #endif
139 : #endif
140 :
141 0 : va_end(ap);
142 0 : }
143 :
144 : /**
145 : * Return true if |arg| matches the given argument name.
146 : */
147 0 : static bool IsArg(const char* arg, const char* s)
148 : {
149 0 : if (*arg == '-')
150 : {
151 0 : if (*++arg == '-')
152 0 : ++arg;
153 0 : return !strcasecmp(arg, s);
154 : }
155 :
156 : #if defined(XP_WIN)
157 : if (*arg == '/')
158 : return !strcasecmp(++arg, s);
159 : #endif
160 :
161 : return false;
162 : }
163 :
164 0 : Bootstrap::UniquePtr gBootstrap;
165 :
166 0 : static int do_main(int argc, char* argv[], char* envp[])
167 : {
168 : // Allow firefox.exe to launch XULRunner apps via -app <application.ini>
169 : // Note that -app must be the *first* argument.
170 0 : const char *appDataFile = getenv("XUL_APP_FILE");
171 0 : if ((!appDataFile || !*appDataFile) &&
172 0 : (argc > 1 && IsArg(argv[1], "app"))) {
173 0 : if (argc == 2) {
174 0 : Output("Incorrect number of arguments passed to -app");
175 0 : return 255;
176 : }
177 0 : appDataFile = argv[2];
178 :
179 : char appEnv[MAXPATHLEN];
180 0 : SprintfLiteral(appEnv, "XUL_APP_FILE=%s", argv[2]);
181 0 : if (putenv(strdup(appEnv))) {
182 0 : Output("Couldn't set %s.\n", appEnv);
183 0 : return 255;
184 : }
185 0 : argv[2] = argv[0];
186 0 : argv += 2;
187 0 : argc -= 2;
188 0 : } else if (argc > 1 && IsArg(argv[1], "xpcshell")) {
189 0 : for (int i = 1; i < argc; i++) {
190 0 : argv[i] = argv[i + 1];
191 : }
192 :
193 : XREShellData shellData;
194 : #if defined(XP_WIN) && defined(MOZ_SANDBOX)
195 : shellData.sandboxBrokerServices =
196 : sandboxing::GetInitializedBrokerServices();
197 : #endif
198 :
199 0 : return gBootstrap->XRE_XPCShellMain(--argc, argv, envp, &shellData);
200 : }
201 :
202 : BootstrapConfig config;
203 :
204 0 : if (appDataFile && *appDataFile) {
205 0 : config.appData = nullptr;
206 0 : config.appDataPath = appDataFile;
207 : } else {
208 : // no -app flag so we use the compiled-in app data
209 0 : config.appData = &sAppData;
210 0 : config.appDataPath = kDesktopFolder;
211 : }
212 :
213 : #if defined(XP_WIN) && defined(MOZ_SANDBOX)
214 : sandbox::BrokerServices* brokerServices =
215 : sandboxing::GetInitializedBrokerServices();
216 : sandboxing::PermissionsService* permissionsService =
217 : sandboxing::GetPermissionsService();
218 : #if defined(MOZ_CONTENT_SANDBOX)
219 : if (!brokerServices) {
220 : Output("Couldn't initialize the broker services.\n");
221 : return 255;
222 : }
223 : #endif
224 : config.sandboxBrokerServices = brokerServices;
225 : config.sandboxPermissionsService = permissionsService;
226 : #endif
227 :
228 : #ifdef LIBFUZZER
229 : if (getenv("LIBFUZZER"))
230 : gBootstrap->XRE_LibFuzzerSetDriver(fuzzer::FuzzerDriver);
231 : #endif
232 :
233 0 : return gBootstrap->XRE_main(argc, argv, config);
234 : }
235 :
236 : static nsresult
237 0 : InitXPCOMGlue()
238 : {
239 0 : UniqueFreePtr<char> exePath = BinaryPath::Get();
240 0 : if (!exePath) {
241 0 : Output("Couldn't find the application directory.\n");
242 0 : return NS_ERROR_FAILURE;
243 : }
244 :
245 0 : gBootstrap = mozilla::GetBootstrap(exePath.get());
246 0 : if (!gBootstrap) {
247 0 : Output("Couldn't load XPCOM.\n");
248 0 : return NS_ERROR_FAILURE;
249 : }
250 :
251 : // This will set this thread as the main thread.
252 0 : gBootstrap->NS_LogInit();
253 :
254 0 : return NS_OK;
255 : }
256 :
257 : #ifdef HAS_DLL_BLOCKLIST
258 : // NB: This must be extern, as this value is checked elsewhere
259 : uint32_t gBlocklistInitFlags = eDllBlocklistInitFlagDefault;
260 : #endif
261 :
262 1 : int main(int argc, char* argv[], char* envp[])
263 : {
264 0 : mozilla::TimeStamp start = mozilla::TimeStamp::Now();
265 :
266 : #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
267 : // We are launching as a content process, delegate to the appropriate
268 : // main
269 1 : if (argc > 1 && IsArg(argv[1], "contentproc")) {
270 : #ifdef HAS_DLL_BLOCKLIST
271 : DllBlocklist_Initialize(eDllBlocklistInitFlagIsChildProcess);
272 : #endif
273 : #if defined(XP_WIN) && defined(MOZ_SANDBOX)
274 : // We need to initialize the sandbox TargetServices before InitXPCOMGlue
275 : // because we might need the sandbox broker to give access to some files.
276 : if (IsSandboxedProcess() && !sandboxing::GetInitializedTargetServices()) {
277 : Output("Failed to initialize the sandbox target services.");
278 : return 255;
279 : }
280 : #endif
281 :
282 0 : nsresult rv = InitXPCOMGlue();
283 0 : if (NS_FAILED(rv)) {
284 : return 255;
285 : }
286 :
287 0 : int result = content_process_main(gBootstrap.get(), argc, argv);
288 :
289 : // InitXPCOMGlue calls NS_LogInit, so we need to balance it here.
290 0 : gBootstrap->NS_LogTerm();
291 :
292 0 : return result;
293 : }
294 : #endif
295 :
296 : #ifdef HAS_DLL_BLOCKLIST
297 : DllBlocklist_Initialize(gBlocklistInitFlags);
298 : #endif
299 :
300 0 : nsresult rv = InitXPCOMGlue();
301 1 : if (NS_FAILED(rv)) {
302 : return 255;
303 : }
304 :
305 1 : gBootstrap->XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start);
306 :
307 : #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
308 0 : gBootstrap->XRE_EnableSameExecutableForContentProc();
309 : #endif
310 :
311 1 : int result = do_main(argc, argv, envp);
312 :
313 0 : gBootstrap->NS_LogTerm();
314 :
315 : #ifdef XP_MACOSX
316 : // Allow writes again. While we would like to catch writes from static
317 : // destructors to allow early exits to use _exit, we know that there is
318 : // at least one such write that we don't control (see bug 826029). For
319 : // now we enable writes again and early exits will have to use exit instead
320 : // of _exit.
321 : gBootstrap->XRE_StopLateWriteChecks();
322 : #endif
323 :
324 : gBootstrap.reset();
325 :
326 : return result;
327 : }
|