diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
commit | 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch) | |
tree | a31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /security/sandbox/mac/Sandbox.mm | |
parent | Initial commit. (diff) | |
download | firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip |
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'security/sandbox/mac/Sandbox.mm')
-rw-r--r-- | security/sandbox/mac/Sandbox.mm | 802 |
1 files changed, 802 insertions, 0 deletions
diff --git a/security/sandbox/mac/Sandbox.mm b/security/sandbox/mac/Sandbox.mm new file mode 100644 index 0000000000..24589eb00f --- /dev/null +++ b/security/sandbox/mac/Sandbox.mm @@ -0,0 +1,802 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// The Mac sandbox module is a static library (a Library in moz.build terms) +// that can be linked into any binary (for example plugin-container or XUL). +// It must not have dependencies on any other Mozilla module. This is why, +// for example, it has its own OS X version detection code, rather than +// linking to nsCocoaFeatures.mm in XUL. + +#include "Sandbox.h" + +#include <CoreFoundation/CoreFoundation.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/sysctl.h> +#include <sys/types.h> + +#include <iostream> +#include <sstream> +#include <vector> + +#include "SandboxPolicyContent.h" +#include "SandboxPolicyGMP.h" +#include "SandboxPolicyRDD.h" +#include "SandboxPolicySocket.h" +#include "SandboxPolicyUtility.h" +#include "mozilla/Assertions.h" + +#include "mozilla/GeckoArgs.h" +#include "mozilla/ipc/UtilityProcessSandboxing.h" + +// Undocumented sandbox setup routines. +extern "C" int sandbox_init_with_parameters(const char* profile, uint64_t flags, + const char* const parameters[], char** errorbuf); +extern "C" void sandbox_free_error(char* errorbuf); +extern "C" int sandbox_check(pid_t pid, const char* operation, int type, ...); + +// Note about "major", "minor" and "bugfix" in the following code: +// +// The code decomposes an OS X version number into these components, and in +// doing so follows Apple's terminology in Gestalt.h. But this is very +// misleading, because in other contexts Apple uses the "minor" component of +// an OS X version number to indicate a "major" release (for example the "9" +// in OS X 10.9.5), and the "bugfix" component to indicate a "minor" release +// (for example the "5" in OS X 10.9.5). +class OSXVersion { + public: + static void Get(int32_t& aMajor, int32_t& aMinor); + + private: + static void GetSystemVersion(int32_t& aMajor, int32_t& aMinor, int32_t& aBugFix); + static bool mCached; + static int32_t mOSXVersionMajor; + static int32_t mOSXVersionMinor; +}; + +bool OSXVersion::mCached = false; +int32_t OSXVersion::mOSXVersionMajor; +int32_t OSXVersion::mOSXVersionMinor; + +void OSXVersion::Get(int32_t& aMajor, int32_t& aMinor) { + if (!mCached) { + int32_t major, minor, bugfix; + GetSystemVersion(major, minor, bugfix); + mOSXVersionMajor = major; + mOSXVersionMinor = minor; + mCached = true; + } + aMajor = mOSXVersionMajor; + aMinor = mOSXVersionMinor; +} + +void OSXVersion::GetSystemVersion(int32_t& aMajor, int32_t& aMinor, int32_t& aBugFix) { + SInt32 major = 0, minor = 0, bugfix = 0; + + CFURLRef url = CFURLCreateWithString( + kCFAllocatorDefault, CFSTR("file:///System/Library/CoreServices/SystemVersion.plist"), NULL); + CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, url); + CFReadStreamOpen(stream); + CFDictionaryRef sysVersionPlist = (CFDictionaryRef)CFPropertyListCreateWithStream( + kCFAllocatorDefault, stream, 0, kCFPropertyListImmutable, NULL, NULL); + CFReadStreamClose(stream); + CFRelease(stream); + CFRelease(url); + + CFStringRef versionString = + (CFStringRef)CFDictionaryGetValue(sysVersionPlist, CFSTR("ProductVersion")); + CFArrayRef versions = + CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, versionString, CFSTR(".")); + CFIndex count = CFArrayGetCount(versions); + if (count > 0) { + CFStringRef component = (CFStringRef)CFArrayGetValueAtIndex(versions, 0); + major = CFStringGetIntValue(component); + if (count > 1) { + component = (CFStringRef)CFArrayGetValueAtIndex(versions, 1); + minor = CFStringGetIntValue(component); + if (count > 2) { + component = (CFStringRef)CFArrayGetValueAtIndex(versions, 2); + bugfix = CFStringGetIntValue(component); + } + } + } + CFRelease(sysVersionPlist); + CFRelease(versions); + + if (major < 10) { + // If 'major' isn't what we expect, assume 10.6. + aMajor = 10; + aMinor = 6; + aBugFix = 0; + } else if ((major == 10) && (minor >= 16)) { + // Account for SystemVersionCompat.plist being used which is + // automatically used for builds using older SDK versions and + // results in 11.0 being reported as 10.16. Assume the compat + // version will increase in step with the correct version. + aMajor = 11; + aMinor = minor - 16; + aBugFix = bugfix; + } else { + aMajor = major; + aMinor = minor; + aBugFix = bugfix; + } +} + +bool GetRealPath(std::string& aOutputPath, const char* aInputPath) { + char* resolvedPath = realpath(aInputPath, nullptr); + if (resolvedPath == nullptr) { + return false; + } + + aOutputPath = resolvedPath; + free(resolvedPath); + + return !aOutputPath.empty(); +} + +/* + * Returns true if the process is running under Rosetta translation. Returns + * false if running natively or if an error was encountered. To be called + * before enabling the sandbox therefore not requiring the sysctl be allowed + * by the sandbox policy. We use the `sysctl.proc_translated` sysctl which is + * documented by Apple to be used for this purpose. + */ +bool ProcessIsRosettaTranslated() { + int ret = 0; + size_t size = sizeof(ret); + if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) { + if (errno != ENOENT) { + fprintf(stderr, "Failed to check for translation environment\n"); + } + return false; + } + return (ret == 1); +} + +void MacSandboxInfo::AppendAsParams(std::vector<std::string>& aParams) const { + this->AppendStartupParam(aParams); + this->AppendLoggingParam(aParams); + this->AppendAppPathParam(aParams); + + switch (this->type) { + case MacSandboxType_Content: + this->AppendLevelParam(aParams); + this->AppendAudioParam(aParams); + this->AppendWindowServerParam(aParams); + this->AppendReadPathParams(aParams); +#ifdef DEBUG + this->AppendDebugWriteDirParam(aParams); +#endif + break; + case MacSandboxType_RDD: + case MacSandboxType_Socket: + case MacSandboxType_Utility: + break; + case MacSandboxType_GMP: + this->AppendPluginPathParam(aParams); + this->AppendWindowServerParam(aParams); + this->AppendReadPathParams(aParams); + break; + default: + // Before supporting a new process type, add a case statement + // here to append any neccesary process-type-specific params. + MOZ_RELEASE_ASSERT(false); + break; + } +} + +void MacSandboxInfo::AppendStartupParam(std::vector<std::string>& aParams) const { + aParams.push_back("-sbStartup"); +} + +void MacSandboxInfo::AppendLoggingParam(std::vector<std::string>& aParams) const { + if (this->shouldLog) { + aParams.push_back("-sbLogging"); + } +} + +void MacSandboxInfo::AppendAppPathParam(std::vector<std::string>& aParams) const { + aParams.push_back("-sbAppPath"); + aParams.push_back(this->appPath); +} + +void MacSandboxInfo::AppendPluginPathParam(std::vector<std::string>& aParams) const { + aParams.push_back("-sbPluginPath"); + aParams.push_back(this->pluginPath); +} + +/* static */ +void MacSandboxInfo::AppendFileAccessParam(std::vector<std::string>& aParams, + bool aHasFilePrivileges) { + if (aHasFilePrivileges) { + aParams.push_back("-sbAllowFileAccess"); + } +} + +void MacSandboxInfo::AppendLevelParam(std::vector<std::string>& aParams) const { + std::ostringstream os; + os << this->level; + std::string levelString = os.str(); + aParams.push_back("-sbLevel"); + aParams.push_back(levelString); +} + +void MacSandboxInfo::AppendAudioParam(std::vector<std::string>& aParams) const { + if (this->hasAudio) { + aParams.push_back("-sbAllowAudio"); + } +} + +void MacSandboxInfo::AppendWindowServerParam(std::vector<std::string>& aParams) const { + if (this->hasWindowServer) { + aParams.push_back("-sbAllowWindowServer"); + } +} + +void MacSandboxInfo::AppendReadPathParams(std::vector<std::string>& aParams) const { + if (!this->testingReadPath1.empty()) { + aParams.push_back("-sbTestingReadPath"); + aParams.push_back(this->testingReadPath1.c_str()); + } + if (!this->testingReadPath2.empty()) { + aParams.push_back("-sbTestingReadPath"); + aParams.push_back(this->testingReadPath2.c_str()); + } + if (!this->testingReadPath3.empty()) { + aParams.push_back("-sbTestingReadPath"); + aParams.push_back(this->testingReadPath3.c_str()); + } + if (!this->testingReadPath4.empty()) { + aParams.push_back("-sbTestingReadPath"); + aParams.push_back(this->testingReadPath4.c_str()); + } +} + +#ifdef DEBUG +void MacSandboxInfo::AppendDebugWriteDirParam(std::vector<std::string>& aParams) const { + if (!this->debugWriteDir.empty()) { + aParams.push_back("-sbDebugWriteDir"); + aParams.push_back(this->debugWriteDir.c_str()); + } +} +#endif + +namespace mozilla { + +bool StartMacSandbox(MacSandboxInfo const& aInfo, std::string& aErrorMessage) { + std::vector<const char*> params; + std::string profile; + + // Use a combined version number to simplify version check logic + // in sandbox policies. For example, 10.14 becomes "1014". + int32_t major = 0, minor = 0; + OSXVersion::Get(major, minor); + MOZ_ASSERT(minor >= 0 && minor < 100); + std::string combinedVersion = std::to_string((major * 100) + minor); + + params.push_back("IS_ROSETTA_TRANSLATED"); + params.push_back(ProcessIsRosettaTranslated() ? "TRUE" : "FALSE"); + + // Used for the content process to access to parts of the cache dir. + std::string userCacheDir; + + if (aInfo.type == MacSandboxType_Utility) { + profile = const_cast<char*>(SandboxPolicyUtility); + + switch (aInfo.utilityKind) { + case ipc::SandboxingKind::GENERIC_UTILITY: + // Nothing to do here specifically + break; + + case ipc::SandboxingKind::UTILITY_AUDIO_DECODING_APPLE_MEDIA: { + profile.append(SandboxPolicyUtilityAudioDecoderAppleMediaAddend); + params.push_back("MAC_OS_VERSION"); + params.push_back(combinedVersion.c_str()); + } break; + + default: + MOZ_ASSERT(false, "Invalid SandboxingKind"); + break; + } + params.push_back("SHOULD_LOG"); + params.push_back(aInfo.shouldLog ? "TRUE" : "FALSE"); + params.push_back("APP_PATH"); + params.push_back(aInfo.appPath.c_str()); + if (!aInfo.crashServerPort.empty()) { + params.push_back("CRASH_PORT"); + params.push_back(aInfo.crashServerPort.c_str()); + } + } else if (aInfo.type == MacSandboxType_RDD) { + profile = const_cast<char*>(SandboxPolicyRDD); + params.push_back("SHOULD_LOG"); + params.push_back(aInfo.shouldLog ? "TRUE" : "FALSE"); + params.push_back("MAC_OS_VERSION"); + params.push_back(combinedVersion.c_str()); + params.push_back("APP_PATH"); + params.push_back(aInfo.appPath.c_str()); + params.push_back("HOME_PATH"); + params.push_back(getenv("HOME")); + if (!aInfo.crashServerPort.empty()) { + params.push_back("CRASH_PORT"); + params.push_back(aInfo.crashServerPort.c_str()); + } + } else if (aInfo.type == MacSandboxType_Socket) { + profile = const_cast<char*>(SandboxPolicySocket); + params.push_back("SHOULD_LOG"); + params.push_back(aInfo.shouldLog ? "TRUE" : "FALSE"); + params.push_back("APP_PATH"); + params.push_back(aInfo.appPath.c_str()); + if (!aInfo.crashServerPort.empty()) { + params.push_back("CRASH_PORT"); + params.push_back(aInfo.crashServerPort.c_str()); + } + params.push_back("HOME_PATH"); + params.push_back(getenv("HOME")); + } else if (aInfo.type == MacSandboxType_GMP) { + profile = const_cast<char*>(SandboxPolicyGMP); + params.push_back("SHOULD_LOG"); + params.push_back(aInfo.shouldLog ? "TRUE" : "FALSE"); + params.push_back("APP_PATH"); + params.push_back(aInfo.appPath.c_str()); + params.push_back("PLUGIN_PATH"); + params.push_back(aInfo.pluginPath.c_str()); + if (!aInfo.pluginBinaryPath.empty()) { + params.push_back("PLUGIN_BINARY_PATH"); + params.push_back(aInfo.pluginBinaryPath.c_str()); + } + params.push_back("HAS_WINDOW_SERVER"); + params.push_back(aInfo.hasWindowServer ? "TRUE" : "FALSE"); + if (!aInfo.crashServerPort.empty()) { + params.push_back("CRASH_PORT"); + params.push_back(aInfo.crashServerPort.c_str()); + } + if (!aInfo.testingReadPath1.empty()) { + params.push_back("TESTING_READ_PATH1"); + params.push_back(aInfo.testingReadPath1.c_str()); + } + if (!aInfo.testingReadPath2.empty()) { + params.push_back("TESTING_READ_PATH2"); + params.push_back(aInfo.testingReadPath2.c_str()); + } + } else if (aInfo.type == MacSandboxType_Content) { + MOZ_ASSERT(aInfo.level >= 1); + if (aInfo.level >= 1) { + profile = SandboxPolicyContent; + params.push_back("SHOULD_LOG"); + params.push_back(aInfo.shouldLog ? "TRUE" : "FALSE"); + params.push_back("SANDBOX_LEVEL_1"); + params.push_back(aInfo.level == 1 ? "TRUE" : "FALSE"); + params.push_back("SANDBOX_LEVEL_2"); + params.push_back(aInfo.level == 2 ? "TRUE" : "FALSE"); + params.push_back("SANDBOX_LEVEL_3"); + params.push_back(aInfo.level == 3 ? "TRUE" : "FALSE"); + params.push_back("MAC_OS_VERSION"); + params.push_back(combinedVersion.c_str()); + params.push_back("APP_PATH"); + params.push_back(aInfo.appPath.c_str()); + params.push_back("PROFILE_DIR"); + params.push_back(aInfo.profileDir.c_str()); + params.push_back("HOME_PATH"); + params.push_back(getenv("HOME")); + params.push_back("HAS_SANDBOXED_PROFILE"); + params.push_back(aInfo.hasSandboxedProfile ? "TRUE" : "FALSE"); + params.push_back("HAS_WINDOW_SERVER"); + params.push_back(aInfo.hasWindowServer ? "TRUE" : "FALSE"); + if (!aInfo.crashServerPort.empty()) { + params.push_back("CRASH_PORT"); + params.push_back(aInfo.crashServerPort.c_str()); + } + + params.push_back("DARWIN_USER_CACHE_DIR"); + char confStrBuf[PATH_MAX]; + if (!confstr(_CS_DARWIN_USER_CACHE_DIR, confStrBuf, sizeof(confStrBuf))) { + return false; + } + if (!GetRealPath(userCacheDir, confStrBuf)) { + return false; + } + params.push_back(userCacheDir.c_str()); + + if (!aInfo.testingReadPath1.empty()) { + params.push_back("TESTING_READ_PATH1"); + params.push_back(aInfo.testingReadPath1.c_str()); + } + if (!aInfo.testingReadPath2.empty()) { + params.push_back("TESTING_READ_PATH2"); + params.push_back(aInfo.testingReadPath2.c_str()); + } + if (!aInfo.testingReadPath3.empty()) { + params.push_back("TESTING_READ_PATH3"); + params.push_back(aInfo.testingReadPath3.c_str()); + } + if (!aInfo.testingReadPath4.empty()) { + params.push_back("TESTING_READ_PATH4"); + params.push_back(aInfo.testingReadPath4.c_str()); + } +#ifdef DEBUG + if (!aInfo.debugWriteDir.empty()) { + params.push_back("DEBUG_WRITE_DIR"); + params.push_back(aInfo.debugWriteDir.c_str()); + } +#endif // DEBUG + + if (aInfo.hasFilePrivileges) { + profile.append(SandboxPolicyContentFileAddend); + } + if (aInfo.hasAudio) { + profile.append(SandboxPolicyContentAudioAddend); + } + } else { + fprintf(stderr, "Content sandbox disabled due to sandbox level setting\n"); + return false; + } + } else { + char* msg = NULL; + asprintf(&msg, "Unexpected sandbox type %u", aInfo.type); + if (msg) { + aErrorMessage.assign(msg); + free(msg); + } + return false; + } + + if (profile.empty()) { + fprintf(stderr, "Out of memory in StartMacSandbox()!\n"); + return false; + } + +// In order to avoid relying on any other Mozilla modules (as described at the +// top of this file), we use our own #define instead of the existing MOZ_LOG +// infrastructure. This can be used by developers to debug the macOS sandbox +// policy. +#define MAC_SANDBOX_PRINT_POLICY 0 +#if MAC_SANDBOX_PRINT_POLICY + printf("Sandbox params for PID %d:\n", getpid()); + for (size_t i = 0; i < params.size() / 2; i++) { + printf(" %s = %s\n", params[i * 2], params[(i * 2) + 1]); + } + printf("Sandbox profile:\n%s\n", profile.c_str()); +#endif + + // The parameters array is null terminated. + params.push_back(nullptr); + + char* errorbuf = NULL; + int rv = sandbox_init_with_parameters(profile.c_str(), 0, params.data(), &errorbuf); + if (rv) { + if (errorbuf) { + char* msg = NULL; + asprintf(&msg, "sandbox_init() failed with error \"%s\"", errorbuf); + if (msg) { + aErrorMessage.assign(msg); + free(msg); + } + fprintf(stderr, "profile: %s\n", profile.c_str()); + sandbox_free_error(errorbuf); + } + } + if (rv) { + return false; + } + + return true; +} + +/* + * Fill |aInfo| with content sandbox params parsed from the provided + * command line arguments. Return false if any sandbox parameters needed + * for early startup of the sandbox are not present in the arguments. + */ +bool GetContentSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo) { + // Ensure we find these paramaters in the command + // line arguments. Return false if any are missing. + bool foundSandboxLevel = false; + bool foundValidSandboxLevel = false; + bool foundAppPath = false; + + // Read access directories used in testing + int nTestingReadPaths = 0; + std::string testingReadPaths[MAX_CONTENT_TESTING_READ_PATHS] = {}; + + // Collect sandbox params from CLI arguments + for (int i = 0; i < aArgc; i++) { + if ((strcmp(aArgv[i], "-sbLevel") == 0) && (i + 1 < aArgc)) { + std::stringstream ss(aArgv[i + 1]); + int level = 0; + ss >> level; + foundSandboxLevel = true; + aInfo.level = level; + foundValidSandboxLevel = level > 0 && level <= 3 ? true : false; + if (!foundValidSandboxLevel) { + break; + } + i++; + continue; + } + + if (strcmp(aArgv[i], "-sbLogging") == 0) { + aInfo.shouldLog = true; + continue; + } + + if (strcmp(aArgv[i], "-sbAllowFileAccess") == 0) { + aInfo.hasFilePrivileges = true; + continue; + } + + if (strcmp(aArgv[i], "-sbAllowAudio") == 0) { + aInfo.hasAudio = true; + continue; + } + + if (strcmp(aArgv[i], "-sbAllowWindowServer") == 0) { + aInfo.hasWindowServer = true; + continue; + } + + if ((strcmp(aArgv[i], "-sbAppPath") == 0) && (i + 1 < aArgc)) { + foundAppPath = true; + aInfo.appPath.assign(aArgv[i + 1]); + i++; + continue; + } + + if ((strcmp(aArgv[i], "-sbTestingReadPath") == 0) && (i + 1 < aArgc)) { + if (nTestingReadPaths >= MAX_CONTENT_TESTING_READ_PATHS) { + MOZ_CRASH("Too many content process -sbTestingReadPath arguments"); + } + testingReadPaths[nTestingReadPaths] = aArgv[i + 1]; + nTestingReadPaths++; + i++; + continue; + } + + if ((strcmp(aArgv[i], "-profile") == 0) && (i + 1 < aArgc)) { + aInfo.hasSandboxedProfile = true; + aInfo.profileDir.assign(aArgv[i + 1]); + i++; + continue; + } + +#ifdef DEBUG + if ((strcmp(aArgv[i], "-sbDebugWriteDir") == 0) && (i + 1 < aArgc)) { + aInfo.debugWriteDir.assign(aArgv[i + 1]); + i++; + continue; + } +#endif // DEBUG + + // Handle crash server positional argument + if (strstr(aArgv[i], "gecko-crash-server-pipe") != NULL) { + aInfo.crashServerPort.assign(aArgv[i]); + continue; + } + } + + if (!foundSandboxLevel) { + fprintf(stderr, "Content sandbox disabled due to " + "missing sandbox CLI level parameter.\n"); + return false; + } + + if (!foundValidSandboxLevel) { + fprintf(stderr, + "Content sandbox disabled due to invalid" + "sandbox level (%d)\n", + aInfo.level); + return false; + } + + if (!foundAppPath) { + fprintf(stderr, "Content sandbox disabled due to " + "missing sandbox CLI app path parameter.\n"); + return false; + } + + aInfo.testingReadPath1 = testingReadPaths[0]; + aInfo.testingReadPath2 = testingReadPaths[1]; + aInfo.testingReadPath3 = testingReadPaths[2]; + aInfo.testingReadPath4 = testingReadPaths[3]; + + return true; +} + +bool GetUtilitySandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo, + bool aSandboxingKindRequired = true) { + // Ensure we find these paramaters in the command + // line arguments. Return false if any are missing. + bool foundAppPath = false; + + // Collect sandbox params from CLI arguments + for (int i = 0; i < aArgc; i++) { + if (strcmp(aArgv[i], "-sbLogging") == 0) { + aInfo.shouldLog = true; + continue; + } + + if ((strcmp(aArgv[i], "-sbAppPath") == 0) && (i + 1 < aArgc)) { + foundAppPath = true; + aInfo.appPath.assign(aArgv[i + 1]); + i++; + continue; + } + + // Handle crash server positional argument + if (strstr(aArgv[i], "gecko-crash-server-pipe") != NULL) { + aInfo.crashServerPort.assign(aArgv[i]); + continue; + } + } + + if (aSandboxingKindRequired) { + Maybe<uint64_t> sandboxingKind = + geckoargs::sSandboxingKind.Get(aArgc, aArgv, CheckArgFlag::None); + if (sandboxingKind.isNothing()) { + fprintf(stderr, "Utility sandbox requires a sandboxingKind"); + return false; + } + aInfo.utilityKind = (ipc::SandboxingKind)*sandboxingKind; + } + + if (!foundAppPath) { + fprintf(stderr, "Utility sandbox disabled due to " + "missing sandbox CLI app path parameter.\n"); + return false; + } + + return true; +} + +bool GetSocketSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo) { + return GetUtilitySandboxParamsFromArgs(aArgc, aArgv, aInfo, false); +} + +bool GetPluginSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo) { + // Ensure we find these paramaters in the command + // line arguments. Return false if any are missing. + bool foundAppPath = false; + bool foundPluginPath = false; + + // Read access directories used in testing + int nTestingReadPaths = 0; + std::string testingReadPaths[MAX_GMP_TESTING_READ_PATHS] = {}; + + // Collect sandbox params from CLI arguments + for (int i = 0; i < aArgc; i++) { + if (strcmp(aArgv[i], "-sbLogging") == 0) { + aInfo.shouldLog = true; + continue; + } + + if ((strcmp(aArgv[i], "-sbAppPath") == 0) && (i + 1 < aArgc)) { + foundAppPath = true; + aInfo.appPath.assign(aArgv[i + 1]); + i++; + continue; + } + + if ((strcmp(aArgv[i], "-sbPluginPath") == 0) && (i + 1 < aArgc)) { + foundPluginPath = true; + aInfo.pluginPath.assign(aArgv[i + 1]); + i++; + continue; + } + + if (strcmp(aArgv[i], "-sbAllowWindowServer") == 0) { + aInfo.hasWindowServer = true; + continue; + } + + if ((strcmp(aArgv[i], "-sbTestingReadPath") == 0) && (i + 1 < aArgc)) { + if (nTestingReadPaths >= MAX_GMP_TESTING_READ_PATHS) { + MOZ_CRASH("Too many GMP process -sbTestingReadPath arguments"); + } + testingReadPaths[nTestingReadPaths] = aArgv[i + 1]; + nTestingReadPaths++; + i++; + continue; + } + + // Handle crash server positional argument + if (strstr(aArgv[i], "gecko-crash-server-pipe") != NULL) { + aInfo.crashServerPort.assign(aArgv[i]); + continue; + } + } + + if (!foundPluginPath) { + fprintf(stderr, "GMP sandbox disabled due to " + "missing sandbox CLI plugin path parameter.\n"); + return false; + } + + if (!foundAppPath) { + fprintf(stderr, "GMP sandbox disabled due to " + "missing sandbox CLI app path parameter.\n"); + return false; + } + + aInfo.testingReadPath1 = testingReadPaths[0]; + aInfo.testingReadPath2 = testingReadPaths[1]; + + return true; +} + +bool GetRDDSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo) { + return GetUtilitySandboxParamsFromArgs(aArgc, aArgv, aInfo, false); +} + +/* + * Returns true if no errors were encountered or if early sandbox startup is + * not enabled for this process. Returns false if an error was encountered. + */ +bool StartMacSandboxIfEnabled(const MacSandboxType aSandboxType, int aArgc, char** aArgv, + std::string& aErrorMessage) { + bool earlyStartupEnabled = false; + + // Check for the -sbStartup CLI parameter which + // indicates we should start the sandbox now. + for (int i = 0; i < aArgc; i++) { + if (strcmp(aArgv[i], "-sbStartup") == 0) { + earlyStartupEnabled = true; + break; + } + } + + // The sandbox will be started later when/if parent + // sends the sandbox startup message. Return true + // indicating no errors occurred. + if (!earlyStartupEnabled) { + return true; + } + + MacSandboxInfo info; + info.type = aSandboxType; + + // For now, early start is only implemented + // for content and utility sandbox types. + switch (aSandboxType) { + case MacSandboxType_Content: + if (!GetContentSandboxParamsFromArgs(aArgc, aArgv, info)) { + return false; + } + break; + case MacSandboxType_GMP: + if (!GetPluginSandboxParamsFromArgs(aArgc, aArgv, info)) { + return false; + } + break; + case MacSandboxType_RDD: + if (!GetRDDSandboxParamsFromArgs(aArgc, aArgv, info)) { + return false; + } + break; + case MacSandboxType_Socket: + if (!GetSocketSandboxParamsFromArgs(aArgc, aArgv, info)) { + return false; + } + break; + case MacSandboxType_Utility: + if (!GetUtilitySandboxParamsFromArgs(aArgc, aArgv, info)) { + return false; + } + break; + default: + MOZ_RELEASE_ASSERT(false); + break; + } + + return StartMacSandbox(info, aErrorMessage); +} + +bool IsMacSandboxStarted() { return sandbox_check(getpid(), NULL, 0) == 1; } + +#ifdef DEBUG +// sandbox_check returns 1 if the specified process is sandboxed +void AssertMacSandboxEnabled() { MOZ_ASSERT(sandbox_check(getpid(), NULL, 0) == 1); } +#endif /* DEBUG */ + +} // namespace mozilla |