Bug 1284897 - Add mechanism to libsandbox_s to track names of files that have been given special sandbox access permissions (PermissionsService). r=bobowen, r=glandium
authorDavid Parks <dparks@mozilla.com>
Tue, 14 Feb 2017 15:08:40 -0800
changeset 373429 7be63656e4fbefdebceb297ca4388ef5f2b884d0
parent 373428 e2609138ebe19488f0937ea8782fc0f9cb6e8de8
child 373430 6ecd19d2582250b42ff890660eb33109c3bf062c
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbobowen, glandium
bugs1284897
milestone54.0a1
Bug 1284897 - Add mechanism to libsandbox_s to track names of files that have been given special sandbox access permissions (PermissionsService). r=bobowen, r=glandium Hook this into the browser via the XREAppData. This patch does not include the changes to Chromium source code.
browser/app/nsBrowserApp.cpp
security/sandbox/chromium-shim/sandbox/win/permissionsService.cpp
security/sandbox/chromium-shim/sandbox/win/permissionsService.h
security/sandbox/moz.build
security/sandbox/win/SandboxInitialization.cpp
security/sandbox/win/SandboxInitialization.h
security/sandbox/win/src/sandboxpermissions/moz.build
security/sandbox/win/src/sandboxpermissions/sandboxPermissions.cpp
security/sandbox/win/src/sandboxpermissions/sandboxPermissions.h
toolkit/xre/Bootstrap.h
toolkit/xre/nsAppRunner.cpp
xpcom/build/XREAppData.h
xpcom/glue/XREAppData.cpp
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -212,23 +212,26 @@ static int do_main(int argc, char* argv[
     // no -app flag so we use the compiled-in app data
     config.appData = &sAppData;
     config.appDataPath = kDesktopFolder;
   }
 
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
   sandbox::BrokerServices* brokerServices =
     sandboxing::GetInitializedBrokerServices();
+  sandboxing::PermissionsService* permissionsService =
+    sandboxing::GetPermissionsService();
 #if defined(MOZ_CONTENT_SANDBOX)
   if (!brokerServices) {
     Output("Couldn't initialize the broker services.\n");
     return 255;
   }
 #endif
   config.sandboxBrokerServices = brokerServices;
+  config.sandboxPermissionsService = permissionsService;
 #endif
 
 #ifdef LIBFUZZER
   if (getenv("LIBFUZZER"))
     gBootstrap->XRE_LibFuzzerSetDriver(fuzzer::FuzzerDriver);
 #endif
 
   return gBootstrap->XRE_main(argc, argv, config);
new file mode 100644
--- /dev/null
+++ b/security/sandbox/chromium-shim/sandbox/win/permissionsService.cpp
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* SandboxPermissions.cpp - Special permissions granted to sandboxed processes */
+
+#include "permissionsService.h"
+#include <algorithm>
+#include <winternl.h>
+
+namespace mozilla {
+namespace sandboxing {
+
+static const std::wstring ZONE_IDENTIFIER_STR(L":ZONE.IDENTIFIER");
+static const std::wstring ZONE_ID_DATA_STR(L":ZONE.IDENTIFIER:$DATA");
+
+bool
+StringEndsWith(const std::wstring& str, const std::wstring& strEnding)
+{
+  if (strEnding.size() > str.size()) {
+    return false;
+  }
+  return std::equal(strEnding.rbegin(), strEnding.rend(), str.rbegin());
+}
+
+// Converts NT device internal filenames to normal user-space by stripping
+// the prefixes and suffixes from the file name.
+std::wstring
+GetPlainFileName(const wchar_t* aNTFileName)
+{
+  while (*aNTFileName == L'\\' || *aNTFileName == L'.' ||
+         *aNTFileName == L'?' || *aNTFileName == L':' ) {
+    ++aNTFileName;
+  }
+  std::wstring nameCopy(aNTFileName);
+  std::transform(nameCopy.begin(), nameCopy.end(), nameCopy.begin(), towupper);
+  if (StringEndsWith(nameCopy, ZONE_ID_DATA_STR)) {
+    nameCopy = nameCopy.substr(0, nameCopy.size() - ZONE_ID_DATA_STR.size());
+  } else if (StringEndsWith(nameCopy, ZONE_IDENTIFIER_STR)) {
+    nameCopy = nameCopy.substr(0, nameCopy.size() - ZONE_IDENTIFIER_STR.size());
+  }
+  return nameCopy;
+}
+
+/* static */ PermissionsService*
+PermissionsService::GetInstance()
+{
+  static PermissionsService sPermissionsService;
+  return &sPermissionsService;
+}
+
+PermissionsService::PermissionsService() :
+  mFileAccessViolationFunc(nullptr)
+{
+}
+
+void
+PermissionsService::GrantFileAccess(uint32_t aProcessId,
+                                    const wchar_t* aFilename,
+                                    bool aPermitWrite)
+{
+  FilePermissionMap& permissions = mProcessFilePermissions[aProcessId];
+  std::wstring filename = GetPlainFileName(aFilename);
+  permissions[filename] |= aPermitWrite;
+}
+
+void
+PermissionsService::SetFileAccessViolationFunc(FileAccessViolationFunc aFavFunc)
+{
+  mFileAccessViolationFunc = aFavFunc;
+}
+
+void
+PermissionsService::ReportBlockedFile(bool aNeedsWrite)
+{
+  if (mFileAccessViolationFunc) {
+    mFileAccessViolationFunc(aNeedsWrite);
+  }
+}
+
+bool
+PermissionsService::UserGrantedFileAccess(uint32_t aProcessId,
+                                          const wchar_t* aFilename,
+                                          uint32_t aAccess,
+                                          uint32_t aDisposition)
+{
+  // There are 3 types of permissions:
+  // * Those available w/ read-only permission
+  // * Those available w/ read-only AND read-write permission
+  // * Those always forbidden.
+  const uint32_t FORBIDDEN_FLAGS =
+    FILE_EXECUTE | FILE_LIST_DIRECTORY | FILE_TRAVERSE | STANDARD_RIGHTS_EXECUTE;
+  const uint32_t NEEDS_WRITE_FLAGS =
+    FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA |
+    DELETE | STANDARD_RIGHTS_WRITE;
+  bool needsWrite =
+    (aAccess & NEEDS_WRITE_FLAGS) || (aDisposition != FILE_OPEN);
+
+  if (aAccess & FORBIDDEN_FLAGS) {
+    ReportBlockedFile(needsWrite);
+    return false;
+  }
+
+  auto permissions = mProcessFilePermissions.find(aProcessId);
+  if (permissions == mProcessFilePermissions.end()) {
+    ReportBlockedFile(needsWrite);
+    return false;  // process has no special file access at all
+  }
+
+  std::wstring filename = GetPlainFileName(aFilename);
+  auto itPermission = permissions->second.find(filename);
+  if (itPermission == permissions->second.end()) {
+    ReportBlockedFile(needsWrite);
+    return false;  // process has no access to this file
+  }
+
+  // We have read permission.  Check for write permission if requested.
+  if (!needsWrite || itPermission->second) {
+    return true;
+  }
+
+  // We needed write access but didn't have it.
+  ReportBlockedFile(needsWrite);
+  return false;
+}
+
+void
+PermissionsService::RemovePermissionsForProcess(uint32_t aProcessId)
+{
+  mProcessFilePermissions.erase(aProcessId);
+}
+
+}   // namespace sandboxing
+}   // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/security/sandbox/chromium-shim/sandbox/win/permissionsService.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_sandboxing_permissionsService_h
+#define mozilla_sandboxing_permissionsService_h
+
+#include <unordered_map>
+
+namespace mozilla {
+namespace sandboxing {
+
+/*
+ * Represents additional permissions granted to sandboxed processes.
+ * The members are virtual so that the object can be created in any
+ * library that links with libsandbox_s and then shared with and used
+ * by libXUL, which does not link with libsandbox_s.
+ */
+class PermissionsService
+{
+public:
+  static PermissionsService* GetInstance();
+
+  /*
+   * Allow future access to aFilename by the plugin process.
+   */
+  virtual void GrantFileAccess(uint32_t aProcessId, const wchar_t* aFilename,
+                               bool aPermitWrite);
+
+  /*
+   * Type of callback function that the sandbox uses to report file
+   * accesses that were denied.
+   * Parameter is a boolean indicating the access request was read-only
+   * (false) or read-write (true)
+   */
+  typedef void (*FileAccessViolationFunc)(bool);
+
+  /*
+   * Sets the callback function that is called whenever a file access is
+   * denied by the sandbox.
+   */
+  virtual void SetFileAccessViolationFunc(FileAccessViolationFunc aFavFunc);
+
+  /*
+   * Returns true if the user has granted the sandboxed plugin process the
+   * requested permission to open the file.
+   * Calls aFavFunc with file info if the file access was blocked.
+   */
+  virtual bool UserGrantedFileAccess(uint32_t aProcessId, const wchar_t* aFilename,
+                                     uint32_t aAccess, uint32_t aDisposition);
+
+  /*
+   * Clears all special file access for the given plugin process.
+   */
+  virtual void RemovePermissionsForProcess(uint32_t aProcessId);
+
+private:
+  PermissionsService();
+  void ReportBlockedFile(bool aNeedsWrite);
+
+  // Maps from filenames to a boolean indicating read-only permission (false) or
+  // read-write permission (true).
+  typedef std::unordered_map<std::wstring, bool> FilePermissionMap;
+
+  // Maps from process ID to map of user-granted file permissions for
+  // that process.
+  typedef std::unordered_map<uint32_t, FilePermissionMap> ProcessFilePermissionMap;
+
+  ProcessFilePermissionMap mProcessFilePermissions;
+  FileAccessViolationFunc mFileAccessViolationFunc;
+};
+
+} // namespace sandboxing
+} // namespace mozilla
+
+#endif // mozilla_sandboxing_permissionsService_h
--- a/security/sandbox/moz.build
+++ b/security/sandbox/moz.build
@@ -14,33 +14,36 @@ if CONFIG['OS_ARCH'] == 'Linux':
 elif CONFIG['OS_ARCH'] == 'Darwin':
     DIRS += ['mac']
 elif CONFIG['OS_ARCH'] == 'WINNT':
     Library('sandbox_s')
     FORCE_STATIC_LIB = True
 
     DIRS += [
         'win/src/sandboxbroker',
+        'win/src/sandboxpermissions',
         'win/src/sandboxtarget',
     ]
 
     if (CONFIG['CPU_ARCH'] == 'x86' and CONFIG['_MSC_VER'] and not
             CONFIG['CLANG_CL']):
         DIRS += ['win/wow_helper']
 
     EXPORTS.mozilla.sandboxing += [
         'chromium-shim/sandbox/win/loggingCallbacks.h',
         'chromium-shim/sandbox/win/loggingTypes.h',
+        'chromium-shim/sandbox/win/permissionsService.h',
         'chromium-shim/sandbox/win/sandboxLogging.h',
         'win/SandboxInitialization.h',
     ]
 
     SOURCES += [
         'chromium-shim/base/files/file_path.cpp',
         'chromium-shim/base/logging.cpp',
+        'chromium-shim/sandbox/win/permissionsService.cpp',
         'chromium-shim/sandbox/win/sandboxLogging.cpp',
         'chromium/base/at_exit.cc',
         'chromium/base/base_switches.cc',
         'chromium/base/callback_internal.cc',
         'chromium/base/cpu.cc',
         'chromium/base/debug/alias.cc',
         'chromium/base/debug/profiler.cc',
         'chromium/base/hash.cc',
--- a/security/sandbox/win/SandboxInitialization.cpp
+++ b/security/sandbox/win/SandboxInitialization.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SandboxInitialization.h"
 
 #include "sandbox/win/src/sandbox_factory.h"
+#include "mozilla/sandboxing/permissionsService.h"
 
 namespace mozilla {
 namespace sandboxing {
 
 static sandbox::TargetServices*
 InitializeTargetServices()
 {
   sandbox::TargetServices* targetServices =
@@ -72,10 +73,15 @@ sandbox::BrokerServices*
 GetInitializedBrokerServices()
 {
   static sandbox::BrokerServices* sInitializedBrokerServices =
     InitializeBrokerServices();
 
   return sInitializedBrokerServices;
 }
 
+PermissionsService* GetPermissionsService()
+{
+  return PermissionsService::GetInstance();
+}
+
 } // sandboxing
 } // mozilla
--- a/security/sandbox/win/SandboxInitialization.h
+++ b/security/sandbox/win/SandboxInitialization.h
@@ -16,16 +16,18 @@ class TargetServices;
 // function defined in one of the Chromium sandbox cc files.
 extern "C" bool IsSandboxedProcess();
 
 namespace mozilla {
 // Note the Chromium code just uses a bare sandbox namespace, which makes using
 // sandbox for our namespace painful.
 namespace sandboxing {
 
+class PermissionsService;
+
 /**
  * Initializes (if required) and returns the Chromium sandbox TargetServices.
  *
  * @return the TargetServices or null if the creation or initialization failed.
  */
 sandbox::TargetServices* GetInitializedTargetServices();
 
 /**
@@ -36,12 +38,14 @@ void LowerSandbox();
 
 /**
  * Initializes (if required) and returns the Chromium sandbox BrokerServices.
  *
  * @return the BrokerServices or null if the creation or initialization failed.
  */
 sandbox::BrokerServices* GetInitializedBrokerServices();
 
+PermissionsService* GetPermissionsService();
+
 } // sandboxing
 } // mozilla
 
 #endif // mozilla_sandboxing_SandboxInitialization_h
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/sandboxpermissions/moz.build
@@ -0,0 +1,22 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+SOURCES += [
+    'sandboxPermissions.cpp',
+]
+
+EXPORTS += [
+    'sandboxPermissions.h',
+]
+
+for var in ('UNICODE', '_UNICODE'):
+    DEFINES[var] = True
+
+LOCAL_INCLUDES += [
+    '/security/sandbox/win',
+]
+
+FINAL_LIBRARY = 'xul'
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/sandboxpermissions/sandboxPermissions.cpp
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "sandboxPermissions.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/sandboxing/permissionsService.h"
+
+namespace mozilla
+{
+
+sandboxing::PermissionsService* SandboxPermissions::sPermissionsService = nullptr;
+
+void
+SandboxPermissions::Initialize(sandboxing::PermissionsService* aPermissionsService,
+                               FileAccessViolationFunc aFileAccessViolationFunc)
+{
+  sPermissionsService = aPermissionsService;
+  sPermissionsService->SetFileAccessViolationFunc(aFileAccessViolationFunc);
+}
+
+void
+SandboxPermissions::GrantFileAccess(uint32_t aProcessId, const wchar_t* aFilename,
+                                    bool aPermitWrite)
+{
+  MOZ_ASSERT(sPermissionsService, "Must initialize sandbox PermissionsService");
+  sPermissionsService->GrantFileAccess(aProcessId, aFilename, aPermitWrite);
+}
+
+void
+SandboxPermissions::RemovePermissionsForProcess(uint32_t aProcessId)
+{
+  if (!sPermissionsService) {
+    return;   // No permissions service was initialized
+  }
+  sPermissionsService->RemovePermissionsForProcess(aProcessId);
+}
+
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/sandboxpermissions/sandboxPermissions.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_sandboxing_sandboxPermissions_h
+#define mozilla_sandboxing_sandboxPermissions_h
+
+#include <stdint.h>
+#include <windows.h>
+
+namespace mozilla {
+
+namespace sandboxing {
+  class PermissionsService;
+}
+
+/*
+ * This object wraps a PermissionsService object.  This object is available
+ * in libXUL but PermissionsService is not.
+ */
+class SandboxPermissions
+{
+public:
+  /*
+   * Type of callback function that the sandbox uses to report file
+   * accesses that were denied.
+   * Parameter is a boolean indicating the access request was read-only
+   * (false) or read-write (true)
+   */
+  typedef void (*FileAccessViolationFunc)(bool);
+
+  /*
+   * Prepare this object by providing it with the internal permissions service.
+   */
+  static void Initialize(sandboxing::PermissionsService* aPermissionsService,
+                         FileAccessViolationFunc aFileAccessViolationFunc);
+
+  /*
+   * Allow future access to aFilename by the process with the given ID.
+   */
+  void GrantFileAccess(uint32_t aProcessId, const wchar_t* aFilename,
+                       bool aPermitWrite);
+
+  /*
+   * Clears all special file access for the given process.
+   */
+  void RemovePermissionsForProcess(uint32_t aProcessId);
+
+private:
+  static sandboxing::PermissionsService* sPermissionsService;
+};
+
+} // mozilla
+
+#endif  // mozilla_sandboxing_sandboxPermissions_h
--- a/toolkit/xre/Bootstrap.h
+++ b/toolkit/xre/Bootstrap.h
@@ -26,21 +26,28 @@ void GeckoStart(JNIEnv* aEnv, char** arg
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
 namespace sandbox {
 class BrokerServices;
 }
 #endif
 
 namespace mozilla {
 
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+namespace sandboxing {
+class PermissionsService;
+}
+#endif
+
 struct BootstrapConfig
 {
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
   /* Chromium sandbox BrokerServices. */
   sandbox::BrokerServices* sandboxBrokerServices;
+  sandboxing::PermissionsService* sandboxPermissionsService;
 #endif
   /* Pointer to static XRE AppData from application.ini.h */
   const StaticXREAppData* appData;
   /* When the pointer above is null, points to the (string) path of an
    * application.ini file to open and parse.
    * When the pointer above is non-null, may indicate the directory where
    * application files are, relative to the XRE. */
   const char* appDataPath;
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -210,16 +210,17 @@
 #include "GeneratedJNIWrappers.h"
 #endif
 
 #if defined(MOZ_SANDBOX)
 #if defined(XP_LINUX) && !defined(ANDROID)
 #include "mozilla/SandboxInfo.h"
 #elif defined(XP_WIN)
 #include "SandboxBroker.h"
+#include "SandboxPermissions.h"
 #endif
 #endif
 
 extern uint32_t gRestartMode;
 extern void InstallSignalHandlers(const char *ProgramName);
 
 #define FILE_COMPATIBILITY_INFO NS_LITERAL_CSTRING("compatibility.ini")
 #define FILE_INVALIDATE_CACHES NS_LITERAL_CSTRING(".purgecaches")
@@ -3314,16 +3315,20 @@ XREMain::XRE_mainInit(bool* aExitFlag)
     if (BrowserTabsRemoteAutostart()) {
       MOZ_CRASH("Failed to initialize broker services, can't continue.");
     }
 #endif
     // Otherwise just warn for the moment, as most things will work.
     NS_WARNING("Failed to initialize broker services, sandboxed processes will "
                "fail to start.");
   }
+  if (mAppData->sandboxPermissionsService) {
+    SandboxPermissions::Initialize(mAppData->sandboxPermissionsService,
+                                   nullptr);
+  }
 #endif
 
 #ifdef XP_MACOSX
   // Set up ability to respond to system (Apple) events. This must occur before
   // ProcessUpdates to ensure that links clicked in external applications aren't
   // lost when updates are pending.
   SetupMacApplicationDelegate();
 
@@ -4602,16 +4607,17 @@ XREMain::XRE_main(int argc, char* argv[]
   }
 
   if (!mAppData->directory) {
     mAppData->directory = mAppData->xreDirectory;
   }
 
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
   mAppData->sandboxBrokerServices = aConfig.sandboxBrokerServices;
+  mAppData->sandboxPermissionsService = aConfig.sandboxPermissionsService;
 #endif
 
   mozilla::IOInterposerInit ioInterposerGuard;
 
 #if defined(XP_WIN)
   // Some COM settings are global to the process and must be set before any non-
   // trivial COM is run in the application. Since these settings may affect
   // stability, we should instantiate COM ASAP so that we can ensure that these
--- a/xpcom/build/XREAppData.h
+++ b/xpcom/build/XREAppData.h
@@ -12,16 +12,21 @@
 #include "nsCOMPtr.h"
 #include "nsCRTGlue.h"
 #include "nsIFile.h"
 
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
 namespace sandbox {
 class BrokerServices;
 }
+namespace mozilla {
+namespace sandboxing {
+class PermissionsService;
+}
+}
 #endif
 
 namespace mozilla {
 
 struct StaticXREAppData;
 
 /**
  * Application-specific data needed to start the apprunner.
@@ -189,16 +194,17 @@ public:
    */
   CharPtr UAName;
 
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
   /**
    * Chromium sandbox BrokerServices.
    */
   sandbox::BrokerServices* sandboxBrokerServices = nullptr;
+  mozilla::sandboxing::PermissionsService* sandboxPermissionsService;
 #endif
 };
 
 /**
  * Indicates whether or not the profile migrator service may be
  * invoked at startup when creating a profile.
  */
 #define NS_XRE_ENABLE_PROFILE_MIGRATOR (1 << 1)
--- a/xpcom/glue/XREAppData.cpp
+++ b/xpcom/glue/XREAppData.cpp
@@ -44,13 +44,14 @@ XREAppData::operator=(const XREAppData& 
   xreDirectory = aOther.xreDirectory;
   minVersion = aOther.minVersion;
   maxVersion = aOther.maxVersion;
   crashReporterURL = aOther.crashReporterURL;
   profile = aOther.profile;
   UAName = aOther.UAName;
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
   sandboxBrokerServices = aOther.sandboxBrokerServices;
+  sandboxPermissionsService = aOther.sandboxPermissionsService;
 #endif
   return *this;
 }
 
 } // namespace mozilla