Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit b9bdcde

Browse files
committed
Bug 1431441 - Part 3 - Start the Mac content sandbox earlier r=Alex_Gaynor
Pass sandbox parameters to content processes on the command line allowing for early sandbox startup. Limited to Nightly until confirmed to be stable and ready to ride the trains. Enable early sandbox startup by default on Nightly and use pref "security.sandbox.content.mac.earlyinit" to disable early startup for debugging purposes. Once early startup is stable, the original sandbox startup code can be removed. Depends on D6719 Differential Revision: https://phabricator.services.mozilla.com/D6720 --HG-- extra : moz-landing-system : lando
1 parent a710b03 commit b9bdcde

10 files changed

Lines changed: 382 additions & 0 deletions

File tree

browser/app/moz.build

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ if CONFIG['OS_ARCH'] == 'WINNT':
8484
'ole32.dll',
8585
]
8686

87+
if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'Darwin':
88+
USE_LIBS += [
89+
'mozsandbox',
90+
]
91+
8792
if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
8893
# For sandbox includes and the include dependencies those have
8994
LOCAL_INCLUDES += [

browser/app/nsBrowserApp.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@
4343
#include "FuzzerDefs.h"
4444
#endif
4545

46+
#ifdef XP_MACOSX
47+
#include "mozilla/Sandbox.h"
48+
#endif
49+
4650
#ifdef MOZ_LINUX_32_SSE2_STARTUP_ERROR
4751
#include <cpuid.h>
4852
#include "mozilla/Unused.h"
@@ -263,6 +267,16 @@ int main(int argc, char* argv[], char* envp[])
263267
{
264268
mozilla::TimeStamp start = mozilla::TimeStamp::Now();
265269

270+
#ifdef XP_MACOSX
271+
if (argc > 1 && IsArg(argv[1], "contentproc")) {
272+
std::string err;
273+
if (!mozilla::EarlyStartMacSandboxIfEnabled(argc, argv, err)) {
274+
Output("Sandbox error: %s\n", err.c_str());
275+
MOZ_CRASH("Sandbox initialization failed");
276+
}
277+
}
278+
#endif
279+
266280
#ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
267281
// We are launching as a content process, delegate to the appropriate
268282
// main

browser/app/profile/firefox.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,12 @@ pref("security.sandbox.gpu.level", 0);
10261026
pref("security.sandbox.gmp.win32k-disable", false);
10271027
#endif
10281028

1029+
#if defined(NIGHTLY_BUILD) && defined(XP_MACOSX) && defined(MOZ_SANDBOX)
1030+
// Start the Mac sandbox immediately during child process startup instead
1031+
// of when messaged by the parent after the message loop is running.
1032+
pref("security.sandbox.content.mac.earlyinit", true);
1033+
#endif
1034+
10291035
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX) && defined(MOZ_CONTENT_SANDBOX)
10301036
// This pref is discussed in bug 1083344, the naming is inspired from its
10311037
// Windows counterpart, but on Mac it's an integer which means:

dom/ipc/ContentParent.cpp

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
#include "mozilla/Unused.h"
111111
#include "mozilla/HangDetails.h"
112112
#include "nsAnonymousTemporaryFile.h"
113+
#include "nsAppDirectoryServiceDefs.h"
113114
#include "nsAppRunner.h"
114115
#include "nsCDefaultURIFixup.h"
115116
#include "nsCExternalHandlerService.h"
@@ -119,6 +120,7 @@
119120
#include "nsConsoleService.h"
120121
#include "nsContentUtils.h"
121122
#include "nsDebugImpl.h"
123+
#include "nsDirectoryService.h"
122124
#include "nsDirectoryServiceDefs.h"
123125
#include "nsEmbedCID.h"
124126
#include "nsFrameLoader.h"
@@ -214,6 +216,10 @@
214216
#include "signaling/src/peerconnection/WebrtcGlobalParent.h"
215217
#endif
216218

219+
#if defined(XP_MACOSX)
220+
#include "nsMacUtilsImpl.h"
221+
#endif
222+
217223
#if defined(ANDROID) || defined(LINUX)
218224
#include "nsSystemInfo.h"
219225
#endif
@@ -609,6 +615,10 @@ static const char* sObserverTopics[] = {
609615
"clear-site-data-reload-needed",
610616
};
611617

618+
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
619+
bool ContentParent::sEarlySandboxInit = false;
620+
#endif
621+
612622
// PreallocateProcess is called by the PreallocatedProcessManager.
613623
// ContentParent then takes this process back within GetNewOrUsedBrowserProcess.
614624
/*static*/ already_AddRefed<ContentParent>
@@ -2130,6 +2140,115 @@ ContentParent::GetTestShellSingleton()
21302140
return static_cast<TestShellParent*>(p);
21312141
}
21322142

