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

Commit ef9150c

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 a99a3fe commit ef9150c

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>
@@ -2145,6 +2155,115 @@ ContentParent::GetTestShellSingleton()
21452155
return static_cast<TestShellParent*>(p);
21462156
}
21472157

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

2355+
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
2356+
if (sEarlySandboxInit && IsContentSandboxEnabled()) {
2357+
AppendSandboxParams(extraArgs);
2358+
}
2359+
#endif
2360+
22362361
nsCString parentBuildID(mozilla::PlatformBuildID());
22372362
extraArgs.push_back("-parentBuildID");
22382363
extraArgs.push_back(parentBuildID.get());
@@ -2352,6 +2477,17 @@ ContentParent::ContentParent(ContentParent* aOpener,
23522477
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
23532478
bool isFile = mRemoteType.EqualsLiteral(FILE_REMOTE_TYPE);
23542479
mSubprocess = new ContentProcessHost(this, isFile);
2480+
2481+
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
2482+
// sEarlySandboxInit is statically initialized to false.
2483+
// Once we've set it to true due to the pref, avoid checking the
2484+
// pref on subsequent calls. As a result, changing the earlyinit
2485+
// pref requires restarting the browser to take effect.
2486+
if (!ContentParent::sEarlySandboxInit) {
2487+
ContentParent::sEarlySandboxInit =
2488+
Preferences::GetBool("security.sandbox.content.mac.earlyinit");
2489+
}
2490+
#endif
23552491
}
23562492

23572493
ContentParent::~ContentParent()
@@ -2622,6 +2758,12 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority)
26222758
// of value to take effect.
26232759
shouldSandbox = IsContentSandboxEnabled();
26242760

2761+
#ifdef XP_MACOSX
2762+
// If the sandbox was initialized during content process
2763+
// startup, we must not send the SetProcessSandbox message.
2764+
shouldSandbox = shouldSandbox && !sEarlySandboxInit;
2765+
#endif
2766+
26252767
#ifdef XP_LINUX
26262768
if (shouldSandbox) {
26272769
MOZ_ASSERT(!mSandboxBroker);

dom/ipc/ContentParent.h

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

1266+
void AppendSandboxParams(std::vector<std::string>& aArgs);
1267+
12661268
public:
12671269
void SendGetFilesResponseAndForget(const nsID& aID,
12681270
const GetFilesResponseResult& aResult);
@@ -1388,6 +1390,13 @@ class ContentParent final : public PContentParent
13881390

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

13931402
} // 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)