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