2143+
#ifdef XP_MACOSX
2144+
void
2145+
ContentParent::AppendSandboxParams(std::vector<std::string> &aArgs)
2146+
{
2147+
nsCOMPtr<nsIProperties>
2148+
directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
2149+
if (!directoryService) {
2150+
MOZ_CRASH("Failed to get the directory service");
2151+
}
2152+
2153+
// Indicates the child should startup the sandbox
2154+
aArgs.push_back("-sbStartup");
2155+
2156+
// The content sandbox level
2157+
int contentSandboxLevel =
2158+
Preferences::GetInt("security.sandbox.content.level");
2159+
std::ostringstream os;
2160+
os << contentSandboxLevel;
2161+
std::string contentSandboxLevelString = os.str();
2162+
aArgs.push_back("-sbLevel");
2163+
aArgs.push_back(contentSandboxLevelString);
2164+
2165+
// Sandbox logging
2166+
if (Preferences::GetBool("security.sandbox.logging.enabled") ||
2167+
PR_GetEnv("MOZ_SANDBOX_LOGGING")) {
2168+
aArgs.push_back("-sbLogging");
2169+
}
2170+
2171+
// For file content processes
2172+
if (GetRemoteType().EqualsLiteral(FILE_REMOTE_TYPE)) {
2173+
aArgs.push_back("-sbAllowFileAccess");
2174+
}
2175+
2176+
// Audio access
2177+
if (!Preferences::GetBool("media.cubeb.sandbox")) {
2178+
aArgs.push_back("-sbAllowAudio");
2179+
}
2180+
2181+
// .app path (normalized)
2182+
nsAutoCString appPath;
2183+
if (!nsMacUtilsImpl::GetAppPath(appPath)) {
2184+
MOZ_CRASH("Failed to get app dir paths");
2185+
}
2186+
aArgs.push_back("-sbAppPath");
2187+
aArgs.push_back(appPath.get());
2188+
2189+
// TESTING_READ_PATH1
2190+
nsAutoCString testingReadPath1;
2191+
Preferences::GetCString("security.sandbox.content.mac.testing_read_path1",
2192+
testingReadPath1);
2193+
if (!testingReadPath1.IsEmpty()) {
2194+
aArgs.push_back("-sbTestingReadPath");
2195+
aArgs.push_back(testingReadPath1.get());
2196+
}
2197+
2198+
// TESTING_READ_PATH2
2199+
nsAutoCString testingReadPath2;
2200+
Preferences::GetCString("security.sandbox.content.mac.testing_read_path2",
2201+
testingReadPath2);
2202+
if (!testingReadPath2.IsEmpty()) {
2203+
aArgs.push_back("-sbTestingReadPath");
2204+
aArgs.push_back(testingReadPath2.get());
2205+
}
2206+
2207+
// TESTING_READ_PATH3, TESTING_READ_PATH4. In development builds,
2208+
// these are used to whitelist the repo dir and object dir respectively.
2209+
nsresult rv;
2210+
if (mozilla::IsDevelopmentBuild()) {
2211+
// Repo dir
2212+
nsCOMPtr<nsIFile> repoDir;
2213+
rv = mozilla::GetRepoDir(getter_AddRefs(repoDir));
2214+
if (NS_FAILED(rv)) {
2215+
MOZ_CRASH("Failed to get path to repo dir");
2216+
}
2217+
nsCString repoDirPath;
2218+
Unused << repoDir->GetNativePath(repoDirPath);
2219+
aArgs.push_back("-sbTestingReadPath");
2220+
aArgs.push_back(repoDirPath.get());
2221+
2222+
// Object dir
2223+
nsCOMPtr<nsIFile> objDir;
2224+
rv = mozilla::GetObjDir(getter_AddRefs(objDir));
2225+
if (NS_FAILED(rv)) {
2226+
MOZ_CRASH("Failed to get path to build object dir");
2227+
}
2228+
nsCString objDirPath;
2229+
Unused << objDir->GetNativePath(objDirPath);
2230+
aArgs.push_back("-sbTestingReadPath");
2231+
aArgs.push_back(objDirPath.get());
2232+
}
2233+
2234+
// DEBUG_WRITE_DIR
2235+
#ifdef DEBUG
2236+
// When a content process dies intentionally (|NoteIntentionalCrash|), for
2237+
// tests it wants to log that it did this. Allow writing to this location
2238+
// that the testrunner wants.
2239+
char *bloatLog = PR_GetEnv("XPCOM_MEM_BLOAT_LOG");
2240+
if (bloatLog != nullptr) {
2241+
// |bloatLog| points to a specific file, but we actually write to a sibling
2242+
// of that path.
2243+
nsAutoCString bloatDirectoryPath =
2244+
nsMacUtilsImpl::GetDirectoryPath(bloatLog);
2245+
aArgs.push_back("-sbDebugWriteDir");
2246+
aArgs.push_back(bloatDirectoryPath.get());
2247+
}
2248+
#endif // DEBUG
2249+
}
2250+
#endif // XP_MACOSX
2251+
21332252
bool
21342253
ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PRIORITY_FOREGROUND */)
21352254
{
@@ -2218,6 +2337,12 @@ ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PR
22182337
extraArgs.push_back("-safeMode");
22192338
}
22202339

