diff options
Diffstat (limited to 'security/sandbox/mac')
-rw-r--r-- | security/sandbox/mac/Sandbox.h | 90 | ||||
-rw-r--r-- | security/sandbox/mac/Sandbox.mm | 823 | ||||
-rw-r--r-- | security/sandbox/mac/SandboxPolicyContent.h | 374 | ||||
-rw-r--r-- | security/sandbox/mac/SandboxPolicyGMP.h | 82 | ||||
-rw-r--r-- | security/sandbox/mac/SandboxPolicyRDD.h | 184 | ||||
-rw-r--r-- | security/sandbox/mac/SandboxPolicySocket.h | 141 | ||||
-rw-r--r-- | security/sandbox/mac/SandboxPolicyUtility.h | 70 | ||||
-rw-r--r-- | security/sandbox/mac/moz.build | 19 |
8 files changed, 1783 insertions, 0 deletions
diff --git a/security/sandbox/mac/Sandbox.h b/security/sandbox/mac/Sandbox.h new file mode 100644 index 0000000000..3500182292 --- /dev/null +++ b/security/sandbox/mac/Sandbox.h @@ -0,0 +1,90 @@ +/* -*- 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/. */ + +#ifndef mozilla_Sandbox_h +#define mozilla_Sandbox_h + +#include <string> +#include "mozilla/ipc/UtilityProcessSandboxing.h" + +enum MacSandboxType { + MacSandboxType_Default = 0, + MacSandboxType_Content, + MacSandboxType_GMP, + MacSandboxType_RDD, + MacSandboxType_Socket, + MacSandboxType_Utility, + MacSandboxType_Invalid +}; + +typedef struct _MacSandboxInfo { + _MacSandboxInfo() + : type(MacSandboxType_Default), + level(0), + hasFilePrivileges(false), + hasSandboxedProfile(false), + hasAudio(false), + hasWindowServer(false), + shouldLog(false) {} + _MacSandboxInfo(const struct _MacSandboxInfo& other) = default; + + void AppendAsParams(std::vector<std::string>& aParams) const; + static void AppendFileAccessParam(std::vector<std::string>& aParams, + bool aHasFilePrivileges); + + private: + void AppendStartupParam(std::vector<std::string>& aParams) const; + void AppendLoggingParam(std::vector<std::string>& aParams) const; + void AppendAppPathParam(std::vector<std::string>& aParams) const; + void AppendPluginPathParam(std::vector<std::string>& aParams) const; + void AppendLevelParam(std::vector<std::string>& aParams) const; + void AppendAudioParam(std::vector<std::string>& aParams) const; + void AppendWindowServerParam(std::vector<std::string>& aParams) const; + void AppendReadPathParams(std::vector<std::string>& aParams) const; +#ifdef DEBUG + void AppendDebugWriteDirParam(std::vector<std::string>& aParams) const; +#endif + + public: + MacSandboxType type; + mozilla::ipc::SandboxingKind utilityKind; + int32_t level; + bool hasFilePrivileges; + bool hasSandboxedProfile; + bool hasAudio; + bool hasWindowServer; + + std::string appPath; + std::string appBinaryPath; + std::string appDir; + std::string profileDir; + std::string debugWriteDir; + + std::string pluginPath; + std::string pluginBinaryPath; + + std::string testingReadPath1; + std::string testingReadPath2; + std::string testingReadPath3; + std::string testingReadPath4; + + std::string crashServerPort; + + bool shouldLog; +} MacSandboxInfo; + +namespace mozilla { + +bool StartMacSandbox(MacSandboxInfo const& aInfo, std::string& aErrorMessage); +bool StartMacSandboxIfEnabled(MacSandboxType aSandboxType, int aArgc, + char** aArgv, std::string& aErrorMessage); +bool IsMacSandboxStarted(); +#ifdef DEBUG +void AssertMacSandboxEnabled(); +#endif /* DEBUG */ + +} // namespace mozilla + +#endif // mozilla_Sandbox_h diff --git a/security/sandbox/mac/Sandbox.mm b/security/sandbox/mac/Sandbox.mm new file mode 100644 index 0000000000..2c9972a8fa --- /dev/null +++ b/security/sandbox/mac/Sandbox.mm @@ -0,0 +1,823 @@ +/* -*- 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 diff --git a/security/sandbox/mac/SandboxPolicyContent.h b/security/sandbox/mac/SandboxPolicyContent.h new file mode 100644 index 0000000000..3f49f684d6 --- /dev/null +++ b/security/sandbox/mac/SandboxPolicyContent.h @@ -0,0 +1,374 @@ +/* -*- 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/. */ + +#ifndef mozilla_SandboxPolicyContent_h +#define mozilla_SandboxPolicyContent_h + +#define MAX_CONTENT_TESTING_READ_PATHS 4 + +namespace mozilla { + +static const char SandboxPolicyContent[] = R"SANDBOX_LITERAL( + (version 1) + + (define should-log (param "SHOULD_LOG")) + (define sandbox-level-1 (param "SANDBOX_LEVEL_1")) + (define sandbox-level-2 (param "SANDBOX_LEVEL_2")) + (define sandbox-level-3 (param "SANDBOX_LEVEL_3")) + (define macosVersion (string->number (param "MAC_OS_VERSION"))) + (define appPath (param "APP_PATH")) + (define hasProfileDir (param "HAS_SANDBOXED_PROFILE")) + (define profileDir (param "PROFILE_DIR")) + (define hasWindowServer (param "HAS_WINDOW_SERVER")) + (define home-path (param "HOME_PATH")) + (define debugWriteDir (param "DEBUG_WRITE_DIR")) + (define userCacheDir (param "DARWIN_USER_CACHE_DIR")) + (define testingReadPath1 (param "TESTING_READ_PATH1")) + (define testingReadPath2 (param "TESTING_READ_PATH2")) + (define testingReadPath3 (param "TESTING_READ_PATH3")) + (define testingReadPath4 (param "TESTING_READ_PATH4")) + (define crashPort (param "CRASH_PORT")) + (define isRosettaTranslated (param "IS_ROSETTA_TRANSLATED")) + + (define (moz-deny feature) + (if (string=? should-log "TRUE") + (deny feature) + (deny feature (with no-log)))) + + (moz-deny default) + ; These are not included in (deny default) + (moz-deny process-info*) + (moz-deny nvram*) + (moz-deny iokit-get-properties) + (moz-deny file-map-executable) + + (if (string=? should-log "TRUE") + (debug deny)) + + (if (string=? isRosettaTranslated "TRUE") + (allow file-map-executable (subpath "/private/var/db/oah"))) + + (allow file-map-executable file-read* + (subpath "/System") + (subpath "/usr/lib") + (subpath "/Library/GPUBundles") + (subpath appPath)) + + ; Allow read access to standard system paths. + (allow file-read* + (require-all (file-mode #o0004) + (require-any + (subpath "/Library/Filesystems/NetFSPlugins") + (subpath "/usr/share")))) + + ; For stat and symlink resolution + (allow file-read-metadata (subpath "/")) + + ; Timezone + (allow file-read* + (subpath "/private/var/db/timezone") + (subpath "/usr/share/zoneinfo") + (subpath "/usr/share/zoneinfo.default") + (literal "/private/etc/localtime")) + + ; Allow read access to standard special files. + (allow file-read* + (literal "/dev/autofs_nowait") + (literal "/dev/random") + (literal "/dev/urandom")) + + (allow file-read* + file-write-data + (literal "/dev/null") + (literal "/dev/zero")) + + (allow file-read* + file-write-data + file-ioctl + (literal "/dev/dtracehelper")) + + ; Needed for things like getpriority()/setpriority() + (allow process-info-pidinfo process-info-setcontrol (target self)) + + (allow sysctl-read + (sysctl-name-regex #"^sysctl\.") + (sysctl-name "kern.ostype") + (sysctl-name "kern.osversion") + (sysctl-name "kern.osrelease") + (sysctl-name "kern.version") + (sysctl-name "kern.tcsm_available") + (sysctl-name "kern.tcsm_enable") + ; TODO: remove "kern.hostname". Without it the tests hang, but the hostname + ; is arguably sensitive information, so we should see what can be done about + ; removing it. + (sysctl-name "kern.hostname") + (sysctl-name "hw.machine") + (sysctl-name "hw.memsize") + (sysctl-name "hw.model") + (sysctl-name "hw.ncpu") + (sysctl-name "hw.activecpu") + (sysctl-name "hw.byteorder") + (sysctl-name "hw.pagesize_compat") + (sysctl-name "hw.logicalcpu") + (sysctl-name "hw.logicalcpu_max") + (sysctl-name "hw.perflevel0.logicalcpu_max") + (sysctl-name "hw.perflevel1.logicalcpu_max") + (sysctl-name "hw.physicalcpu_max") + (sysctl-name "hw.busfrequency_compat") + (sysctl-name "hw.busfrequency_max") + (sysctl-name "hw.cpufrequency") + (sysctl-name "hw.cpufrequency_compat") + (sysctl-name "hw.cpufrequency_max") + (sysctl-name "hw.l2cachesize") + (sysctl-name "hw.l3cachesize") + (sysctl-name "hw.cachelinesize") + (sysctl-name "hw.cachelinesize_compat") + (sysctl-name "hw.tbfrequency_compat") + (sysctl-name "hw.vectorunit") + (sysctl-name "hw.optional.sse2") + (sysctl-name "hw.optional.sse3") + (sysctl-name "hw.optional.sse4_1") + (sysctl-name "hw.optional.sse4_2") + (sysctl-name "hw.optional.avx1_0") + (sysctl-name "hw.optional.avx2_0") + (sysctl-name "hw.optional.avx512f") + (sysctl-name "machdep.cpu.vendor") + (sysctl-name "machdep.cpu.family") + (sysctl-name "machdep.cpu.model") + (sysctl-name "machdep.cpu.stepping") + (sysctl-name "debug.intel.gstLevelGST") + (sysctl-name "debug.intel.gstLoaderControl")) + (allow sysctl-write + (sysctl-name "kern.tcsm_enable")) + + (define (home-regex home-relative-regex) + (regex (string-append "^" (regex-quote home-path) home-relative-regex))) + (define (home-subpath home-relative-subpath) + (subpath (string-append home-path home-relative-subpath))) + (define (home-literal home-relative-literal) + (literal (string-append home-path home-relative-literal))) + + (define (profile-subpath profile-relative-subpath) + (subpath (string-append profileDir profile-relative-subpath))) + + (define (allow-shared-list domain) + (allow file-read* + (home-regex (string-append "/Library/Preferences/" (regex-quote domain))))) + + (allow ipc-posix-shm-read-data ipc-posix-shm-write-data + (ipc-posix-name-regex #"^CFPBS:")) + + (allow signal (target self)) + (if (string? crashPort) + (allow mach-lookup (global-name crashPort))) + (if (string=? hasWindowServer "TRUE") + (allow mach-lookup (global-name "com.apple.windowserver.active"))) + (allow mach-lookup + (global-name "com.apple.system.opendirectoryd.libinfo") + (global-name "com.apple.CoreServices.coreservicesd") + (global-name "com.apple.coreservices.launchservicesd") + (global-name "com.apple.lsd.mapdb")) + + (allow mach-lookup + ; bug 1392988 + (xpc-service-name "com.apple.coremedia.videodecoder") + (xpc-service-name "com.apple.coremedia.videoencoder")) + + (if (>= macosVersion 1100) + (allow mach-lookup + ; bug 1655655 + (global-name "com.apple.trustd.agent"))) + + (allow iokit-open + (iokit-user-client-class "IOHIDParamUserClient")) + + ; Only supported on macOS 10.10+ + (if (defined? 'iokit-get-properties) + (allow iokit-get-properties + (iokit-property "board-id") + (iokit-property "class-code") + (iokit-property "vendor-id") + (iokit-property "device-id") + (iokit-property "IODVDBundleName") + (iokit-property "IOGLBundleName") + (iokit-property "IOGVACodec") + (iokit-property "IOGVAHEVCDecode") + (iokit-property "IOGVAHEVCEncode") + (iokit-property "IOGVAXDecode") + (iokit-property "IOPCITunnelled") + (iokit-property "IOVARendererID") + (iokit-property "MetalPluginName") + (iokit-property "MetalPluginClassName"))) + + ; depending on systems, the 1st, 2nd or both rules are necessary + (allow user-preference-read (preference-domain "com.apple.HIToolbox")) + (allow file-read-data (literal "/Library/Preferences/com.apple.HIToolbox.plist")) + + (allow user-preference-read (preference-domain "com.apple.ATS")) + + ; Needed for some global preferences (such as scrolling behavior) + (allow file-read-data + (literal "/Library/Preferences/.GlobalPreferences.plist") + (home-literal "/Library/Preferences/.GlobalPreferences.plist") + (home-regex #"/Library/Preferences/ByHost/\.GlobalPreferences.*") + (home-literal "/Library/Preferences/com.apple.universalaccess.plist")) + (allow mach-lookup + (global-name "com.apple.cfprefsd.agent") + (global-name "com.apple.cfprefsd.daemon")) + (allow ipc-posix-shm-read-data + (ipc-posix-name-regex #"^apple\.cfprefs\..*")) + + (allow file-read* + (subpath "/Library/ColorSync/Profiles") + (subpath "/Library/Spelling") + (literal "/") + (literal "/private/tmp") + (literal "/private/var/tmp") + (home-literal "/.CFUserTextEncoding") + (home-literal "/Library/Preferences/com.apple.DownloadAssessment.plist") + (home-subpath "/Library/Colors") + (home-subpath "/Library/ColorSync/Profiles") + (home-subpath "/Library/Keyboard Layouts") + (home-subpath "/Library/Input Methods") + (home-subpath "/Library/Spelling")) + + (when testingReadPath1 + (allow file-read* file-map-executable (subpath testingReadPath1))) + (when testingReadPath2 + (allow file-read* file-map-executable (subpath testingReadPath2))) + (when testingReadPath3 + (allow file-read* file-map-executable (subpath testingReadPath3))) + (when testingReadPath4 + (allow file-read* file-map-executable (subpath testingReadPath4))) + + ; bug 1692220 + (when userCacheDir + (allow file-read* + (subpath (string-append userCacheDir "/com.apple.FontRegistry")))) + + ; bug 1303987 + (if (string? debugWriteDir) + (begin + (allow file-write-data (subpath debugWriteDir)) + (allow file-write-create + (require-all + (subpath debugWriteDir) + (vnode-type REGULAR-FILE))))) + + (allow-shared-list "org.mozilla.plugincontainer") + +; Per-user and system-wide Extensions dir + (allow file-read* + (home-regex "/Library/Application Support/[^/]+/Extensions/") + (regex "^/Library/Application Support/[^/]+/Extensions/")) + +; The following rules impose file access restrictions which get +; more restrictive in higher levels. When file-origin-specific +; content processes are used for file:// origin browsing, the +; global file-read* permission should be removed from each level. + +; level 1: global read access permitted, no global write access + (if (string=? sandbox-level-1 "TRUE") (allow file-read*)) + +; level 2: global read access permitted, no global write access, +; no read/write access to ~/Library, +; no read/write access to $PROFILE, +; read access permitted to $PROFILE/{extensions,chrome} + (if (string=? sandbox-level-2 "TRUE") + (begin + ; bug 1201935 + (allow file-read* (home-subpath "/Library/Caches/TemporaryItems")) + (if (string=? hasProfileDir "TRUE") + ; we have a profile dir + (allow file-read* (require-all + (require-not (home-subpath "/Library")) + (require-not (subpath profileDir)))) + ; we don't have a profile dir + (allow file-read* (require-not (home-subpath "/Library")))))) + + ; level 3: Does not have any of it's own rules. The global rules provide: + ; no global read/write access, + ; read access permitted to $PROFILE/{extensions,chrome} + + (if (string=? hasProfileDir "TRUE") + ; we have a profile dir + (allow file-read* + (profile-subpath "/extensions") + (profile-subpath "/chrome"))) + +; accelerated graphics + (allow user-preference-read (preference-domain "com.apple.opengl")) + (allow user-preference-read (preference-domain "com.nvidia.OpenGL")) + (allow mach-lookup + (global-name "com.apple.cvmsServ") + (global-name "com.apple.MTLCompilerService")) + (allow iokit-open + (iokit-connection "IOAccelerator") + (iokit-user-client-class "IOAccelerationUserClient") + (iokit-user-client-class "IOSurfaceRootUserClient") + (iokit-user-client-class "IOSurfaceSendRight") + (iokit-user-client-class "IOFramebufferSharedUserClient") + (iokit-user-client-class "AGPMClient") + (iokit-user-client-class "AppleGraphicsControlClient")) + +; bug 1153809 + (allow iokit-open + (iokit-user-client-class "NVDVDContextTesla") + (iokit-user-client-class "Gen6DVDContext")) + + ; Fonts + (allow file-read* + (subpath "/Library/Fonts") + (subpath "/Library/Application Support/Apple/Fonts") + (home-subpath "/Library/Fonts") + ; Allow read access to paths allowed via sandbox extensions. + ; This is needed for fonts in non-standard locations normally + ; due to third party font managers. The extensions are + ; automatically issued by the font server in response to font + ; API calls. + (extension "com.apple.app-sandbox.read")) + ; Fonts may continue to work without explicitly allowing these + ; services because, at present, connections are made to the services + ; before the sandbox is enabled as a side-effect of some API calls. + (allow mach-lookup + (global-name "com.apple.fonts") + (global-name "com.apple.FontObjectsServer")) + + ; bug 1565575 + (allow mach-lookup (global-name "com.apple.audio.AudioComponentRegistrar")) +)SANDBOX_LITERAL"; + +// These are additional rules that are added to the content process rules for +// file content processes. +static const char SandboxPolicyContentFileAddend[] = R"SANDBOX_LITERAL( + ; This process has blanket file read privileges + (allow file-read*) + + ; File content processes need access to iconservices to draw file icons in + ; directory listings + (allow mach-lookup (global-name "com.apple.iconservices")) +)SANDBOX_LITERAL"; + +// These are additional rules that are added to the content process rules when +// audio remoting is not enabled. (Once audio remoting is always used these +// will be deleted.) +static const char SandboxPolicyContentAudioAddend[] = R"SANDBOX_LITERAL( + (allow ipc-posix-shm-read* ipc-posix-shm-write-data + (ipc-posix-name-regex #"^AudioIO")) + + (allow mach-lookup + (global-name "com.apple.audio.coreaudiod") + (global-name "com.apple.audio.audiohald")) + + (allow iokit-open (iokit-user-client-class "IOAudioEngineUserClient")) + + (allow file-read* (subpath "/Library/Audio/Plug-Ins")) + + (allow device-microphone) +)SANDBOX_LITERAL"; + +} // namespace mozilla + +#endif // mozilla_SandboxPolicyContent_h diff --git a/security/sandbox/mac/SandboxPolicyGMP.h b/security/sandbox/mac/SandboxPolicyGMP.h new file mode 100644 index 0000000000..fd50858718 --- /dev/null +++ b/security/sandbox/mac/SandboxPolicyGMP.h @@ -0,0 +1,82 @@ +/* -*- 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/. */ + +#ifndef mozilla_SandboxPolicyGMP_h +#define mozilla_SandboxPolicyGMP_h + +#define MAX_GMP_TESTING_READ_PATHS 2 + +namespace mozilla { + +static const char SandboxPolicyGMP[] = R"SANDBOX_LITERAL( + (version 1) + + (define should-log (param "SHOULD_LOG")) + (define app-path (param "APP_PATH")) + (define plugin-path (param "PLUGIN_PATH")) + (define plugin-binary-path (param "PLUGIN_BINARY_PATH")) + (define crashPort (param "CRASH_PORT")) + (define hasWindowServer (param "HAS_WINDOW_SERVER")) + (define testingReadPath1 (param "TESTING_READ_PATH1")) + (define testingReadPath2 (param "TESTING_READ_PATH2")) + (define isRosettaTranslated (param "IS_ROSETTA_TRANSLATED")) + + (define (moz-deny feature) + (if (string=? should-log "TRUE") + (deny feature) + (deny feature (with no-log)))) + + (moz-deny default) + ; These are not included in (deny default) + (moz-deny process-info*) + (moz-deny nvram*) + (moz-deny file-map-executable) + (allow process-info-pidinfo (target self)) + + ; Needed for things like getpriority()/setpriority()/pthread_setname() + (allow process-info-pidinfo process-info-setcontrol (target self)) + + (if (string=? isRosettaTranslated "TRUE") + (allow file-map-executable (subpath "/private/var/db/oah"))) + + (allow file-map-executable file-read* + (subpath "/System/Library") + (subpath "/usr/lib") + (subpath plugin-path) + (subpath app-path)) + + (when plugin-binary-path + (allow file-read* file-map-executable (subpath plugin-binary-path))) + (when testingReadPath1 + (allow file-read* file-map-executable (subpath testingReadPath1))) + (when testingReadPath2 + (allow file-read* file-map-executable (subpath testingReadPath2))) + + (if (string? crashPort) + (allow mach-lookup (global-name crashPort))) + + (allow signal (target self)) + (allow sysctl-read) + (allow iokit-open (iokit-user-client-class "IOHIDParamUserClient")) + (allow file-read* + (literal "/etc") + (literal "/dev/random") + (literal "/dev/urandom") + (literal "/usr/share/icu/icudt51l.dat")) + + ; Timezone + (allow file-read* + (subpath "/private/var/db/timezone") + (subpath "/usr/share/zoneinfo") + (subpath "/usr/share/zoneinfo.default") + (literal "/private/etc/localtime")) + + (if (string=? hasWindowServer "TRUE") + (allow mach-lookup (global-name "com.apple.windowserver.active"))) +)SANDBOX_LITERAL"; + +} // namespace mozilla + +#endif // mozilla_SandboxPolicyGMP_h diff --git a/security/sandbox/mac/SandboxPolicyRDD.h b/security/sandbox/mac/SandboxPolicyRDD.h new file mode 100644 index 0000000000..ddce1f4ecc --- /dev/null +++ b/security/sandbox/mac/SandboxPolicyRDD.h @@ -0,0 +1,184 @@ +/* -*- 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/. */ + +#ifndef mozilla_SandboxPolicyRDD_h +#define mozilla_SandboxPolicyRDD_h + +namespace mozilla { + +static const char SandboxPolicyRDD[] = R"SANDBOX_LITERAL( + (version 1) + + (define should-log (param "SHOULD_LOG")) + (define macosVersion (string->number (param "MAC_OS_VERSION"))) + (define app-path (param "APP_PATH")) + (define home-path (param "HOME_PATH")) + (define crashPort (param "CRASH_PORT")) + (define isRosettaTranslated (param "IS_ROSETTA_TRANSLATED")) + + (define (moz-deny feature) + (if (string=? should-log "TRUE") + (deny feature) + (deny feature (with no-log)))) + + (moz-deny default) + ; These are not included in (deny default) + (moz-deny process-info*) + (moz-deny nvram*) + (moz-deny iokit-get-properties) + (moz-deny file-map-executable) + + ; Needed for things like getpriority()/setpriority()/pthread_setname() + (allow process-info-pidinfo process-info-setcontrol (target self)) + + (if (string=? isRosettaTranslated "TRUE") + (allow file-map-executable (subpath "/private/var/db/oah"))) + + (allow file-map-executable file-read* + (subpath "/System") + (subpath "/usr/lib") + (subpath "/Library/GPUBundles") + (subpath app-path)) + + (if (string? crashPort) + (allow mach-lookup (global-name crashPort))) + + (allow signal (target self)) + (allow sysctl-read) + (allow file-read* + (literal "/dev/random") + (literal "/dev/urandom") + (subpath "/usr/share/icu")) + + ; Timezone + (allow file-read* + (subpath "/private/var/db/timezone") + (subpath "/usr/share/zoneinfo") + (subpath "/usr/share/zoneinfo.default") + (literal "/private/etc/localtime")) + + (allow sysctl-read + (sysctl-name-regex #"^sysctl\.") + (sysctl-name "kern.ostype") + (sysctl-name "kern.osversion") + (sysctl-name "kern.osrelease") + (sysctl-name "kern.osproductversion") + (sysctl-name "kern.version") + ; TODO: remove "kern.hostname". Without it the tests hang, but the hostname + ; is arguably sensitive information, so we should see what can be done about + ; removing it. + (sysctl-name "kern.hostname") + (sysctl-name "hw.machine") + (sysctl-name "hw.memsize") + (sysctl-name "hw.model") + (sysctl-name "hw.ncpu") + (sysctl-name "hw.activecpu") + (sysctl-name "hw.byteorder") + (sysctl-name "hw.pagesize_compat") + (sysctl-name "hw.logicalcpu_max") + (sysctl-name "hw.physicalcpu_max") + (sysctl-name "hw.busfrequency_compat") + (sysctl-name "hw.busfrequency_max") + (sysctl-name "hw.cpufrequency") + (sysctl-name "hw.cpufrequency_compat") + (sysctl-name "hw.cpufrequency_max") + (sysctl-name "hw.l2cachesize") + (sysctl-name "hw.l3cachesize") + (sysctl-name "hw.cachelinesize") + (sysctl-name "hw.cachelinesize_compat") + (sysctl-name "hw.tbfrequency_compat") + (sysctl-name "hw.vectorunit") + (sysctl-name "hw.optional.sse2") + (sysctl-name "hw.optional.sse3") + (sysctl-name "hw.optional.sse4_1") + (sysctl-name "hw.optional.sse4_2") + (sysctl-name "hw.optional.avx1_0") + (sysctl-name "hw.optional.avx2_0") + (sysctl-name "hw.optional.avx512f") + (sysctl-name "machdep.cpu.vendor") + (sysctl-name "machdep.cpu.family") + (sysctl-name "machdep.cpu.model") + (sysctl-name "machdep.cpu.stepping") + (sysctl-name "debug.intel.gstLevelGST") + (sysctl-name "debug.intel.gstLoaderControl")) + + (define (home-regex home-relative-regex) + (regex (string-append "^" (regex-quote home-path) home-relative-regex))) + (define (home-subpath home-relative-subpath) + (subpath (string-append home-path home-relative-subpath))) + (define (home-literal home-relative-literal) + (literal (string-append home-path home-relative-literal))) + (define (allow-shared-list domain) + (allow file-read* + (home-regex (string-append "/Library/Preferences/" (regex-quote domain))))) + + (allow ipc-posix-shm-read-data ipc-posix-shm-write-data + (ipc-posix-name-regex #"^CFPBS:")) + + (allow mach-lookup + (global-name "com.apple.CoreServices.coreservicesd") + (global-name "com.apple.coreservices.launchservicesd") + (global-name "com.apple.lsd.mapdb")) + + (allow file-read* + (subpath "/Library/ColorSync/Profiles") + (literal "/") + (literal "/private/tmp") + (literal "/private/var/tmp") + (home-subpath "/Library/Colors") + (home-subpath "/Library/ColorSync/Profiles")) + + (allow mach-lookup + ; bug 1392988 + (xpc-service-name "com.apple.coremedia.videodecoder") + (xpc-service-name "com.apple.coremedia.videoencoder")) + + (if (>= macosVersion 1100) + (allow mach-lookup + ; bug 1655655 + (global-name "com.apple.trustd.agent"))) + + ; Only supported on macOS 10.10+ + (if (defined? 'iokit-get-properties) + (allow iokit-get-properties + (iokit-property "board-id") + (iokit-property "class-code") + (iokit-property "vendor-id") + (iokit-property "device-id") + (iokit-property "IODVDBundleName") + (iokit-property "IOGLBundleName") + (iokit-property "IOGVACodec") + (iokit-property "IOGVAHEVCDecode") + (iokit-property "IOAVDHEVCDecodeCapabilities") + (iokit-property "IOGVAHEVCEncode") + (iokit-property "IOGVAXDecode") + (iokit-property "IOPCITunnelled") + (iokit-property "IOVARendererID") + (iokit-property "MetalPluginName") + (iokit-property "MetalPluginClassName"))) + +; accelerated graphics + (allow user-preference-read (preference-domain "com.apple.opengl")) + (allow user-preference-read (preference-domain "com.nvidia.OpenGL")) + (allow mach-lookup + (global-name "com.apple.cvmsServ") + (global-name "com.apple.MTLCompilerService")) + (allow iokit-open + (iokit-connection "IOAccelerator") + (iokit-user-client-class "IOAccelerationUserClient") + (iokit-user-client-class "IOSurfaceRootUserClient") + (iokit-user-client-class "IOSurfaceSendRight") + (iokit-user-client-class "IOFramebufferSharedUserClient") + (iokit-user-client-class "AGPMClient") + (iokit-user-client-class "AppleGraphicsControlClient")) + + (allow mach-lookup + ; bug 1565575 + (global-name "com.apple.audio.AudioComponentRegistrar")) +)SANDBOX_LITERAL"; + +} // namespace mozilla + +#endif // mozilla_SandboxPolicyRDD_h diff --git a/security/sandbox/mac/SandboxPolicySocket.h b/security/sandbox/mac/SandboxPolicySocket.h new file mode 100644 index 0000000000..f26608b440 --- /dev/null +++ b/security/sandbox/mac/SandboxPolicySocket.h @@ -0,0 +1,141 @@ +/* -*- 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/. */ + +#ifndef mozilla_SandboxPolicySocket_h +#define mozilla_SandboxPolicySocket_h + +namespace mozilla { + +static const char SandboxPolicySocket[] = R"SANDBOX_LITERAL( + (version 1) + + (define should-log (param "SHOULD_LOG")) + (define app-path (param "APP_PATH")) + (define crashPort (param "CRASH_PORT")) + (define home-path (param "HOME_PATH")) + (define isRosettaTranslated (param "IS_ROSETTA_TRANSLATED")) + + (define (moz-deny feature) + (if (string=? should-log "TRUE") + (deny feature) + (deny feature (with no-log)))) + + (define (home-subpath home-relative-subpath) + (subpath (string-append home-path home-relative-subpath))) + (define (home-literal home-relative-literal) + (literal (string-append home-path home-relative-literal))) + (define (home-regex home-relative-regex) + (regex (string-append "^" (regex-quote home-path) home-relative-regex))) + + (moz-deny default) + ; These are not included in (deny default) + (moz-deny process-info*) + (moz-deny nvram*) + (moz-deny file-map-executable) + + (if (string=? should-log "TRUE") + (debug deny)) + + ; Needed for things like getpriority()/setpriority()/pthread_setname() + (allow process-info-pidinfo process-info-setcontrol (target self)) + + (if (string=? isRosettaTranslated "TRUE") + (allow file-map-executable (subpath "/private/var/db/oah"))) + + (allow file-map-executable file-read* + (subpath "/System/Library") + (subpath "/usr/lib") + (subpath app-path)) + + (if (string? crashPort) + (allow mach-lookup (global-name crashPort))) + + (allow signal (target self)) + (allow sysctl-read) + (allow file-read* + (literal "/dev/random") + (literal "/dev/urandom") + (subpath "/usr/share/icu")) + + ; For stat and symlink resolution + (allow file-read-metadata (subpath "/")) + + ; Timezone + (allow file-read* + (subpath "/private/var/db/timezone") + (subpath "/usr/share/zoneinfo") + (subpath "/usr/share/zoneinfo.default") + (literal "/private/etc/localtime")) + + ; Needed for some global preferences + (allow file-read-data + (literal "/Library/Preferences/.GlobalPreferences.plist") + (home-literal "/Library/Preferences/.GlobalPreferences.plist") + (home-regex #"/Library/Preferences/ByHost/\.GlobalPreferences.*") + (home-literal "/Library/Preferences/com.apple.universalaccess.plist")) + + (allow file-read-data (literal "/private/etc/passwd")) + + (allow network-outbound + (control-name "com.apple.netsrc") + (literal "/private/var/run/mDNSResponder") + (remote tcp) + (remote udp)) + + (allow system-socket + (require-all (socket-domain AF_SYSTEM) + (socket-protocol 2)) ; SYSPROTO_CONTROL + (socket-domain AF_ROUTE)) + + (allow network-bind network-inbound + (local tcp) + (local udp)) + + ; Distributed notifications memory. + (allow ipc-posix-shm-read-data + (ipc-posix-name "apple.shm.notification_center")) + + ; Notification data from the security server database. + (allow ipc-posix-shm + (ipc-posix-name "com.apple.AppleDatabaseChanged")) + + ; From system.sb + (allow mach-lookup + (global-name "com.apple.bsd.dirhelper") + (global-name "com.apple.coreservices.launchservicesd") + (global-name "com.apple.system.notification_center")) + + ; resolv.conf and hosts file + (allow file-read* + (literal "/") + (literal "/etc") + (literal "/etc/hosts") + (literal "/etc/resolv.conf") + (literal "/private") + (literal "/private/etc") + (literal "/private/etc/hosts") + (literal "/private/etc/resolv.conf") + (literal "/private/var") + (literal "/private/var/run") + (literal "/private/var/run/resolv.conf") + (literal "/var") + (literal "/var/run")) + + ; Certificate databases + (allow file-read* + (subpath "/private/var/db/mds") + (subpath "/Library/Keychains") + (subpath "/System/Library/Keychains") + (subpath "/System/Library/Security") + (home-subpath "/Library/Keychains")) + + ; For enabling TCSM + (allow sysctl-write + (sysctl-name "kern.tcsm_enable")) +)SANDBOX_LITERAL"; + +} // namespace mozilla + +#endif // mozilla_SandboxPolicySocket_h diff --git a/security/sandbox/mac/SandboxPolicyUtility.h b/security/sandbox/mac/SandboxPolicyUtility.h new file mode 100644 index 0000000000..64add1fab9 --- /dev/null +++ b/security/sandbox/mac/SandboxPolicyUtility.h @@ -0,0 +1,70 @@ +/* -*- 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/. */ + +#ifndef mozilla_SandboxPolicyUtility_h +#define mozilla_SandboxPolicyUtility_h + +namespace mozilla { + +static const char SandboxPolicyUtility[] = R"SANDBOX_LITERAL( + (version 1) + + (define should-log (param "SHOULD_LOG")) + (define app-path (param "APP_PATH")) + (define crashPort (param "CRASH_PORT")) + (define isRosettaTranslated (param "IS_ROSETTA_TRANSLATED")) + + (define (moz-deny feature) + (if (string=? should-log "TRUE") + (deny feature) + (deny feature (with no-log)))) + + (moz-deny default) + ; These are not included in (deny default) + (moz-deny process-info*) + (moz-deny nvram*) + (moz-deny file-map-executable) + + ; Needed for things like getpriority()/setpriority()/pthread_setname() + (allow process-info-pidinfo process-info-setcontrol (target self)) + + (if (string=? isRosettaTranslated "TRUE") + (allow file-map-executable (subpath "/private/var/db/oah"))) + + (allow file-map-executable file-read* + (subpath "/System/Library") + (subpath "/usr/lib") + (subpath app-path)) + + (if (string? crashPort) + (allow mach-lookup (global-name crashPort))) + + (allow signal (target self)) + (allow sysctl-read) + (allow file-read* + (literal "/dev/random") + (literal "/dev/urandom") + (subpath "/usr/share/icu")) + + ; Timezone + (allow file-read* + (subpath "/private/var/db/timezone") + (subpath "/usr/share/zoneinfo") + (subpath "/usr/share/zoneinfo.default") + (literal "/private/etc/localtime")) + + (allow mach-lookup + (global-name "com.apple.coreservices.launchservicesd")) +)SANDBOX_LITERAL"; + +static const char SandboxPolicyUtilityAudioDecoderAppleMediaAddend[] = + R"SANDBOX_LITERAL( + ; For Utility AudioDecoder AppleMedia codecs (bug 1565575) + (allow mach-lookup (global-name "com.apple.audio.AudioComponentRegistrar")) +)SANDBOX_LITERAL"; + +} // namespace mozilla + +#endif // mozilla_SandboxPolicyUtility_h diff --git a/security/sandbox/mac/moz.build b/security/sandbox/mac/moz.build new file mode 100644 index 0000000000..00b96334b6 --- /dev/null +++ b/security/sandbox/mac/moz.build @@ -0,0 +1,19 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +EXPORTS.mozilla += [ + "Sandbox.h", + "SandboxPolicyContent.h", + "SandboxPolicyGMP.h", + "SandboxPolicyRDD.h", + "SandboxPolicyUtility.h", +] + +SOURCES += [ + "Sandbox.mm", +] + +Library("mozsandbox") |