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/. */
6 #include "nsXULAppAPI.h"
7 #include "mozilla/XREAppData.h"
8 #include "XREShellData.h"
9 #include "application.ini.h"
10 #include "mozilla/Bootstrap.h"
11 #include "mozilla/ProcessType.h"
12 #include "mozilla/RuntimeExceptionModule.h"
13 #include "mozilla/ScopeExit.h"
14 #include "BrowserDefines.h"
18 #elif defined(XP_UNIX)
19 # include <sys/resource.h>
31 # include "mozilla/PreXULSkeletonUI.h"
32 # include "freestanding/SharedSection.h"
33 # include "LauncherProcessWin.h"
34 # include "mozilla/GeckoArgs.h"
35 # include "mozilla/mscom/ProcessRuntime.h"
36 # include "mozilla/WindowsDllBlocklist.h"
37 # include "mozilla/WindowsDpiInitialization.h"
38 # include "mozilla/WindowsProcessMitigations.h"
40 # define XRE_WANT_ENVIRON
41 # define strcasecmp _stricmp
43 # include "mozilla/sandboxing/SandboxInitialization.h"
46 #include "BinaryPath.h"
48 #include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL
50 #include "mozilla/Sprintf.h"
51 #include "mozilla/StartupTimeline.h"
52 #include "BaseProfiler.h"
55 # include "FuzzerDefs.h"
58 #ifdef MOZ_LINUX_32_SSE2_STARTUP_ERROR
60 # include "mozilla/Unused.h"
62 static bool IsSSE2Available() {
63 // The rest of the app has been compiled to assume that SSE2 is present
64 // unconditionally, so we can't use the normal copy of SSE.cpp here.
65 // Since SSE.cpp caches the results and we need them only transiently,
66 // instead of #including SSE.cpp here, let's just inline the specific check
68 unsigned int level
= 1u;
69 unsigned int eax
, ebx
, ecx
, edx
;
70 unsigned int bits
= (1u << 26);
71 unsigned int max
= __get_cpuid_max(0, nullptr);
75 __cpuid_count(level
, 0, eax
, ebx
, ecx
, edx
);
76 return (edx
& bits
) == bits
;
79 static const char sSSE2Message
[] =
80 "This browser version requires a processor with the SSE2 instruction "
81 "set extension.\nYou may be able to obtain a version that does not "
82 "require SSE2 from your Linux distribution.\n";
84 __attribute__((constructor
)) static void SSE2Check() {
85 if (IsSSE2Available()) {
88 // Using write() in order to avoid jemalloc-based buffering. Ignoring return
89 // values, since there isn't much we could do on failure and there is no
90 // point in trying to recover from errors.
92 write(STDERR_FILENO
, sSSE2Message
, MOZ_ARRAY_LENGTH(sSSE2Message
) - 1));
93 // _exit() instead of exit() to avoid running the usual "at exit" code.
98 #if !defined(MOZ_WIDGET_COCOA) && !defined(MOZ_WIDGET_ANDROID)
99 # define MOZ_BROWSER_CAN_BE_CONTENTPROC
100 # include "../../ipc/contentproc/plugin-container.cpp"
103 using namespace mozilla
;
106 # define kOSXResourcesFolder "Resources"
108 #define kDesktopFolder "browser"
110 static MOZ_FORMAT_PRINTF(1, 2) void Output(const char* fmt
, ...) {
115 vfprintf(stderr
, fmt
, ap
);
118 vsnprintf_s(msg
, _countof(msg
), _TRUNCATE
, fmt
, ap
);
120 wchar_t wide_msg
[2048];
121 MultiByteToWideChar(CP_UTF8
, 0, msg
, -1, wide_msg
, _countof(wide_msg
));
123 fwprintf_s(stderr
, wide_msg
);
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");
129 decltype(MessageBoxW
)* messageBoxW
=
130 (decltype(MessageBoxW
)*)GetProcAddress(user32
, "MessageBoxW");
132 messageBoxW(nullptr, wide_msg
, L
"Firefox",
133 MB_OK
| MB_ICONERROR
| MB_SETFOREGROUND
);
144 * Return true if |arg| matches the given argument name.
146 static bool IsArg(const char* arg
, const char* s
) {
148 if (*++arg
== '-') ++arg
;
149 return !strcasecmp(arg
, s
);
153 if (*arg
== '/') return !strcasecmp(++arg
, s
);
159 Bootstrap::UniquePtr gBootstrap
;
161 static int do_main(int argc
, char* argv
[], char* envp
[]) {
162 // Allow firefox.exe to launch XULRunner apps via -app <application.ini>
163 // Note that -app must be the *first* argument.
164 const char* appDataFile
= getenv("XUL_APP_FILE");
165 if ((!appDataFile
|| !*appDataFile
) && (argc
> 1 && IsArg(argv
[1], "app"))) {
167 Output("Incorrect number of arguments passed to -app");
170 appDataFile
= argv
[2];
172 char appEnv
[MAXPATHLEN
];
173 SprintfLiteral(appEnv
, "XUL_APP_FILE=%s", argv
[2]);
174 if (putenv(strdup(appEnv
))) {
175 Output("Couldn't set %s.\n", appEnv
);
181 } else if (argc
> 1 && IsArg(argv
[1], "xpcshell")) {
182 for (int i
= 1; i
< argc
; i
++) {
183 argv
[i
] = argv
[i
+ 1];
186 XREShellData shellData
;
187 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
188 shellData
.sandboxBrokerServices
=
189 sandboxing::GetInitializedBrokerServices();
193 shellData
.fuzzerDriver
= fuzzer::FuzzerDriver
;
196 return gBootstrap
->XRE_XPCShellMain(--argc
, argv
, envp
, &shellData
);
199 BootstrapConfig config
;
201 if (appDataFile
&& *appDataFile
) {
202 config
.appData
= nullptr;
203 config
.appDataPath
= appDataFile
;
205 // no -app flag so we use the compiled-in app data
206 config
.appData
= &sAppData
;
207 config
.appDataPath
= kDesktopFolder
;
210 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
211 sandbox::BrokerServices
* brokerServices
=
212 sandboxing::GetInitializedBrokerServices();
213 if (!brokerServices
) {
214 Output("Couldn't initialize the broker services.\n");
217 config
.sandboxBrokerServices
= brokerServices
;
221 if (getenv("FUZZER"))
222 gBootstrap
->XRE_LibFuzzerSetDriver(fuzzer::FuzzerDriver
);
225 EnsureBrowserCommandlineSafe(argc
, argv
);
227 return gBootstrap
->XRE_main(argc
, argv
, config
);
230 static nsresult
InitXPCOMGlue(LibLoadingStrategy aLibLoadingStrategy
) {
235 UniqueFreePtr
<char> exePath
= BinaryPath::Get();
237 Output("Couldn't find the application directory.\n");
238 return NS_ERROR_FAILURE
;
241 auto bootstrapResult
=
242 mozilla::GetBootstrap(exePath
.get(), aLibLoadingStrategy
);
243 if (bootstrapResult
.isErr()) {
244 Output("Couldn't load XPCOM.\n");
245 return NS_ERROR_FAILURE
;
248 gBootstrap
= bootstrapResult
.unwrap();
250 // This will set this thread as the main thread.
251 gBootstrap
->NS_LogInit();
256 #ifdef HAS_DLL_BLOCKLIST
257 // NB: This must be extern, as this value is checked elsewhere
258 uint32_t gBlocklistInitFlags
= eDllBlocklistInitFlagDefault
;
262 static void ReserveDefaultFileDescriptors() {
263 // Reserve the lower positions of the file descriptors to make sure
264 // we don't reuse stdin/stdout/stderr in case they we closed
266 // Otherwise code explicitly writing to fd 1 or 2 might accidentally
267 // write to something else, like in bug 1820896 where FD 1 is
268 // reused for the X server display connection.
269 int fd
= open("/dev/null", O_RDONLY
);
270 for (int i
= 0; i
< 2; i
++) {
271 mozilla::Unused
<< dup(fd
);
276 int main(int argc
, char* argv
[], char* envp
[]) {
278 ReserveDefaultFileDescriptors();
280 #if defined(MOZ_ENABLE_FORKSERVER)
281 if (strcmp(argv
[argc
- 1], "forkserver") == 0) {
282 nsresult rv
= InitXPCOMGlue(LibLoadingStrategy::NoReadAhead
);
287 // Run a fork server in this process, single thread. When it
288 // returns, it means the fork server have been stopped or a new
289 // content process is created.
291 // For the later case, XRE_ForkServer() will return false, running
292 // in a content process just forked from the fork server process.
293 // argc & argv will be updated with the values passing from the
294 // chrome process. With the new values, this function
295 // continues the reset of the code acting as a content process.
296 if (gBootstrap
->XRE_ForkServer(&argc
, &argv
)) {
297 // Return from the fork server in the fork server process.
298 // Stop the fork server.
299 gBootstrap
->NS_LogTerm();
302 // In a content process forked from the fork server.
303 // Start acting as a content process.
307 mozilla::TimeStamp start
= mozilla::TimeStamp::Now();
309 AUTO_BASE_PROFILER_INIT
;
310 AUTO_BASE_PROFILER_LABEL("nsBrowserApp main", OTHER
);
312 // Make sure we unregister the runtime exception module before returning.
313 // We do this here to cover both registers for child and main processes.
314 auto unregisterRuntimeExceptionModule
=
315 MakeScopeExit([] { CrashReporter::UnregisterRuntimeExceptionModule(); });
317 #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
318 // We are launching as a content process, delegate to the appropriate
320 if (argc
> 1 && IsArg(argv
[1], "contentproc")) {
321 // Set the process type. We don't remove the arg here as that will be done
322 // later in common code.
323 SetGeckoProcessType(argv
[argc
- 1]);
325 // Register an external module to report on otherwise uncatchable
326 // exceptions. Note that in child processes this must be called after Gecko
327 // process type has been set.
328 CrashReporter::RegisterRuntimeExceptionModule();
330 # if defined(XP_WIN) && defined(MOZ_SANDBOX)
331 // We need to set whether our process is supposed to have win32k locked down
332 // from the command line setting before DllBlocklist_Initialize,
333 // GetInitializedTargetServices and WindowsDpiInitialization.
334 Maybe
<bool> win32kLockedDown
=
335 mozilla::geckoargs::sWin32kLockedDown
.Get(argc
, argv
);
336 if (win32kLockedDown
.isSome() && *win32kLockedDown
) {
337 mozilla::SetWin32kLockedDownInPolicy();
341 # ifdef HAS_DLL_BLOCKLIST
343 gBlocklistInitFlags
| eDllBlocklistInitFlagIsChildProcess
;
344 SetDllBlocklistProcessTypeFlags(initFlags
, GetGeckoProcessType());
345 DllBlocklist_Initialize(initFlags
);
346 # endif // HAS_DLL_BLOCKLIST
348 # if defined(XP_WIN) && defined(MOZ_SANDBOX)
349 // We need to initialize the sandbox TargetServices before InitXPCOMGlue
350 // because we might need the sandbox broker to give access to some files.
351 if (IsSandboxedProcess() && !sandboxing::GetInitializedTargetServices()) {
352 Output("Failed to initialize the sandbox target services.");
357 // Ideally, we would be able to set our DPI awareness in
358 // firefox.exe.manifest Unfortunately, that would cause Win32k calls when
359 // user32.dll gets loaded, which would be incompatible with Win32k Lockdown
361 // MSDN says that it's allowed-but-not-recommended to initialize DPI
362 // programatically, as long as it's done before any HWNDs are created.
363 // Thus, we do it almost as soon as we possibly can
365 auto result
= mozilla::WindowsDpiInitialization();
366 (void)result
; // Ignore errors since some tools block DPI calls
370 nsresult rv
= InitXPCOMGlue(LibLoadingStrategy::NoReadAhead
);
375 int result
= content_process_main(gBootstrap
.get(), argc
, argv
);
377 # if defined(DEBUG) && defined(HAS_DLL_BLOCKLIST)
378 DllBlocklist_Shutdown();
381 // InitXPCOMGlue calls NS_LogInit, so we need to balance it here.
382 gBootstrap
->NS_LogTerm();
388 // Register an external module to report on otherwise uncatchable exceptions.
389 CrashReporter::RegisterRuntimeExceptionModule();
391 #ifdef HAS_DLL_BLOCKLIST
392 DllBlocklist_Initialize(gBlocklistInitFlags
);
395 // We will likely only ever support this as a command line argument on Windows
396 // and OSX, so we're ifdefing here just to not create any expectations.
397 #if defined(XP_WIN) || defined(XP_MACOSX)
398 if (argc
> 1 && IsArg(argv
[1], "silentmode")) {
399 ::putenv(const_cast<char*>("MOZ_APP_SILENT_START=1"));
401 // On windows We also want to set a separate variable, which we want to
402 // persist across restarts, which will let us keep the process alive
403 // even if the last window is closed.
404 ::putenv(const_cast<char*>("MOZ_APP_ALLOW_WINDOWLESS=1"));
406 # if defined(XP_MACOSX)
407 ::putenv(const_cast<char*>("MOZ_APP_NO_DOCK=1"));
414 // Ideally, we would be able to set our DPI awareness in firefox.exe.manifest
415 // Unfortunately, that would cause Win32k calls when user32.dll gets loaded,
416 // which would be incompatible with Win32k Lockdown
418 // MSDN says that it's allowed-but-not-recommended to initialize DPI
419 // programatically, as long as it's done before any HWNDs are created.
420 // Thus, we do it almost as soon as we possibly can
422 auto result
= mozilla::WindowsDpiInitialization();
423 (void)result
; // Ignore errors since some tools block DPI calls
426 // Once the browser process hits the main function, we no longer need
427 // a writable section handle because all dependent modules have been
429 mozilla::freestanding::gSharedSection
.ConvertToReadOnly();
431 mozilla::CreateAndStorePreXULSkeletonUI(GetModuleHandle(nullptr), argc
, argv
);
434 nsresult rv
= InitXPCOMGlue(LibLoadingStrategy::ReadAhead
);
439 gBootstrap
->XRE_StartupTimelineRecord(mozilla::StartupTimeline::START
, start
);
441 #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
442 gBootstrap
->XRE_EnableSameExecutableForContentProc();
445 int result
= do_main(argc
, argv
, envp
);
448 CleanupProcessRuntime();
451 gBootstrap
->NS_LogTerm();
453 #if defined(DEBUG) && defined(HAS_DLL_BLOCKLIST)
454 DllBlocklist_Shutdown();
458 // Allow writes again. While we would like to catch writes from static
459 // destructors to allow early exits to use _exit, we know that there is
460 // at least one such write that we don't control (see bug 826029). For
461 // now we enable writes again and early exits will have to use exit instead
463 gBootstrap
->XRE_StopLateWriteChecks();