2340+
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
2341+
if (sEarlySandboxInit && IsContentSandboxEnabled()) {
2342+
AppendSandboxParams(extraArgs);
2343+
}
2344+
#endif
2345+
22212346
nsCString parentBuildID(mozilla::PlatformBuildID());
22222347
extraArgs.push_back("-parentBuildID");
22232348
extraArgs.push_back(parentBuildID.get());
@@ -2337,6 +2462,17 @@ ContentParent::ContentParent(ContentParent* aOpener,
23372462
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
23382463
bool isFile = mRemoteType.EqualsLiteral(FILE_REMOTE_TYPE);
23392464
mSubprocess = new ContentProcessHost(this, isFile);
2465+
2466+
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
2467+
// sEarlySandboxInit is statically initialized to false.
2468+
// Once we've set it to true due to the pref, avoid checking the
2469+
// pref on subsequent calls. As a result, changing the earlyinit
2470+
// pref requires restarting the browser to take effect.
2471+
if (!ContentParent::sEarlySandboxInit) {
2472+
ContentParent::sEarlySandboxInit =
2473+
Preferences::GetBool("security.sandbox.content.mac.earlyinit");
2474+
}
2475+
#endif
23402476
}
23412477

23422478
ContentParent::~ContentParent()
@@ -2607,6 +2743,12 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority)
26072743
// of value to take effect.
26082744
shouldSandbox = IsContentSandboxEnabled();
26092745

2746+
#ifdef XP_MACOSX
2747+
// If the sandbox was initialized during content process
2748+
// startup, we must not send the SetProcessSandbox message.
2749+
shouldSandbox = shouldSandbox && !sEarlySandboxInit;
2750+
#endif
2751+
26102752
#ifdef XP_LINUX
26112753
if (shouldSandbox) {
26122754
MOZ_ASSERT(!mSandboxBroker);

dom/ipc/ContentParent.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,6 +1262,8 @@ class ContentParent final : public PContentParent
12621262
// initializing.
12631263
void MaybeEnableRemoteInputEventQueue();
12641264

1265+
void AppendSandboxParams(std::vector<std::string>& aArgs);
1266+
12651267
public:
12661268
void SendGetFilesResponseAndForget(const nsID& aID,
12671269
const GetFilesResponseResult& aResult);
@@ -1387,6 +1389,13 @@ class ContentParent final : public PContentParent
13871389

13881390
static uint64_t sNextTabParentId;
13891391
static nsDataHashtable<nsUint64HashKey, TabParent*> sNextTabParents;
1392+
1393+
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
1394+
// When set to true, indicates that content processes should
1395+
// initialize their sandbox during startup instead of waiting
1396+
// for the SetProcessSandbox IPDL message.
1397+
static bool sEarlySandboxInit;
1398+
#endif
13901399
};
13911400

13921401
} // namespace dom

ipc/app/MozillaRuntimeMain.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,23 @@
99
#include "mozilla/Bootstrap.h"
1010
#include "mozilla/WindowsDllBlocklist.h"
1111

12+
#ifdef XP_MACOSX
13+
#include "mozilla/Sandbox.h"
14+
#endif
15+
1216
using namespace mozilla;
1317

1418
int
1519
main(int argc, char *argv[])
1620
{
21+
#ifdef XP_MACOSX
22+
std::string err;
23+
if (!mozilla::EarlyStartMacSandboxIfEnabled(argc, argv, err)) {
24+
fprintf(stderr, "Sandbox error: %s\n", err.c_str());
25+
MOZ_CRASH("Sandbox initialization failed");
26+
}
27+
#endif
28+
1729
#ifdef HAS_DLL_BLOCKLIST
1830
DllBlocklist_Initialize(eDllBlocklistInitFlagIsChildProcess);
1931
#endif

ipc/glue/GeckoChildProcessHost.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,12 @@ AddAppDirToCommandLine(std::vector<std::string>& aCmdLine)
549549
NS_GET_IID(nsIFile),
550550
getter_AddRefs(profileDir));
551551
if (NS_SUCCEEDED(rv)) {
552+
// If the profile doesn't exist, normalization will
553+
// fail. But we don't return an error here because some
554+
// tests require startup with a missing profile dir.
555+
// For users, almost universally, the profile will be in
556+
// the home directory and normalization isn't required.
557+
mozilla::Unused << profileDir->Normalize();
552558
nsAutoCString path;
553559
MOZ_ALWAYS_SUCCEEDS(profileDir->GetNativePath(path));
554560
aCmdLine.push_back("-profile");

security/sandbox/mac/Sandbox.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,17 @@ typedef struct _MacSandboxInfo {
6767
std::string testingReadPath3;
6868
std::string testingReadPath4;
6969

70+
std::string parentPort;
71+
std::string crashServerPort;
72+
7073
bool shouldLog;
7174
} MacSandboxInfo;
7275

7376
namespace mozilla {
7477

7578
bool StartMacSandbox(MacSandboxInfo const &aInfo, std::string &aErrorMessage);
79+
bool EarlyStartMacSandboxIfEnabled(int aArgc, char** aArgv,
80+
std::string &aErrorMessage);
7681

7782
} // namespace mozilla
7883

0 commit comments

Comments
 (0)