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 <stdio.h> 15#include <stdlib.h> 16#include <CoreFoundation/CoreFoundation.h> 17#include <iostream> 18#include <sstream> 19#include <vector> 20 21#include "mozilla/Assertions.h" 22#include "SandboxPolicyContent.h" 23#include "SandboxPolicyFlash.h" 24#include "SandboxPolicyGMP.h" 25#include "SandboxPolicyUtility.h" 26#include "SandboxPolicySocket.h" 27 28// Undocumented sandbox setup routines. 29extern "C" int sandbox_init_with_parameters(const char* profile, uint64_t flags, 30 const char* const parameters[], char** errorbuf); 31extern "C" void sandbox_free_error(char* errorbuf); 32extern "C" int sandbox_check(pid_t pid, const char* operation, int type, ...); 33 34// Note about "major", "minor" and "bugfix" in the following code: 35// 36// The code decomposes an OS X version number into these components, and in 37// doing so follows Apple's terminology in Gestalt.h. But this is very 38// misleading, because in other contexts Apple uses the "minor" component of 39// an OS X version number to indicate a "major" release (for example the "9" 40// in OS X 10.9.5), and the "bugfix" component to indicate a "minor" release 41// (for example the "5" in OS X 10.9.5). 42class OSXVersion { 43 public: 44 static void Get(int32_t& aMajor, int32_t& aMinor); 45 46 private: 47 static void GetSystemVersion(int32_t& aMajor, int32_t& aMinor, int32_t& aBugFix); 48 static bool mCached; 49 static int32_t mOSXVersionMajor; 50 static int32_t mOSXVersionMinor; 51}; 52 53bool OSXVersion::mCached = false; 54int32_t OSXVersion::mOSXVersionMajor; 55int32_t OSXVersion::mOSXVersionMinor; 56 57void OSXVersion::Get(int32_t& aMajor, int32_t& aMinor) { 58 if (!mCached) { 59 int32_t major, minor, bugfix; 60 GetSystemVersion(major, minor, bugfix); 61 mOSXVersionMajor = major; 62 mOSXVersionMinor = minor; 63 mCached = true; 64 } 65 aMajor = mOSXVersionMajor; 66 aMinor = mOSXVersionMinor; 67} 68 69void OSXVersion::GetSystemVersion(int32_t& aMajor, int32_t& aMinor, int32_t& aBugFix) { 70 SInt32 major = 0, minor = 0, bugfix = 0; 71 72 CFURLRef url = CFURLCreateWithString( 73 kCFAllocatorDefault, CFSTR("file:///System/Library/CoreServices/SystemVersion.plist"), NULL); 74 CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, url); 75 CFReadStreamOpen(stream); 76 CFDictionaryRef sysVersionPlist = (CFDictionaryRef)CFPropertyListCreateWithStream( 77 kCFAllocatorDefault, stream, 0, kCFPropertyListImmutable, NULL, NULL); 78 CFReadStreamClose(stream); 79 CFRelease(stream); 80 CFRelease(url); 81 82 CFStringRef versionString = 83 (CFStringRef)CFDictionaryGetValue(sysVersionPlist, CFSTR("ProductVersion")); 84 CFArrayRef versions = 85 CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, versionString, CFSTR(".")); 86 CFIndex count = CFArrayGetCount(versions); 87 if (count > 0) { 88 CFStringRef component = (CFStringRef)CFArrayGetValueAtIndex(versions, 0); 89 major = CFStringGetIntValue(component); 90 if (count > 1) { 91 component = (CFStringRef)CFArrayGetValueAtIndex(versions, 1); 92 minor = CFStringGetIntValue(component); 93 if (count > 2) { 94 component = (CFStringRef)CFArrayGetValueAtIndex(versions, 2); 95 bugfix = CFStringGetIntValue(component); 96 } 97 } 98 } 99 CFRelease(sysVersionPlist); 100 CFRelease(versions); 101 102 if (major < 10) { 103 // If 'major' isn't what we expect, assume 10.6. 104 aMajor = 10; 105 aMinor = 6; 106 aBugFix = 0; 107 } else if ((major == 10) && (minor >= 16)) { 108 // Account for SystemVersionCompat.plist being used which is 109 // automatically used for builds using older SDK versions and 110 // results in 11.0 being reported as 10.16. Assume the compat 111 // version will increase in step with the correct version. 112 aMajor = 11; 113 aMinor = minor - 16; 114 aBugFix = bugfix; 115 } else { 116 aMajor = major; 117 aMinor = minor; 118 aBugFix = bugfix; 119 } 120} 121 122bool GetRealPath(std::string& aOutputPath, const char* aInputPath) { 123 char* resolvedPath = realpath(aInputPath, nullptr); 124 if (resolvedPath == nullptr) { 125 return false; 126 } 127 128 aOutputPath = resolvedPath; 129 free(resolvedPath); 130 131 return !aOutputPath.empty(); 132} 133 134void MacSandboxInfo::AppendAsParams(std::vector<std::string>& aParams) const { 135 this->AppendStartupParam(aParams); 136 this->AppendLoggingParam(aParams); 137 this->AppendAppPathParam(aParams); 138 139 switch (this->type) { 140 case MacSandboxType_Content: 141 this->AppendLevelParam(aParams); 142 this->AppendAudioParam(aParams); 143 this->AppendWindowServerParam(aParams); 144 this->AppendReadPathParams(aParams); 145#ifdef DEBUG 146 this->AppendDebugWriteDirParam(aParams); 147#endif 148 break; 149 case MacSandboxType_Utility: 150 case MacSandboxType_Socket: 151 break; 152 case MacSandboxType_GMP: 153 this->AppendPluginPathParam(aParams); 154 this->AppendWindowServerParam(aParams); 155 this->AppendReadPathParams(aParams); 156 break; 157 default: 158 // Before supporting a new process type, add a case statement 159 // here to append any neccesary process-type-specific params. 160 MOZ_RELEASE_ASSERT(false); 161 break; 162 } 163} 164 165void MacSandboxInfo::AppendStartupParam(std::vector<std::string>& aParams) const { 166 aParams.push_back("-sbStartup"); 167} 168 169void MacSandboxInfo::AppendLoggingParam(std::vector<std::string>& aParams) const { 170 if (this->shouldLog) { 171 aParams.push_back("-sbLogging"); 172 } 173} 174 175void MacSandboxInfo::AppendAppPathParam(std::vector<std::string>& aParams) const { 176 aParams.push_back("-sbAppPath"); 177 aParams.push_back(this->appPath); 178} 179 180void MacSandboxInfo::AppendPluginPathParam(std::vector<std::string>& aParams) const { 181 aParams.push_back("-sbPluginPath"); 182 aParams.push_back(this->pluginPath); 183} 184 185/* static */ 186void MacSandboxInfo::AppendFileAccessParam(std::vector<std::string>& aParams, 187 bool aHasFilePrivileges) { 188 if (aHasFilePrivileges) { 189 aParams.push_back("-sbAllowFileAccess"); 190 } 191} 192 193void MacSandboxInfo::AppendLevelParam(std::vector<std::string>& aParams) const { 194 std::ostringstream os; 195 os << this->level; 196 std::string levelString = os.str(); 197 aParams.push_back("-sbLevel"); 198 aParams.push_back(levelString); 199} 200 201void MacSandboxInfo::AppendAudioParam(std::vector<std::string>& aParams) const { 202 if (this->hasAudio) { 203 aParams.push_back("-sbAllowAudio"); 204 } 205} 206 207void MacSandboxInfo::AppendWindowServerParam(std::vector<std::string>& aParams) const { 208 if (this->hasWindowServer) { 209 aParams.push_back("-sbAllowWindowServer"); 210 } 211} 212 213void MacSandboxInfo::AppendReadPathParams(std::vector<std::string>& aParams) const { 214 if (!this->testingReadPath1.empty()) { 215 aParams.push_back("-sbTestingReadPath"); 216 aParams.push_back(this->testingReadPath1.c_str()); 217 } 218 if (!this->testingReadPath2.empty()) { 219 aParams.push_back("-sbTestingReadPath"); 220 aParams.push_back(this->testingReadPath2.c_str()); 221 } 222 if (!this->testingReadPath3.empty()) { 223 aParams.push_back("-sbTestingReadPath"); 224 aParams.push_back(this->testingReadPath3.c_str()); 225 } 226 if (!this->testingReadPath4.empty()) { 227 aParams.push_back("-sbTestingReadPath"); 228 aParams.push_back(this->testingReadPath4.c_str()); 229 } 230} 231 232#ifdef DEBUG 233void MacSandboxInfo::AppendDebugWriteDirParam(std::vector<std::string>& aParams) const { 234 if (!this->debugWriteDir.empty()) { 235 aParams.push_back("-sbDebugWriteDir"); 236 aParams.push_back(this->debugWriteDir.c_str()); 237 } 238} 239#endif 240 241namespace mozilla { 242 243bool StartMacSandbox(MacSandboxInfo const& aInfo, std::string& aErrorMessage) { 244 std::vector<const char*> params; 245 std::string profile; 246 247 // Use a combined version number to simplify version check logic 248 // in sandbox policies. For example, 10.14 becomes "1014". 249 int32_t major = 0, minor = 0; 250 OSXVersion::Get(major, minor); 251 MOZ_ASSERT(minor >= 0 && minor < 100); 252 std::string combinedVersion = std::to_string((major * 100) + minor); 253 254 // Used for the Flash sandbox. Declared here so that they 255 // stay in scope until sandbox_init_with_parameters is called. 256 std::string flashCacheDir, flashTempDir, flashPath; 257 258 if (aInfo.type == MacSandboxType_Flash) { 259 profile = SandboxPolicyFlash; 260 261 params.push_back("SHOULD_LOG"); 262 params.push_back(aInfo.shouldLog ? "TRUE" : "FALSE"); 263 264 params.push_back("SANDBOX_LEVEL_1"); 265 params.push_back(aInfo.level == 1 ? "TRUE" : "FALSE"); 266 params.push_back("SANDBOX_LEVEL_2"); 267 params.push_back(aInfo.level == 2 ? "TRUE" : "FALSE"); 268 269 params.push_back("MAC_OS_VERSION"); 270 params.push_back(combinedVersion.c_str()); 271 272 params.push_back("HOME_PATH"); 273 params.push_back(getenv("HOME")); 274 275 params.push_back("PLUGIN_BINARY_PATH"); 276 if (!GetRealPath(flashPath, aInfo.pluginBinaryPath.c_str())) { 277 return false; 278 } 279 params.push_back(flashPath.c_str()); 280 281 // User cache dir 282 params.push_back("DARWIN_USER_CACHE_DIR"); 283 char confStrBuf[PATH_MAX]; 284 if (!confstr(_CS_DARWIN_USER_CACHE_DIR, confStrBuf, sizeof(confStrBuf))) { 285 return false; 286 } 287 if (!GetRealPath(flashCacheDir, confStrBuf)) { 288 return false; 289 } 290 params.push_back(flashCacheDir.c_str()); 291 292 // User temp dir 293 params.push_back("DARWIN_USER_TEMP_DIR"); 294 if (!confstr(_CS_DARWIN_USER_TEMP_DIR, confStrBuf, sizeof(confStrBuf))) { 295 return false; 296 } 297 if (!GetRealPath(flashTempDir, confStrBuf)) { 298 return false; 299 } 300 params.push_back(flashTempDir.c_str()); 301 } else if (aInfo.type == MacSandboxType_Utility) { 302 profile = const_cast<char*>(SandboxPolicyUtility); 303 params.push_back("SHOULD_LOG"); 304 params.push_back(aInfo.shouldLog ? "TRUE" : "FALSE"); 305 params.push_back("APP_PATH"); 306 params.push_back(aInfo.appPath.c_str()); 307 if (!aInfo.crashServerPort.empty()) { 308 params.push_back("CRASH_PORT"); 309 params.push_back(aInfo.crashServerPort.c_str()); 310 } 311 } else if (aInfo.type == MacSandboxType_Socket) { 312 profile = const_cast<char*>(SandboxPolicySocket); 313 params.push_back("SHOULD_LOG"); 314 params.push_back(aInfo.shouldLog ? "TRUE" : "FALSE"); 315 params.push_back("APP_PATH"); 316 params.push_back(aInfo.appPath.c_str()); 317 if (!aInfo.crashServerPort.empty()) { 318 params.push_back("CRASH_PORT"); 319 params.push_back(aInfo.crashServerPort.c_str()); 320 } 321 params.push_back("HOME_PATH"); 322 params.push_back(getenv("HOME")); 323 } else if (aInfo.type == MacSandboxType_GMP) { 324 profile = const_cast<char*>(SandboxPolicyGMP); 325 params.push_back("SHOULD_LOG"); 326 params.push_back(aInfo.shouldLog ? "TRUE" : "FALSE"); 327 params.push_back("APP_PATH"); 328 params.push_back(aInfo.appPath.c_str()); 329 params.push_back("PLUGIN_PATH"); 330 params.push_back(aInfo.pluginPath.c_str()); 331 if (!aInfo.pluginBinaryPath.empty()) { 332 params.push_back("PLUGIN_BINARY_PATH"); 333 params.push_back(aInfo.pluginBinaryPath.c_str()); 334 } 335 params.push_back("HAS_WINDOW_SERVER"); 336 params.push_back(aInfo.hasWindowServer ? "TRUE" : "FALSE"); 337 if (!aInfo.crashServerPort.empty()) { 338 params.push_back("CRASH_PORT"); 339 params.push_back(aInfo.crashServerPort.c_str()); 340 } 341 if (!aInfo.testingReadPath1.empty()) { 342 params.push_back("TESTING_READ_PATH1"); 343 params.push_back(aInfo.testingReadPath1.c_str()); 344 } 345 if (!aInfo.testingReadPath2.empty()) { 346 params.push_back("TESTING_READ_PATH2"); 347 params.push_back(aInfo.testingReadPath2.c_str()); 348 } 349 } else if (aInfo.type == MacSandboxType_Content) { 350 MOZ_ASSERT(aInfo.level >= 1); 351 if (aInfo.level >= 1) { 352 profile = SandboxPolicyContent; 353 params.push_back("SHOULD_LOG"); 354 params.push_back(aInfo.shouldLog ? "TRUE" : "FALSE"); 355 params.push_back("SANDBOX_LEVEL_1"); 356 params.push_back(aInfo.level == 1 ? "TRUE" : "FALSE"); 357 params.push_back("SANDBOX_LEVEL_2"); 358 params.push_back(aInfo.level == 2 ? "TRUE" : "FALSE"); 359 params.push_back("SANDBOX_LEVEL_3"); 360 params.push_back(aInfo.level == 3 ? "TRUE" : "FALSE"); 361 params.push_back("MAC_OS_VERSION"); 362 params.push_back(combinedVersion.c_str()); 363 params.push_back("APP_PATH"); 364 params.push_back(aInfo.appPath.c_str()); 365 params.push_back("PROFILE_DIR"); 366 params.push_back(aInfo.profileDir.c_str()); 367 params.push_back("HOME_PATH"); 368 params.push_back(getenv("HOME")); 369 params.push_back("HAS_SANDBOXED_PROFILE"); 370 params.push_back(aInfo.hasSandboxedProfile ? "TRUE" : "FALSE"); 371 params.push_back("HAS_WINDOW_SERVER"); 372 params.push_back(aInfo.hasWindowServer ? "TRUE" : "FALSE"); 373 if (!aInfo.crashServerPort.empty()) { 374 params.push_back("CRASH_PORT"); 375 params.push_back(aInfo.crashServerPort.c_str()); 376 } 377 if (!aInfo.testingReadPath1.empty()) { 378 params.push_back("TESTING_READ_PATH1"); 379 params.push_back(aInfo.testingReadPath1.c_str()); 380 } 381 if (!aInfo.testingReadPath2.empty()) { 382 params.push_back("TESTING_READ_PATH2"); 383 params.push_back(aInfo.testingReadPath2.c_str()); 384 } 385 if (!aInfo.testingReadPath3.empty()) { 386 params.push_back("TESTING_READ_PATH3"); 387 params.push_back(aInfo.testingReadPath3.c_str()); 388 } 389 if (!aInfo.testingReadPath4.empty()) { 390 params.push_back("TESTING_READ_PATH4"); 391 params.push_back(aInfo.testingReadPath4.c_str()); 392 } 393#ifdef DEBUG 394 if (!aInfo.debugWriteDir.empty()) { 395 params.push_back("DEBUG_WRITE_DIR"); 396 params.push_back(aInfo.debugWriteDir.c_str()); 397 } 398#endif // DEBUG 399 400 if (aInfo.hasFilePrivileges) { 401 profile.append(SandboxPolicyContentFileAddend); 402 } 403 if (aInfo.hasAudio) { 404 profile.append(SandboxPolicyContentAudioAddend); 405 } 406 } else { 407 fprintf(stderr, "Content sandbox disabled due to sandbox level setting\n"); 408 return false; 409 } 410 } else { 411 char* msg = NULL; 412 asprintf(&msg, "Unexpected sandbox type %u", aInfo.type); 413 if (msg) { 414 aErrorMessage.assign(msg); 415 free(msg); 416 } 417 return false; 418 } 419 420 if (profile.empty()) { 421 fprintf(stderr, "Out of memory in StartMacSandbox()!\n"); 422 return false; 423 } 424 425// In order to avoid relying on any other Mozilla modules (as described at the 426// top of this file), we use our own #define instead of the existing MOZ_LOG 427// infrastructure. This can be used by developers to debug the macOS sandbox 428// policy. 429#define MAC_SANDBOX_PRINT_POLICY 0 430#if MAC_SANDBOX_PRINT_POLICY 431 printf("Sandbox params for PID %d:\n", getpid()); 432 for (size_t i = 0; i < params.size() / 2; i++) { 433 printf(" %s = %s\n", params[i * 2], params[(i * 2) + 1]); 434 } 435 printf("Sandbox profile:\n%s\n", profile.c_str()); 436#endif 437 438 // The parameters array is null terminated. 439 params.push_back(nullptr); 440 441 char* errorbuf = NULL; 442 int rv = sandbox_init_with_parameters(profile.c_str(), 0, params.data(), &errorbuf); 443 if (rv) { 444 if (errorbuf) { 445 char* msg = NULL; 446 asprintf(&msg, "sandbox_init() failed with error \"%s\"", errorbuf); 447 if (msg) { 448 aErrorMessage.assign(msg); 449 free(msg); 450 } 451 fprintf(stderr, "profile: %s\n", profile.c_str()); 452 sandbox_free_error(errorbuf); 453 } 454 } 455 if (rv) { 456 return false; 457 } 458 459 return true; 460} 461 462/* 463 * Fill |aInfo| with content sandbox params parsed from the provided 464 * command line arguments. Return false if any sandbox parameters needed 465 * for early startup of the sandbox are not present in the arguments. 466 */ 467bool GetContentSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo) { 468 // Ensure we find these paramaters in the command 469 // line arguments. Return false if any are missing. 470 bool foundSandboxLevel = false; 471 bool foundValidSandboxLevel = false; 472 bool foundAppPath = false; 473 474 // Read access directories used in testing 475 int nTestingReadPaths = 0; 476 std::string testingReadPaths[MAX_CONTENT_TESTING_READ_PATHS] = {}; 477 478 // Collect sandbox params from CLI arguments 479 for (int i = 0; i < aArgc; i++) { 480 if ((strcmp(aArgv[i], "-sbLevel") == 0) && (i + 1 < aArgc)) { 481 std::stringstream ss(aArgv[i + 1]); 482 int level = 0; 483 ss >> level; 484 foundSandboxLevel = true; 485 aInfo.level = level; 486 foundValidSandboxLevel = level > 0 && level <= 3 ? true : false; 487 if (!foundValidSandboxLevel) { 488 break; 489 } 490 i++; 491 continue; 492 } 493 494 if (strcmp(aArgv[i], "-sbLogging") == 0) { 495 aInfo.shouldLog = true; 496 continue; 497 } 498 499 if (strcmp(aArgv[i], "-sbAllowFileAccess") == 0) { 500 aInfo.hasFilePrivileges = true; 501 continue; 502 } 503 504 if (strcmp(aArgv[i], "-sbAllowAudio") == 0) { 505 aInfo.hasAudio = true; 506 continue; 507 } 508 509 if (strcmp(aArgv[i], "-sbAllowWindowServer") == 0) { 510 aInfo.hasWindowServer = true; 511 continue; 512 } 513 514 if ((strcmp(aArgv[i], "-sbAppPath") == 0) && (i + 1 < aArgc)) { 515 foundAppPath = true; 516 aInfo.appPath.assign(aArgv[i + 1]); 517 i++; 518 continue; 519 } 520 521 if ((strcmp(aArgv[i], "-sbTestingReadPath") == 0) && (i + 1 < aArgc)) { 522 if (nTestingReadPaths >= MAX_CONTENT_TESTING_READ_PATHS) { 523 MOZ_CRASH("Too many content process -sbTestingReadPath arguments"); 524 } 525 testingReadPaths[nTestingReadPaths] = aArgv[i + 1]; 526 nTestingReadPaths++; 527 i++; 528 continue; 529 } 530 531 if ((strcmp(aArgv[i], "-profile") == 0) && (i + 1 < aArgc)) { 532 aInfo.hasSandboxedProfile = true; 533 aInfo.profileDir.assign(aArgv[i + 1]); 534 i++; 535 continue; 536 } 537 538#ifdef DEBUG 539 if ((strcmp(aArgv[i], "-sbDebugWriteDir") == 0) && (i + 1 < aArgc)) { 540 aInfo.debugWriteDir.assign(aArgv[i + 1]); 541 i++; 542 continue; 543 } 544#endif // DEBUG 545 546 // Handle crash server positional argument 547 if (strstr(aArgv[i], "gecko-crash-server-pipe") != NULL) { 548 aInfo.crashServerPort.assign(aArgv[i]); 549 continue; 550 } 551 } 552 553 if (!foundSandboxLevel) { 554 fprintf(stderr, "Content sandbox disabled due to " 555 "missing sandbox CLI level parameter.\n"); 556 return false; 557 } 558 559 if (!foundValidSandboxLevel) { 560 fprintf(stderr, 561 "Content sandbox disabled due to invalid" 562 "sandbox level (%d)\n", 563 aInfo.level); 564 return false; 565 } 566 567 if (!foundAppPath) { 568 fprintf(stderr, "Content sandbox disabled due to " 569 "missing sandbox CLI app path parameter.\n"); 570 return false; 571 } 572 573 aInfo.testingReadPath1 = testingReadPaths[0]; 574 aInfo.testingReadPath2 = testingReadPaths[1]; 575 aInfo.testingReadPath3 = testingReadPaths[2]; 576 aInfo.testingReadPath4 = testingReadPaths[3]; 577 578 return true; 579} 580 581bool GetUtilitySandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo) { 582 // Ensure we find these paramaters in the command 583 // line arguments. Return false if any are missing. 584 bool foundAppPath = false; 585 586 // Collect sandbox params from CLI arguments 587 for (int i = 0; i < aArgc; i++) { 588 if (strcmp(aArgv[i], "-sbLogging") == 0) { 589 aInfo.shouldLog = true; 590 continue; 591 } 592 593 if ((strcmp(aArgv[i], "-sbAppPath") == 0) && (i + 1 < aArgc)) { 594 foundAppPath = true; 595 aInfo.appPath.assign(aArgv[i + 1]); 596 i++; 597 continue; 598 } 599 600 // Handle crash server positional argument 601 if (strstr(aArgv[i], "gecko-crash-server-pipe") != NULL) { 602 aInfo.crashServerPort.assign(aArgv[i]); 603 continue; 604 } 605 } 606 607 if (!foundAppPath) { 608 fprintf(stderr, "Utility sandbox disabled due to " 609 "missing sandbox CLI app path parameter.\n"); 610 return false; 611 } 612 613 return true; 614} 615 616bool GetSocketSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo) { 617 return GetUtilitySandboxParamsFromArgs(aArgc, aArgv, aInfo); 618} 619 620bool GetPluginSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo) { 621 // Ensure we find these paramaters in the command 622 // line arguments. Return false if any are missing. 623 bool foundAppPath = false; 624 bool foundPluginPath = false; 625 626 // Read access directories used in testing 627 int nTestingReadPaths = 0; 628 std::string testingReadPaths[MAX_GMP_TESTING_READ_PATHS] = {}; 629 630 // Collect sandbox params from CLI arguments 631 for (int i = 0; i < aArgc; i++) { 632 if (strcmp(aArgv[i], "-sbLogging") == 0) { 633 aInfo.shouldLog = true; 634 continue; 635 } 636 637 if ((strcmp(aArgv[i], "-sbAppPath") == 0) && (i + 1 < aArgc)) { 638 foundAppPath = true; 639 aInfo.appPath.assign(aArgv[i + 1]); 640 i++; 641 continue; 642 } 643 644 if ((strcmp(aArgv[i], "-sbPluginPath") == 0) && (i + 1 < aArgc)) { 645 foundPluginPath = true; 646 aInfo.pluginPath.assign(aArgv[i + 1]); 647 i++; 648 continue; 649 } 650 651 if (strcmp(aArgv[i], "-sbAllowWindowServer") == 0) { 652 aInfo.hasWindowServer = true; 653 continue; 654 } 655 656 if ((strcmp(aArgv[i], "-sbTestingReadPath") == 0) && (i + 1 < aArgc)) { 657 if (nTestingReadPaths >= MAX_GMP_TESTING_READ_PATHS) { 658 MOZ_CRASH("Too many GMP process -sbTestingReadPath arguments"); 659 } 660 testingReadPaths[nTestingReadPaths] = aArgv[i + 1]; 661 nTestingReadPaths++; 662 i++; 663 continue; 664 } 665 666 // Handle crash server positional argument 667 if (strstr(aArgv[i], "gecko-crash-server-pipe") != NULL) { 668 aInfo.crashServerPort.assign(aArgv[i]); 669 continue; 670 } 671 } 672 673 if (!foundPluginPath) { 674 fprintf(stderr, "GMP sandbox disabled due to " 675 "missing sandbox CLI plugin path parameter.\n"); 676 return false; 677 } 678 679 if (!foundAppPath) { 680 fprintf(stderr, "GMP sandbox disabled due to " 681 "missing sandbox CLI app path parameter.\n"); 682 return false; 683 } 684 685 aInfo.testingReadPath1 = testingReadPaths[0]; 686 aInfo.testingReadPath2 = testingReadPaths[1]; 687 688 return true; 689} 690 691/* 692 * Returns true if no errors were encountered or if early sandbox startup is 693 * not enabled for this process. Returns false if an error was encountered. 694 */ 695bool StartMacSandboxIfEnabled(const MacSandboxType aSandboxType, int aArgc, char** aArgv, 696 std::string& aErrorMessage) { 697 bool earlyStartupEnabled = false; 698 699 // Check for the -sbStartup CLI parameter which 700 // indicates we should start the sandbox now. 701 for (int i = 0; i < aArgc; i++) { 702 if (strcmp(aArgv[i], "-sbStartup") == 0) { 703 earlyStartupEnabled = true; 704 break; 705 } 706 } 707 708 // The sandbox will be started later when/if parent 709 // sends the sandbox startup message. Return true 710 // indicating no errors occurred. 711 if (!earlyStartupEnabled) { 712 return true; 713 } 714 715 MacSandboxInfo info; 716 info.type = aSandboxType; 717 718 // For now, early start is only implemented 719 // for content and utility sandbox types. 720 switch (aSandboxType) { 721 case MacSandboxType_Content: 722 if (!GetContentSandboxParamsFromArgs(aArgc, aArgv, info)) { 723 return false; 724 } 725 break; 726 case MacSandboxType_Utility: 727 if (!GetUtilitySandboxParamsFromArgs(aArgc, aArgv, info)) { 728 return false; 729 } 730 break; 731 case MacSandboxType_Socket: 732 if (!GetSocketSandboxParamsFromArgs(aArgc, aArgv, info)) { 733 return false; 734 } 735 break; 736 case MacSandboxType_GMP: 737 if (!GetPluginSandboxParamsFromArgs(aArgc, aArgv, info)) { 738 return false; 739 } 740 break; 741 default: 742 MOZ_RELEASE_ASSERT(false); 743 break; 744 } 745 746 return StartMacSandbox(info, aErrorMessage); 747} 748 749bool IsMacSandboxStarted() { return sandbox_check(getpid(), NULL, 0) == 1; } 750 751#ifdef DEBUG 752// sandbox_check returns 1 if the specified process is sandboxed 753void AssertMacSandboxEnabled() { MOZ_ASSERT(sandbox_check(getpid(), NULL, 0) == 1); } 754#endif /* DEBUG */ 755 756} // namespace mozilla 757