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