tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Sandbox.mm (28828B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 // The Mac sandbox module is a static library (a Library in moz.build terms)
      7 // that can be linked into any binary (for example plugin-container or XUL).
      8 // It must not have dependencies on any other Mozilla module.  This is why,
      9 // for example, it has its own OS X version detection code, rather than
     10 // linking to nsCocoaFeatures.mm in XUL.
     11 
     12 #include "Sandbox.h"
     13 
     14 #include <CoreFoundation/CoreFoundation.h>
     15 #include <stdio.h>
     16 #include <stdlib.h>
     17 #include <sys/sysctl.h>
     18 #include <sys/types.h>
     19 
     20 #include <iostream>
     21 #include <sstream>
     22 #include <vector>
     23 
     24 #include "SandboxPolicyContent.h"
     25 #include "SandboxPolicyGMP.h"
     26 #include "SandboxPolicyGPU.h"
     27 #include "SandboxPolicyRDD.h"
     28 #include "SandboxPolicySocket.h"
     29 #include "SandboxPolicyUtility.h"
     30 #if defined(MOZ_PROFILE_GENERATE)
     31 #  include "SandboxPolicyPGO.h"
     32 #endif  // defined(MOZ_PROFILE_GENERATE)
     33 
     34 #include "mozilla/Assertions.h"
     35 
     36 #include "mozilla/GeckoArgs.h"
     37 #include "mozilla/ipc/UtilityProcessSandboxing.h"
     38 #include "mozilla/SandboxSettings.h"
     39 
     40 // Undocumented sandbox setup routines.
     41 extern "C" int sandbox_init_with_parameters(const char* profile, uint64_t flags,
     42                                            const char* const parameters[],
     43                                            char** errorbuf);
     44 extern "C" void sandbox_free_error(char* errorbuf);
     45 extern "C" int sandbox_check(pid_t pid, const char* operation, int type, ...);
     46 
     47 // Note about "major", "minor" and "bugfix" in the following code:
     48 //
     49 // The code decomposes an OS X version number into these components, and in
     50 // doing so follows Apple's terminology in Gestalt.h.  But this is very
     51 // misleading, because in other contexts Apple uses the "minor" component of
     52 // an OS X version number to indicate a "major" release (for example the "9"
     53 // in OS X 10.9.5), and the "bugfix" component to indicate a "minor" release
     54 // (for example the "5" in OS X 10.9.5).
     55 class OSXVersion {
     56 public:
     57  static void Get(int32_t& aMajor, int32_t& aMinor);
     58 
     59 private:
     60  static void GetSystemVersion(int32_t& aMajor, int32_t& aMinor,
     61                               int32_t& aBugFix);
     62  static bool mCached;
     63  static int32_t mOSXVersionMajor;
     64  static int32_t mOSXVersionMinor;
     65 };
     66 
     67 bool OSXVersion::mCached = false;
     68 int32_t OSXVersion::mOSXVersionMajor;
     69 int32_t OSXVersion::mOSXVersionMinor;
     70 
     71 void OSXVersion::Get(int32_t& aMajor, int32_t& aMinor) {
     72  if (!mCached) {
     73    int32_t major, minor, bugfix;
     74    GetSystemVersion(major, minor, bugfix);
     75    mOSXVersionMajor = major;
     76    mOSXVersionMinor = minor;
     77    mCached = true;
     78  }
     79  aMajor = mOSXVersionMajor;
     80  aMinor = mOSXVersionMinor;
     81 }
     82 
     83 void OSXVersion::GetSystemVersion(int32_t& aMajor, int32_t& aMinor,
     84                                  int32_t& aBugFix) {
     85  SInt32 major = 0, minor = 0, bugfix = 0;
     86 
     87  CFURLRef url = CFURLCreateWithString(
     88      kCFAllocatorDefault,
     89      CFSTR("file:///System/Library/CoreServices/SystemVersion.plist"), NULL);
     90  CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
     91  CFReadStreamOpen(stream);
     92  CFDictionaryRef sysVersionPlist =
     93      (CFDictionaryRef)CFPropertyListCreateWithStream(
     94          kCFAllocatorDefault, stream, 0, kCFPropertyListImmutable, NULL, NULL);
     95  CFReadStreamClose(stream);
     96  CFRelease(stream);
     97  CFRelease(url);
     98 
     99  CFStringRef versionString = (CFStringRef)CFDictionaryGetValue(
    100      sysVersionPlist, CFSTR("ProductVersion"));
    101  CFArrayRef versions = CFStringCreateArrayBySeparatingStrings(
    102      kCFAllocatorDefault, versionString, CFSTR("."));
    103  CFIndex count = CFArrayGetCount(versions);
    104  if (count > 0) {
    105    CFStringRef component = (CFStringRef)CFArrayGetValueAtIndex(versions, 0);
    106    major = CFStringGetIntValue(component);
    107    if (count > 1) {
    108      component = (CFStringRef)CFArrayGetValueAtIndex(versions, 1);
    109      minor = CFStringGetIntValue(component);
    110      if (count > 2) {
    111        component = (CFStringRef)CFArrayGetValueAtIndex(versions, 2);
    112        bugfix = CFStringGetIntValue(component);
    113      }
    114    }
    115  }
    116  CFRelease(sysVersionPlist);
    117  CFRelease(versions);
    118 
    119  if (major < 10) {
    120    // If 'major' isn't what we expect, assume 10.6.
    121    aMajor = 10;
    122    aMinor = 6;
    123    aBugFix = 0;
    124  } else if ((major == 10) && (minor >= 16)) {
    125    // Account for SystemVersionCompat.plist being used which is
    126    // automatically used for builds using older SDK versions and
    127    // results in 11.0 being reported as 10.16. Assume the compat
    128    // version will increase in step with the correct version.
    129    aMajor = 11;
    130    aMinor = minor - 16;
    131    aBugFix = bugfix;
    132  } else {
    133    aMajor = major;
    134    aMinor = minor;
    135    aBugFix = bugfix;
    136  }
    137 }
    138 
    139 bool GetRealPath(std::string& aOutputPath, const char* aInputPath) {
    140  char* resolvedPath = realpath(aInputPath, nullptr);
    141  if (resolvedPath == nullptr) {
    142    return false;
    143  }
    144 
    145  aOutputPath = resolvedPath;
    146  free(resolvedPath);
    147 
    148  return !aOutputPath.empty();
    149 }
    150 
    151 /*
    152 * Returns true if the process is running under Rosetta translation. Returns
    153 * false if running natively or if an error was encountered. To be called
    154 * before enabling the sandbox therefore not requiring the sysctl be allowed
    155 * by the sandbox policy. We use the `sysctl.proc_translated` sysctl which is
    156 * documented by Apple to be used for this purpose.
    157 */
    158 bool ProcessIsRosettaTranslated() {
    159  int ret = 0;
    160  size_t size = sizeof(ret);
    161  if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) {
    162    if (errno != ENOENT) {
    163      fprintf(stderr, "Failed to check for translation environment\n");
    164    }
    165    return false;
    166  }
    167  return (ret == 1);
    168 }
    169 
    170 void MacSandboxInfo::AppendAsParams(std::vector<std::string>& aParams) const {
    171  this->AppendStartupParam(aParams);
    172  this->AppendLoggingParam(aParams);
    173  this->AppendAppPathParam(aParams);
    174 
    175  switch (this->type) {
    176    case MacSandboxType_Content:
    177      this->AppendLevelParam(aParams);
    178      this->AppendAudioParam(aParams);
    179      this->AppendWindowServerParam(aParams);
    180      this->AppendReadPathParams(aParams);
    181 #ifdef DEBUG
    182      this->AppendDebugWriteDirParam(aParams);
    183 #endif
    184      break;
    185    case MacSandboxType_RDD:
    186    case MacSandboxType_Socket:
    187    case MacSandboxType_Utility:
    188      break;
    189    case MacSandboxType_GMP:
    190      this->AppendPluginPathParam(aParams);
    191      this->AppendWindowServerParam(aParams);
    192      this->AppendReadPathParams(aParams);
    193      break;
    194    case MacSandboxType_GPU:
    195      break;
    196    default:
    197      // Before supporting a new process type, add a case statement
    198      // here to append any neccesary process-type-specific params.
    199      MOZ_RELEASE_ASSERT(false);
    200      break;
    201  }
    202 }
    203 
    204 void MacSandboxInfo::AppendStartupParam(
    205    std::vector<std::string>& aParams) const {
    206  aParams.push_back("-sbStartup");
    207 }
    208 
    209 void MacSandboxInfo::AppendLoggingParam(
    210    std::vector<std::string>& aParams) const {
    211  if (this->shouldLog) {
    212    aParams.push_back("-sbLogging");
    213  }
    214 }
    215 
    216 void MacSandboxInfo::AppendAppPathParam(
    217    std::vector<std::string>& aParams) const {
    218  aParams.push_back("-sbAppPath");
    219  aParams.push_back(this->appPath);
    220 }
    221 
    222 void MacSandboxInfo::AppendPluginPathParam(
    223    std::vector<std::string>& aParams) const {
    224  aParams.push_back("-sbPluginPath");
    225  aParams.push_back(this->pluginPath);
    226 }
    227 
    228 /* static */
    229 void MacSandboxInfo::AppendFileAccessParam(std::vector<std::string>& aParams,
    230                                           bool aHasFilePrivileges) {
    231  if (aHasFilePrivileges) {
    232    aParams.push_back("-sbAllowFileAccess");
    233  }
    234 }
    235 
    236 void MacSandboxInfo::AppendLevelParam(std::vector<std::string>& aParams) const {
    237  std::ostringstream os;
    238  os << this->level;
    239  std::string levelString = os.str();
    240  aParams.push_back("-sbLevel");
    241  aParams.push_back(levelString);
    242 }
    243 
    244 void MacSandboxInfo::AppendAudioParam(std::vector<std::string>& aParams) const {
    245  if (this->hasAudio) {
    246    aParams.push_back("-sbAllowAudio");
    247  }
    248 }
    249 
    250 void MacSandboxInfo::AppendWindowServerParam(
    251    std::vector<std::string>& aParams) const {
    252  if (this->hasWindowServer) {
    253    aParams.push_back("-sbAllowWindowServer");
    254  }
    255 }
    256 
    257 void MacSandboxInfo::AppendReadPathParams(
    258    std::vector<std::string>& aParams) const {
    259  if (!this->testingReadPath1.empty()) {
    260    aParams.push_back("-sbTestingReadPath");
    261    aParams.push_back(this->testingReadPath1.c_str());
    262  }
    263  if (!this->testingReadPath2.empty()) {
    264    aParams.push_back("-sbTestingReadPath");
    265    aParams.push_back(this->testingReadPath2.c_str());
    266  }
    267  if (!this->testingReadPath3.empty()) {
    268    aParams.push_back("-sbTestingReadPath");
    269    aParams.push_back(this->testingReadPath3.c_str());
    270  }
    271  if (!this->testingReadPath4.empty()) {
    272    aParams.push_back("-sbTestingReadPath");
    273    aParams.push_back(this->testingReadPath4.c_str());
    274  }
    275 }
    276 
    277 #ifdef DEBUG
    278 void MacSandboxInfo::AppendDebugWriteDirParam(
    279    std::vector<std::string>& aParams) const {
    280  if (!this->debugWriteDir.empty()) {
    281    aParams.push_back("-sbDebugWriteDir");
    282    aParams.push_back(this->debugWriteDir.c_str());
    283  }
    284 }
    285 #endif
    286 
    287 namespace mozilla {
    288 
    289 bool StartMacSandbox(MacSandboxInfo const& aInfo, std::string& aErrorMessage) {
    290  std::vector<const char*> params;
    291  std::string profile;
    292 
    293  // Use a combined version number to simplify version check logic
    294  // in sandbox policies. For example, 10.14 becomes "1014".
    295  int32_t major = 0, minor = 0;
    296  OSXVersion::Get(major, minor);
    297  MOZ_ASSERT(minor >= 0 && minor < 100);
    298  std::string combinedVersion = std::to_string((major * 100) + minor);
    299 
    300  params.push_back("IS_ROSETTA_TRANSLATED");
    301  params.push_back(ProcessIsRosettaTranslated() ? "TRUE" : "FALSE");
    302 
    303  // Used for the content process to access to parts of the cache dir.
    304  std::string userCacheDir;
    305  std::string bundleIDCacheDir;
    306 
    307  if (aInfo.type == MacSandboxType_Utility) {
    308    profile = const_cast<char*>(SandboxPolicyUtility);
    309 
    310    switch (aInfo.utilityKind) {
    311      case ipc::SandboxingKind::GENERIC_UTILITY:
    312        // Nothing to do here specifically
    313        break;
    314 
    315 #ifdef MOZ_APPLEMEDIA
    316      case ipc::SandboxingKind::UTILITY_AUDIO_DECODING_APPLE_MEDIA: {
    317        profile.append(SandboxPolicyUtilityMediaServiceAppleMediaAddend);
    318        params.push_back("MAC_OS_VERSION");
    319        params.push_back(combinedVersion.c_str());
    320      } break;
    321 #endif
    322 
    323      default:
    324        MOZ_ASSERT(false, "Invalid SandboxingKind");
    325        break;
    326    }
    327    params.push_back("SHOULD_LOG");
    328    params.push_back(aInfo.shouldLog ? "TRUE" : "FALSE");
    329    params.push_back("APP_PATH");
    330    params.push_back(aInfo.appPath.c_str());
    331    params.push_back("APP_BINARY_PATH");
    332    params.push_back(aInfo.appBinaryPath.c_str());
    333    if (!aInfo.crashServerPort.empty()) {
    334      params.push_back("CRASH_PORT");
    335      params.push_back(aInfo.crashServerPort.c_str());
    336    }
    337  } else if (aInfo.type == MacSandboxType_RDD) {
    338    profile = const_cast<char*>(SandboxPolicyRDD);
    339    params.push_back("SHOULD_LOG");
    340    params.push_back(aInfo.shouldLog ? "TRUE" : "FALSE");
    341    params.push_back("MAC_OS_VERSION");
    342    params.push_back(combinedVersion.c_str());
    343    params.push_back("APP_PATH");
    344    params.push_back(aInfo.appPath.c_str());
    345    params.push_back("HOME_PATH");
    346    params.push_back(getenv("HOME"));
    347    if (!aInfo.crashServerPort.empty()) {
    348      params.push_back("CRASH_PORT");
    349      params.push_back(aInfo.crashServerPort.c_str());
    350    }
    351  } else if (aInfo.type == MacSandboxType_Socket) {
    352    profile = const_cast<char*>(SandboxPolicySocket);
    353    params.push_back("SHOULD_LOG");
    354    params.push_back(aInfo.shouldLog ? "TRUE" : "FALSE");
    355    params.push_back("APP_PATH");
    356    params.push_back(aInfo.appPath.c_str());
    357    if (!aInfo.crashServerPort.empty()) {
    358      params.push_back("CRASH_PORT");
    359      params.push_back(aInfo.crashServerPort.c_str());
    360    }
    361    params.push_back("HOME_PATH");
    362    params.push_back(getenv("HOME"));
    363  } else if (aInfo.type == MacSandboxType_GMP) {
    364    profile = const_cast<char*>(SandboxPolicyGMP);
    365    params.push_back("SHOULD_LOG");
    366    params.push_back(aInfo.shouldLog ? "TRUE" : "FALSE");
    367    params.push_back("APP_PATH");
    368    params.push_back(aInfo.appPath.c_str());
    369    params.push_back("PLUGIN_PATH");
    370    params.push_back(aInfo.pluginPath.c_str());
    371    if (!aInfo.pluginBinaryPath.empty()) {
    372      params.push_back("PLUGIN_BINARY_PATH");
    373      params.push_back(aInfo.pluginBinaryPath.c_str());
    374    }
    375    params.push_back("HAS_WINDOW_SERVER");
    376    params.push_back(aInfo.hasWindowServer ? "TRUE" : "FALSE");
    377    if (!aInfo.crashServerPort.empty()) {
    378      params.push_back("CRASH_PORT");
    379      params.push_back(aInfo.crashServerPort.c_str());
    380    }
    381    if (!aInfo.testingReadPath1.empty()) {
    382      params.push_back("TESTING_READ_PATH1");
    383      params.push_back(aInfo.testingReadPath1.c_str());
    384    }
    385    if (!aInfo.testingReadPath2.empty()) {
    386      params.push_back("TESTING_READ_PATH2");
    387      params.push_back(aInfo.testingReadPath2.c_str());
    388    }
    389  } else if (aInfo.type == MacSandboxType_Content) {
    390    MOZ_ASSERT(aInfo.level >= 1);
    391    if (aInfo.level >= 1) {
    392      profile = SandboxPolicyContent;
    393      params.push_back("SHOULD_LOG");
    394      params.push_back(aInfo.shouldLog ? "TRUE" : "FALSE");
    395      params.push_back("SANDBOX_LEVEL_1");
    396      params.push_back(aInfo.level == 1 ? "TRUE" : "FALSE");
    397      params.push_back("SANDBOX_LEVEL_2");
    398      params.push_back(aInfo.level == 2 ? "TRUE" : "FALSE");
    399      params.push_back("SANDBOX_LEVEL_3");
    400      params.push_back(aInfo.level == 3 ? "TRUE" : "FALSE");
    401      params.push_back("MAC_OS_VERSION");
    402      params.push_back(combinedVersion.c_str());
    403      params.push_back("APP_PATH");
    404      params.push_back(aInfo.appPath.c_str());
    405      params.push_back("PROFILE_DIR");
    406      params.push_back(aInfo.profileDir.c_str());
    407      params.push_back("HOME_PATH");
    408      params.push_back(getenv("HOME"));
    409      params.push_back("HAS_SANDBOXED_PROFILE");
    410      params.push_back(aInfo.hasSandboxedProfile ? "TRUE" : "FALSE");
    411      params.push_back("HAS_WINDOW_SERVER");
    412      params.push_back(aInfo.hasWindowServer ? "TRUE" : "FALSE");
    413      if (!aInfo.crashServerPort.empty()) {
    414        params.push_back("CRASH_PORT");
    415        params.push_back(aInfo.crashServerPort.c_str());
    416      }
    417 
    418      params.push_back("DARWIN_USER_CACHE_DIR");
    419      char confStrBuf[PATH_MAX];
    420      if (!confstr(_CS_DARWIN_USER_CACHE_DIR, confStrBuf, sizeof(confStrBuf))) {
    421        return false;
    422      }
    423      if (!GetRealPath(userCacheDir, confStrBuf)) {
    424        return false;
    425      }
    426      params.push_back(userCacheDir.c_str());
    427 
    428      if (!aInfo.testingReadPath1.empty()) {
    429        params.push_back("TESTING_READ_PATH1");
    430        params.push_back(aInfo.testingReadPath1.c_str());
    431      }
    432      if (!aInfo.testingReadPath2.empty()) {
    433        params.push_back("TESTING_READ_PATH2");
    434        params.push_back(aInfo.testingReadPath2.c_str());
    435      }
    436      if (!aInfo.testingReadPath3.empty()) {
    437        params.push_back("TESTING_READ_PATH3");
    438        params.push_back(aInfo.testingReadPath3.c_str());
    439      }
    440      if (!aInfo.testingReadPath4.empty()) {
    441        params.push_back("TESTING_READ_PATH4");
    442        params.push_back(aInfo.testingReadPath4.c_str());
    443      }
    444 #ifdef DEBUG
    445      if (!aInfo.debugWriteDir.empty()) {
    446        params.push_back("DEBUG_WRITE_DIR");
    447        params.push_back(aInfo.debugWriteDir.c_str());
    448      }
    449 #endif  // DEBUG
    450 
    451      if (aInfo.hasFilePrivileges) {
    452        profile.append(SandboxPolicyContentFileAddend);
    453      }
    454      if (aInfo.hasAudio) {
    455        profile.append(SandboxPolicyContentAudioAddend);
    456      }
    457    } else {
    458      fprintf(stderr,
    459              "Content sandbox disabled due to sandbox level setting\n");
    460      return false;
    461    }
    462  } else if (aInfo.type == MacSandboxType_GPU) {
    463    profile = const_cast<char*>(SandboxPolicyGPU);
    464    params.push_back("SHOULD_LOG");
    465    params.push_back(aInfo.shouldLog ? "TRUE" : "FALSE");
    466    params.push_back("MAC_OS_VERSION");
    467    params.push_back(combinedVersion.c_str());
    468    params.push_back("APP_PATH");
    469    params.push_back(aInfo.appPath.c_str());
    470    params.push_back("HOME_PATH");
    471    params.push_back(getenv("HOME"));
    472    if (!aInfo.crashServerPort.empty()) {
    473      params.push_back("CRASH_PORT");
    474      params.push_back(aInfo.crashServerPort.c_str());
    475    }
    476 
    477    params.push_back("DARWIN_USER_CACHE_DIR");
    478    char confStrBuf[PATH_MAX];
    479    if (!confstr(_CS_DARWIN_USER_CACHE_DIR, confStrBuf, sizeof(confStrBuf))) {
    480      return false;
    481    }
    482    if (!GetRealPath(userCacheDir, confStrBuf)) {
    483      return false;
    484    }
    485    params.push_back(userCacheDir.c_str());
    486 
    487    // For accessing shader cache paths in the cache dir that
    488    // are derived from the applications bundle ID.
    489    bundleIDCacheDir = userCacheDir;
    490    bundleIDCacheDir.append("/" MOZ_GPU_PROCESS_BUNDLEID);
    491    params.push_back("BUNDLE_ID_CACHE_DIR");
    492    params.push_back(bundleIDCacheDir.c_str());
    493  } else {
    494    char* msg = NULL;
    495    asprintf(&msg, "Unexpected sandbox type %u", aInfo.type);
    496    if (msg) {
    497      aErrorMessage.assign(msg);
    498      free(msg);
    499    }
    500    return false;
    501  }
    502 
    503  if (profile.empty()) {
    504    fprintf(stderr, "Out of memory in StartMacSandbox()!\n");
    505    return false;
    506  }
    507 
    508 #if defined(MOZ_PROFILE_GENERATE)
    509  // It should only be allowed on instrumented builds, never on production
    510  // builds.
    511  std::string parentPath;
    512  if (GetLlvmProfileDir(parentPath)) {
    513    params.push_back("PGO_DATA_DIR");
    514    params.push_back(parentPath.c_str());
    515    profile.append(SandboxPolicyPGO);
    516  }
    517 #endif
    518 
    519 // In order to avoid relying on any other Mozilla modules (as described at the
    520 // top of this file), we use our own #define instead of the existing MOZ_LOG
    521 // infrastructure. This can be used by developers to debug the macOS sandbox
    522 // policy.
    523 #define MAC_SANDBOX_PRINT_POLICY 0
    524 #if MAC_SANDBOX_PRINT_POLICY
    525  printf("Sandbox params for PID %d:\n", getpid());
    526  for (size_t i = 0; i < params.size() / 2; i++) {
    527    printf("  %s = %s\n", params[i * 2], params[(i * 2) + 1]);
    528  }
    529  printf("Sandbox profile:\n%s\n", profile.c_str());
    530 #endif
    531 
    532  // The parameters array is null terminated.
    533  params.push_back(nullptr);
    534 
    535  char* errorbuf = NULL;
    536  int rv = sandbox_init_with_parameters(profile.c_str(), 0, params.data(),
    537                                        &errorbuf);
    538  if (rv) {
    539    if (errorbuf) {
    540      char* msg = NULL;
    541      asprintf(&msg, "sandbox_init() failed with error \"%s\"", errorbuf);
    542      if (msg) {
    543        aErrorMessage.assign(msg);
    544        free(msg);
    545      }
    546      fprintf(stderr, "profile: %s\n", profile.c_str());
    547      sandbox_free_error(errorbuf);
    548    }
    549  }
    550  if (rv) {
    551    return false;
    552  }
    553 
    554  return true;
    555 }
    556 
    557 /*
    558 * Fill |aInfo| with content sandbox params parsed from the provided
    559 * command line arguments. Return false if any sandbox parameters needed
    560 * for early startup of the sandbox are not present in the arguments.
    561 */
    562 bool GetContentSandboxParamsFromArgs(int aArgc, char** aArgv,
    563                                     MacSandboxInfo& aInfo) {
    564  // Ensure we find these paramaters in the command
    565  // line arguments. Return false if any are missing.
    566  bool foundSandboxLevel = false;
    567  bool foundValidSandboxLevel = false;
    568  bool foundAppPath = false;
    569 
    570  // Read access directories used in testing
    571  int nTestingReadPaths = 0;
    572  std::string testingReadPaths[MAX_CONTENT_TESTING_READ_PATHS] = {};
    573 
    574  // Collect sandbox params from CLI arguments
    575  for (int i = 0; i < aArgc; i++) {
    576    if ((strcmp(aArgv[i], "-sbLevel") == 0) && (i + 1 < aArgc)) {
    577      std::stringstream ss(aArgv[i + 1]);
    578      int level = 0;
    579      ss >> level;
    580      foundSandboxLevel = true;
    581      aInfo.level = level;
    582      foundValidSandboxLevel = level > 0 && level <= 3 ? true : false;
    583      if (!foundValidSandboxLevel) {
    584        break;
    585      }
    586      i++;
    587      continue;
    588    }
    589 
    590    if (strcmp(aArgv[i], "-sbLogging") == 0) {
    591      aInfo.shouldLog = true;
    592      continue;
    593    }
    594 
    595    if (strcmp(aArgv[i], "-sbAllowFileAccess") == 0) {
    596      aInfo.hasFilePrivileges = true;
    597      continue;
    598    }
    599 
    600    if (strcmp(aArgv[i], "-sbAllowAudio") == 0) {
    601      aInfo.hasAudio = true;
    602      continue;
    603    }
    604 
    605    if (strcmp(aArgv[i], "-sbAllowWindowServer") == 0) {
    606      aInfo.hasWindowServer = true;
    607      continue;
    608    }
    609 
    610    if ((strcmp(aArgv[i], "-sbAppPath") == 0) && (i + 1 < aArgc)) {
    611      foundAppPath = true;
    612      aInfo.appPath.assign(aArgv[i + 1]);
    613      i++;
    614      continue;
    615    }
    616 
    617    if ((strcmp(aArgv[i], "-sbTestingReadPath") == 0) && (i + 1 < aArgc)) {
    618      if (nTestingReadPaths >= MAX_CONTENT_TESTING_READ_PATHS) {
    619        MOZ_CRASH("Too many content process -sbTestingReadPath arguments");
    620      }
    621      testingReadPaths[nTestingReadPaths] = aArgv[i + 1];
    622      nTestingReadPaths++;
    623      i++;
    624      continue;
    625    }
    626 
    627    if ((strcmp(aArgv[i], "-profile") == 0) && (i + 1 < aArgc)) {
    628      aInfo.hasSandboxedProfile = true;
    629      aInfo.profileDir.assign(aArgv[i + 1]);
    630      i++;
    631      continue;
    632    }
    633 
    634 #ifdef DEBUG
    635    if ((strcmp(aArgv[i], "-sbDebugWriteDir") == 0) && (i + 1 < aArgc)) {
    636      aInfo.debugWriteDir.assign(aArgv[i + 1]);
    637      i++;
    638      continue;
    639    }
    640 #endif  // DEBUG
    641 
    642    // Handle crash server positional argument
    643    if (strstr(aArgv[i], "gecko-crash-server-pipe") != NULL) {
    644      aInfo.crashServerPort.assign(aArgv[i]);
    645      continue;
    646    }
    647  }
    648 
    649  if (!foundSandboxLevel) {
    650    fprintf(stderr, "Content sandbox disabled due to "
    651                    "missing sandbox CLI level parameter.\n");
    652    return false;
    653  }
    654 
    655  if (!foundValidSandboxLevel) {
    656    fprintf(stderr,
    657            "Content sandbox disabled due to invalid"
    658            "sandbox level (%d)\n",
    659            aInfo.level);
    660    return false;
    661  }
    662 
    663  if (!foundAppPath) {
    664    fprintf(stderr, "Content sandbox disabled due to "
    665                    "missing sandbox CLI app path parameter.\n");
    666    return false;
    667  }
    668 
    669  aInfo.testingReadPath1 = testingReadPaths[0];
    670  aInfo.testingReadPath2 = testingReadPaths[1];
    671  aInfo.testingReadPath3 = testingReadPaths[2];
    672  aInfo.testingReadPath4 = testingReadPaths[3];
    673 
    674  return true;
    675 }
    676 
    677 bool GetAppPathForExecutable(const char* aAppName, const char* aExecutablePath,
    678                             std::string& aAppPath) {
    679  std::string execPath(aExecutablePath);
    680  std::string appName(aAppName);
    681  size_t pos = execPath.rfind(appName + '/');
    682  if (pos == std::string::npos) {
    683    return false;
    684  }
    685  aAppPath = execPath.substr(0, pos + appName.size());
    686  return true;
    687 }
    688 
    689 bool GetUtilitySandboxParamsFromArgs(int aArgc, char** aArgv,
    690                                     MacSandboxInfo& aInfo,
    691                                     bool aSandboxingKindRequired = true) {
    692  // Ensure we find these paramaters in the command
    693  // line arguments. Return false if any are missing.
    694  bool foundAppPath = false;
    695 
    696  GetAppPathForExecutable(MOZ_CHILD_PROCESS_BUNDLENAME, aArgv[0],
    697                          aInfo.appBinaryPath);
    698 
    699  // Collect sandbox params from CLI arguments
    700  for (int i = 0; i < aArgc; i++) {
    701    if (strcmp(aArgv[i], "-sbLogging") == 0) {
    702      aInfo.shouldLog = true;
    703      continue;
    704    }
    705 
    706    if ((strcmp(aArgv[i], "-sbAppPath") == 0) && (i + 1 < aArgc)) {
    707      foundAppPath = true;
    708      aInfo.appPath.assign(aArgv[i + 1]);
    709      i++;
    710      continue;
    711    }
    712 
    713    // Handle crash server positional argument
    714    if (strstr(aArgv[i], "gecko-crash-server-pipe") != NULL) {
    715      aInfo.crashServerPort.assign(aArgv[i]);
    716      continue;
    717    }
    718  }
    719 
    720  if (aSandboxingKindRequired) {
    721    Maybe<uint64_t> sandboxingKind =
    722        geckoargs::sSandboxingKind.Get(aArgc, aArgv, CheckArgFlag::None);
    723    if (sandboxingKind.isNothing()) {
    724      fprintf(stderr, "Utility sandbox requires a sandboxingKind");
    725      return false;
    726    }
    727    aInfo.utilityKind = (ipc::SandboxingKind)*sandboxingKind;
    728  }
    729 
    730  if (!foundAppPath) {
    731    fprintf(stderr, "Utility sandbox disabled due to "
    732                    "missing sandbox CLI app path parameter.\n");
    733    return false;
    734  }
    735 
    736  return true;
    737 }
    738 
    739 bool GetSocketSandboxParamsFromArgs(int aArgc, char** aArgv,
    740                                    MacSandboxInfo& aInfo) {
    741  return GetUtilitySandboxParamsFromArgs(aArgc, aArgv, aInfo, false);
    742 }
    743 
    744 bool GetPluginSandboxParamsFromArgs(int aArgc, char** aArgv,
    745                                    MacSandboxInfo& aInfo) {
    746  // Ensure we find these paramaters in the command
    747  // line arguments. Return false if any are missing.
    748  bool foundAppPath = false;
    749  bool foundPluginPath = false;
    750 
    751  // Read access directories used in testing
    752  int nTestingReadPaths = 0;
    753  std::string testingReadPaths[MAX_GMP_TESTING_READ_PATHS] = {};
    754 
    755  // Collect sandbox params from CLI arguments
    756  for (int i = 0; i < aArgc; i++) {
    757    if (strcmp(aArgv[i], "-sbLogging") == 0) {
    758      aInfo.shouldLog = true;
    759      continue;
    760    }
    761 
    762    if ((strcmp(aArgv[i], "-sbAppPath") == 0) && (i + 1 < aArgc)) {
    763      foundAppPath = true;
    764      aInfo.appPath.assign(aArgv[i + 1]);
    765      i++;
    766      continue;
    767    }
    768 
    769    if ((strcmp(aArgv[i], "-sbPluginPath") == 0) && (i + 1 < aArgc)) {
    770      foundPluginPath = true;
    771      aInfo.pluginPath.assign(aArgv[i + 1]);
    772      i++;
    773      continue;
    774    }
    775 
    776    if (strcmp(aArgv[i], "-sbAllowWindowServer") == 0) {
    777      aInfo.hasWindowServer = true;
    778      continue;
    779    }
    780 
    781    if ((strcmp(aArgv[i], "-sbTestingReadPath") == 0) && (i + 1 < aArgc)) {
    782      if (nTestingReadPaths >= MAX_GMP_TESTING_READ_PATHS) {
    783        MOZ_CRASH("Too many GMP process -sbTestingReadPath arguments");
    784      }
    785      testingReadPaths[nTestingReadPaths] = aArgv[i + 1];
    786      nTestingReadPaths++;
    787      i++;
    788      continue;
    789    }
    790 
    791    // Handle crash server positional argument
    792    if (strstr(aArgv[i], "gecko-crash-server-pipe") != NULL) {
    793      aInfo.crashServerPort.assign(aArgv[i]);
    794      continue;
    795    }
    796  }
    797 
    798  if (!foundPluginPath) {
    799    fprintf(stderr, "GMP sandbox disabled due to "
    800                    "missing sandbox CLI plugin path parameter.\n");
    801    return false;
    802  }
    803 
    804  if (!foundAppPath) {
    805    fprintf(stderr, "GMP sandbox disabled due to "
    806                    "missing sandbox CLI app path parameter.\n");
    807    return false;
    808  }
    809 
    810  aInfo.testingReadPath1 = testingReadPaths[0];
    811  aInfo.testingReadPath2 = testingReadPaths[1];
    812 
    813  return true;
    814 }
    815 
    816 bool GetRDDSandboxParamsFromArgs(int aArgc, char** aArgv,
    817                                 MacSandboxInfo& aInfo) {
    818  return GetUtilitySandboxParamsFromArgs(aArgc, aArgv, aInfo, false);
    819 }
    820 
    821 bool GetGPUSandboxParamsFromArgs(int aArgc, char** aArgv,
    822                                 MacSandboxInfo& aInfo) {
    823  return GetUtilitySandboxParamsFromArgs(aArgc, aArgv, aInfo, false);
    824 }
    825 
    826 /*
    827 * Returns true if no errors were encountered or if early sandbox startup is
    828 * not enabled for this process. Returns false if an error was encountered.
    829 */
    830 bool StartMacSandboxIfEnabled(const MacSandboxType aSandboxType, int aArgc,
    831                              char** aArgv, std::string& aErrorMessage) {
    832  bool earlyStartupEnabled = false;
    833 
    834  // Check for the -sbStartup CLI parameter which
    835  // indicates we should start the sandbox now.
    836  for (int i = 0; i < aArgc; i++) {
    837    if (strcmp(aArgv[i], "-sbStartup") == 0) {
    838      earlyStartupEnabled = true;
    839      break;
    840    }
    841  }
    842 
    843  // The sandbox will be started later when/if parent
    844  // sends the sandbox startup message. Return true
    845  // indicating no errors occurred.
    846  if (!earlyStartupEnabled) {
    847    return true;
    848  }
    849 
    850  MacSandboxInfo info;
    851  info.type = aSandboxType;
    852 
    853  // For now, early start is only implemented
    854  // for content and utility sandbox types.
    855  switch (aSandboxType) {
    856    case MacSandboxType_Content:
    857      if (!GetContentSandboxParamsFromArgs(aArgc, aArgv, info)) {
    858        return false;
    859      }
    860      break;
    861    case MacSandboxType_GMP:
    862      if (!GetPluginSandboxParamsFromArgs(aArgc, aArgv, info)) {
    863        return false;
    864      }
    865      break;
    866    case MacSandboxType_GPU:
    867      if (!GetGPUSandboxParamsFromArgs(aArgc, aArgv, info)) {
    868        return false;
    869      }
    870      break;
    871    case MacSandboxType_RDD:
    872      if (!GetRDDSandboxParamsFromArgs(aArgc, aArgv, info)) {
    873        return false;
    874      }
    875      break;
    876    case MacSandboxType_Socket:
    877      if (!GetSocketSandboxParamsFromArgs(aArgc, aArgv, info)) {
    878        return false;
    879      }
    880      break;
    881    case MacSandboxType_Utility:
    882      if (!GetUtilitySandboxParamsFromArgs(aArgc, aArgv, info)) {
    883        return false;
    884      }
    885      break;
    886    default:
    887      MOZ_RELEASE_ASSERT(false);
    888      break;
    889  }
    890 
    891  return StartMacSandbox(info, aErrorMessage);
    892 }
    893 
    894 bool IsMacSandboxStarted() { return sandbox_check(getpid(), NULL, 0) == 1; }
    895 
    896 #ifdef DEBUG
    897 // sandbox_check returns 1 if the specified process is sandboxed
    898 void AssertMacSandboxEnabled() {
    899  MOZ_ASSERT(sandbox_check(getpid(), NULL, 0) == 1);
    900 }
    901 #endif /* DEBUG */
    902 
    903 }  // namespace mozilla