void SandboxEarlyInit(GeckoProcessType aType, bool aIsNuwa) { // Bug 1168555: Nuwa isn't reliably single-threaded at this point; // it starts an IPC I/O thread and then shuts it down before calling // the plugin-container entry point, but that thread may not have // finished exiting. If/when any type of sandboxing is used for the // Nuwa process (e.g., unsharing the network namespace there instead // of for each content process, to save memory), this will need to be // changed by moving the SandboxEarlyInit call to an earlier point. if (aIsNuwa) { return; } MOZ_RELEASE_ASSERT(IsSingleThreaded()); const SandboxInfo info = SandboxInfo::Get(); // Which kinds of resource isolation (of those that need to be set // up at this point) can be used by this process? bool canChroot = false; bool canUnshareNet = false; bool canUnshareIPC = false; switch (aType) { case GeckoProcessType_Default: MOZ_ASSERT(false, "SandboxEarlyInit in parent process"); return; #ifdef MOZ_GMP_SANDBOX case GeckoProcessType_GMPlugin: if (!info.Test(SandboxInfo::kEnabledForMedia)) { break; } canUnshareNet = true; canUnshareIPC = true; // Need seccomp-bpf to intercept open(). canChroot = info.Test(SandboxInfo::kHasSeccompBPF); break; #endif // In the future, content processes will be able to use some of // these. default: // Other cases intentionally left blank. break; } // If there's nothing to do, then we're done. if (!canChroot && !canUnshareNet && !canUnshareIPC) { return; } { LinuxCapabilities existingCaps; if (existingCaps.GetCurrent() && existingCaps.AnyEffective()) { SANDBOX_LOG_ERROR("PLEASE DO NOT RUN THIS AS ROOT. Strange things may" " happen when capabilities are dropped."); } } // If capabilities can't be gained, then nothing can be done. if (!info.Test(SandboxInfo::kHasUserNamespaces)) { // Drop any existing capabilities; unsharing the user namespace // would implicitly drop them, so if we're running in a broken // configuration where that would matter (e.g., running as root // from a non-root-owned mode-0700 directory) this means it will // break the same way on all kernels and be easier to troubleshoot. LinuxCapabilities().SetCurrent(); return; } // The failure cases for the various unshares, and setting up the // chroot helper, don't strictly need to be fatal -- but they also // shouldn't fail on any reasonable system, so let's take the small // risk of breakage over the small risk of quietly providing less // security than we expect. (Unlike in SandboxInfo, this is in the // child process, so crashing here isn't as severe a response to the // unexpected.) if (!UnshareUserNamespace()) { SANDBOX_LOG_ERROR("unshare(CLONE_NEWUSER): %s", strerror(errno)); // If CanCreateUserNamespace (SandboxInfo.cpp) returns true, then // the unshare shouldn't have failed. MOZ_CRASH("unshare(CLONE_NEWUSER)"); } // No early returns after this point! We need to drop the // capabilities that were gained by unsharing the user namesapce. if (canUnshareIPC && syscall(__NR_unshare, CLONE_NEWIPC) != 0) { SANDBOX_LOG_ERROR("unshare(CLONE_NEWIPC): %s", strerror(errno)); MOZ_CRASH("unshare(CLONE_NEWIPC)"); } if (canUnshareNet && syscall(__NR_unshare, CLONE_NEWNET) != 0) { SANDBOX_LOG_ERROR("unshare(CLONE_NEWNET): %s", strerror(errno)); MOZ_CRASH("unshare(CLONE_NEWNET)"); } if (canChroot) { gChrootHelper = MakeUnique<SandboxChroot>(); if (!gChrootHelper->Prepare()) { SANDBOX_LOG_ERROR("failed to set up chroot helper"); MOZ_CRASH("SandboxChroot::Prepare"); } } if (!LinuxCapabilities().SetCurrent()) { SANDBOX_LOG_ERROR("dropping capabilities: %s", strerror(errno)); MOZ_CRASH("can't drop capabilities"); } }
void SandboxEarlyInit(GeckoProcessType aType) { const SandboxInfo info = SandboxInfo::Get(); if (info.Test(SandboxInfo::kUnexpectedThreads)) { return; } MOZ_RELEASE_ASSERT(IsSingleThreaded()); // Which kinds of resource isolation (of those that need to be set // up at this point) can be used by this process? bool canChroot = false; bool canUnshareNet = false; bool canUnshareIPC = false; switch (aType) { case GeckoProcessType_Default: MOZ_ASSERT(false, "SandboxEarlyInit in parent process"); return; #ifdef MOZ_GMP_SANDBOX case GeckoProcessType_GMPlugin: if (!info.Test(SandboxInfo::kEnabledForMedia)) { break; } canUnshareNet = true; canUnshareIPC = true; // Need seccomp-bpf to intercept open(). canChroot = info.Test(SandboxInfo::kHasSeccompBPF); break; #endif // In the future, content processes will be able to use some of // these. default: // Other cases intentionally left blank. break; } // If TSYNC is not supported, set up signal handler // used to enable seccomp on each thread. if (!info.Test(SandboxInfo::kHasSeccompTSync)) { gSeccompTsyncBroadcastSignum = FindFreeSignalNumber(); if (gSeccompTsyncBroadcastSignum == 0) { SANDBOX_LOG_ERROR("No available signal numbers!"); MOZ_CRASH(); } void (*oldHandler)(int); oldHandler = signal(gSeccompTsyncBroadcastSignum, SetThreadSandboxHandler); if (oldHandler != SIG_DFL) { // See the comment on FindFreeSignalNumber about race conditions. SANDBOX_LOG_ERROR("signal %d in use by handler %p!\n", gSeccompTsyncBroadcastSignum, oldHandler); MOZ_CRASH(); } } // If there's nothing to do, then we're done. if (!canChroot && !canUnshareNet && !canUnshareIPC) { return; } { LinuxCapabilities existingCaps; if (existingCaps.GetCurrent() && existingCaps.AnyEffective()) { SANDBOX_LOG_ERROR("PLEASE DO NOT RUN THIS AS ROOT. Strange things may" " happen when capabilities are dropped."); } } // If capabilities can't be gained, then nothing can be done. if (!info.Test(SandboxInfo::kHasUserNamespaces)) { // Drop any existing capabilities; unsharing the user namespace // would implicitly drop them, so if we're running in a broken // configuration where that would matter (e.g., running as root // from a non-root-owned mode-0700 directory) this means it will // break the same way on all kernels and be easier to troubleshoot. LinuxCapabilities().SetCurrent(); return; } // The failure cases for the various unshares, and setting up the // chroot helper, don't strictly need to be fatal -- but they also // shouldn't fail on any reasonable system, so let's take the small // risk of breakage over the small risk of quietly providing less // security than we expect. (Unlike in SandboxInfo, this is in the // child process, so crashing here isn't as severe a response to the // unexpected.) if (!UnshareUserNamespace()) { SANDBOX_LOG_ERROR("unshare(CLONE_NEWUSER): %s", strerror(errno)); // If CanCreateUserNamespace (SandboxInfo.cpp) returns true, then // the unshare shouldn't have failed. MOZ_CRASH("unshare(CLONE_NEWUSER)"); } // No early returns after this point! We need to drop the // capabilities that were gained by unsharing the user namesapce. if (canUnshareIPC && syscall(__NR_unshare, CLONE_NEWIPC) != 0) { SANDBOX_LOG_ERROR("unshare(CLONE_NEWIPC): %s", strerror(errno)); MOZ_CRASH("unshare(CLONE_NEWIPC)"); } if (canUnshareNet && syscall(__NR_unshare, CLONE_NEWNET) != 0) { SANDBOX_LOG_ERROR("unshare(CLONE_NEWNET): %s", strerror(errno)); MOZ_CRASH("unshare(CLONE_NEWNET)"); } if (canChroot) { gChrootHelper = MakeUnique<SandboxChroot>(); if (!gChrootHelper->Prepare()) { SANDBOX_LOG_ERROR("failed to set up chroot helper"); MOZ_CRASH("SandboxChroot::Prepare"); } } if (!LinuxCapabilities().SetCurrent()) { SANDBOX_LOG_ERROR("dropping capabilities: %s", strerror(errno)); MOZ_CRASH("can't drop capabilities"); } }