Bug 1290619 - Content sandbox rules should use actual profile directory, not Profiles/*/ regex's draft
authorHaik Aftandilian <haftandilian@mozilla.com>
Fri, 12 Aug 2016 17:43:03 -0700
changeset 400319 b9d3a09d8ea8d258617ad405d34ff618c2ff6a9f
parent 399698 233ab21b64b5d5e9f2f16ea2d4cfb4c8b293c5c4
child 528192 e8a22f06352b9738b9d43a740b91d758957e4583
push id26133
push userhaftandilian@mozilla.com
push dateSat, 13 Aug 2016 01:00:43 +0000
bugs1290619
milestone51.0a1
Bug 1290619 - Content sandbox rules should use actual profile directory, not Profiles/*/ regex's MozReview-Commit-ID: Jsa3ELoXnxD
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentProcess.cpp
dom/ipc/ContentProcess.h
ipc/glue/GeckoChildProcessHost.cpp
security/sandbox/mac/Sandbox.h
security/sandbox/mac/Sandbox.mm
toolkit/xre/nsEmbedFunctions.cpp
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1311,23 +1311,32 @@ StartMacOSContentSandbox()
   }
 
   nsAutoCString tempDirPath;
   rv = tempDir->GetNativePath(tempDirPath);
   if (NS_FAILED(rv)) {
     MOZ_CRASH("Failed to get NS_OS_TEMP_DIR path");
   }
 
+  nsCOMPtr<nsIFile> profileDir;
+  ContentChild::GetSingleton()->GetProfileDir(getter_AddRefs(profileDir));
+  nsCString profileDirPath;
+  rv = profileDir->GetNativePath(profileDirPath);
+  if (NS_FAILED(rv)) {
+    MOZ_CRASH("Failed to get profile path");
+  }
+
   MacSandboxInfo info;
   info.type = MacSandboxType_Content;
   info.level = info.level = sandboxLevel;
   info.appPath.assign(appPath.get());
   info.appBinaryPath.assign(appBinaryPath.get());
   info.appDir.assign(appDir.get());
   info.appTempDir.assign(tempDirPath.get());
+  info.profileDir.assign(profileDirPath.get());
 
   std::string err;
   if (!mozilla::StartMacSandbox(info, err)) {
     NS_WARNING(err.c_str());
     MOZ_CRASH("sandbox_init() failed");
   }
 
   return true;
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -16,16 +16,19 @@
 #include "nsHashKeys.h"
 #include "nsIObserver.h"
 #include "nsTHashtable.h"
 #include "nsRefPtrHashtable.h"
 
 #include "nsWeakPtr.h"
 #include "nsIWindowProvider.h"
 
+#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+#include "nsIFile.h"
+#endif
 
 struct ChromePackage;
 class nsIObserver;
 struct SubstitutionMapping;
 struct OverrideMapping;
 class nsIDomainPolicy;
 
 namespace mozilla {
@@ -109,16 +112,28 @@ public:
   }
 
   void SetProcessName(const nsAString& aName, bool aDontOverride = false);
 
   void GetProcessName(nsAString& aName) const;
 
   void GetProcessName(nsACString& aName) const;
 
+#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+  void GetProfileDir(nsIFile** aProfileDir) const
+  {
+    *aProfileDir = mProfileDir;
+  }
+
+  void SetProfileDir(nsIFile* aProfileDir)
+  {
+    mProfileDir = aProfileDir;
+  }
+#endif
+
   bool IsAlive() const;
 
   static void AppendProcessId(nsACString& aName);
 
   ContentBridgeParent* GetLastBridge()
   {
     MOZ_ASSERT(mLastBridge);
     ContentBridgeParent* parent = mLastBridge;
@@ -677,16 +692,20 @@ private:
   bool mIsAlive;
   nsString mProcessName;
 
   static ContentChild* sSingleton;
 
   nsCOMPtr<nsIDomainPolicy> mPolicy;
   nsCOMPtr<nsITimer> mForceKillTimer;
 
+#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+  nsCOMPtr<nsIFile> mProfileDir;
+#endif
+
   // Hashtable to keep track of the pending GetFilesHelper objects.
   // This GetFilesHelperChild objects are removed when RecvGetFilesResponse is
   // received.
  nsRefPtrHashtable<nsIDHashKey, GetFilesHelperChild> mGetFilesPendingRequests;
 
   DISALLOW_EVIL_CONSTRUCTORS(ContentChild);
 };
 
--- a/dom/ipc/ContentProcess.cpp
+++ b/dom/ipc/ContentProcess.cpp
@@ -109,26 +109,45 @@ SetUpSandboxEnvironment()
 #endif
 
 void
 ContentProcess::SetAppDir(const nsACString& aPath)
 {
   mXREEmbed.SetAppDir(aPath);
 }
 
+#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+void
+ContentProcess::SetProfile(const nsACString& aProfile)
+{
+  bool flag;
+  nsresult rv =
+    XRE_GetFileFromPath(aProfile.BeginReading(), getter_AddRefs(mProfileDir));
+  if (NS_FAILED(rv) ||
+      NS_FAILED(mProfileDir->Exists(&flag)) || !flag) {
+    NS_WARNING("Invalid profile directory passed to content process.");
+    mProfileDir = nullptr;
+  }
+}
+#endif
+
 bool
 ContentProcess::Init()
 {
     mContent.Init(IOThreadChild::message_loop(),
                   ParentPid(),
                   IOThreadChild::channel());
     mXREEmbed.Start();
     mContent.InitXPCOM();
     mContent.InitGraphicsDeviceData();
 
+#if (defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
+    mContent.SetProfileDir(mProfileDir);
+#endif
+
 #if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
     SetUpSandboxEnvironment();
 #endif
 
     return true;
 }
 
 // Note: CleanUp() never gets called in non-debug builds because we exit early
--- a/dom/ipc/ContentProcess.h
+++ b/dom/ipc/ContentProcess.h
@@ -34,19 +34,28 @@ public:
   ~ContentProcess()
   { }
 
   virtual bool Init() override;
   virtual void CleanUp() override;
 
   void SetAppDir(const nsACString& aPath);
 
+#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+  void SetProfile(const nsACString& aProfile);
+#endif
+
 private:
   ContentChild mContent;
   mozilla::ipc::ScopedXREEmbed mXREEmbed;
+
+#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+  nsCOMPtr<nsIFile> mProfileDir;
+#endif
+
 #if defined(XP_WIN)
   // This object initializes and configures COM.
   mozilla::mscom::MainThreadRuntime mCOMRuntime;
 #endif
 
   DISALLOW_EVIL_CONSTRUCTORS(ContentProcess);
 };
 
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -18,16 +18,20 @@
 #include "SharedMemoryBasic.h"
 #endif
 
 #include "MainThreadUtils.h"
 #include "mozilla/Snprintf.h"
 #include "prenv.h"
 #include "nsXPCOMPrivate.h"
 
+#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+#include "nsAppDirectoryServiceDefs.h"
+#endif
+
 #include "nsExceptionHandler.h"
 
 #include "nsDirectoryServiceDefs.h"
 #include "nsIFile.h"
 #include "nsPrintfCString.h"
 
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/ipc/BrowserProcessSubThread.h"
@@ -603,16 +607,30 @@ AddAppDirToCommandLine(std::vector<std::
         aCmdLine.AppendLooseValue(wpath);
 #else
         nsAutoCString path;
         MOZ_ALWAYS_SUCCEEDS(appDir->GetNativePath(path));
         aCmdLine.push_back("-appdir");
         aCmdLine.push_back(path.get());
 #endif
       }
+
+#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+      // Full path to the profile dir
+      nsCOMPtr<nsIFile> profileDir;
+      rv = directoryService->Get(NS_APP_USER_PROFILE_50_DIR,
+                                 NS_GET_IID(nsIFile),
+                                 getter_AddRefs(profileDir));
+      if (NS_SUCCEEDED(rv)) {
+        nsAutoCString path;
+        MOZ_ALWAYS_SUCCEEDS(profileDir->GetNativePath(path));
+        aCmdLine.push_back("-profile");
+        aCmdLine.push_back(path.get());
+#endif
+      }
     }
   }
 }
 
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
 static void
 MaybeAddNsprLogFileAccess(std::vector<std::wstring>& aAllowedFilesReadWrite)
 {
--- a/security/sandbox/mac/Sandbox.h
+++ b/security/sandbox/mac/Sandbox.h
@@ -36,24 +36,26 @@ typedef struct _MacSandboxPluginInfo {
 } MacSandboxPluginInfo;
 
 typedef struct _MacSandboxInfo {
   _MacSandboxInfo()
     : type(MacSandboxType_Default), level(0) {}
   _MacSandboxInfo(const struct _MacSandboxInfo& other)
     : type(other.type), level(other.level), pluginInfo(other.pluginInfo),
       appPath(other.appPath), appBinaryPath(other.appBinaryPath),
-      appDir(other.appDir), appTempDir(other.appTempDir) {}
+      appDir(other.appDir), appTempDir(other.appTempDir),
+      profileDir(other.profileDir) {}
   MacSandboxType type;
   int32_t level;
   MacSandboxPluginInfo pluginInfo;
   std::string appPath;
   std::string appBinaryPath;
   std::string appDir;
   std::string appTempDir;
+  std::string profileDir;
 } MacSandboxInfo;
 
 namespace mozilla {
 
 bool StartMacSandbox(MacSandboxInfo aInfo, std::string &aErrorMessage);
 
 } // namespace mozilla
 
--- a/security/sandbox/mac/Sandbox.mm
+++ b/security/sandbox/mac/Sandbox.mm
@@ -151,16 +151,17 @@ static const char contentSandboxRules[] 
   "(version 1)\n"
   "\n"
   "(define sandbox-level %d)\n"
   "(define macosMinorVersion %d)\n"
   "(define appPath \"%s\")\n"
   "(define appBinaryPath \"%s\")\n"
   "(define appDir \"%s\")\n"
   "(define appTempDir \"%s\")\n"
+  "(define profileDir \"%s\")\n"
   "(define home-path \"%s\")\n"
   "\n"
   "; Allow read access to standard system paths.\n"
   "(allow file-read*\n"
   "  (require-all (file-mode #o0004)\n"
   "    (require-any (subpath \"/Library/Filesystems/NetFSPlugins\")\n"
   "      (subpath \"/System\")\n"
   "      (subpath \"/private/var/db/dyld\")\n"
@@ -226,16 +227,19 @@ static const char contentSandboxRules[] 
   "\n"
   "  (define (home-regex home-relative-regex)\n"
   "    (resolving-regex (string-append \"^\" (regex-quote home-path) home-relative-regex)))\n"
   "  (define (home-subpath home-relative-subpath)\n"
   "    (resolving-subpath (string-append home-path home-relative-subpath)))\n"
   "  (define (home-literal home-relative-literal)\n"
   "    (resolving-literal (string-append home-path home-relative-literal)))\n"
   "\n"
+  "  (define (profile-subpath profile-relative-subpath)\n"
+  "    (resolving-subpath (string-append profileDir profile-relative-subpath)))\n"
+  "\n"
   "  (define (container-regex container-relative-regex)\n"
   "    (resolving-regex (string-append \"^\" (regex-quote container-path) container-relative-regex)))\n"
   "  (define (container-subpath container-relative-subpath)\n"
   "    (resolving-subpath (string-append container-path container-relative-subpath)))\n"
   "  (define (container-literal container-relative-literal)\n"
   "    (resolving-literal (string-append container-path container-relative-literal)))\n"
   "\n"
   "  (define (var-folders-regex var-folders-relative-regex)\n"
@@ -365,18 +369,18 @@ static const char contentSandboxRules[] 
   "  (allow file-read*\n"
   "      (var-folders2-regex \"/com\\.apple\\.IconServices/\")\n"
   "      (var-folders2-regex \"/[^/]+\\.mozrunner/extensions/[^/]+/chrome/[^/]+/content/[^/]+\\.j(s|ar)$\"))\n"
   "\n"
   "  (allow file-write* (var-folders2-regex \"/org\\.chromium\\.[a-zA-Z0-9]*$\"))\n"
   "  (allow file-read*\n"
   "      (home-regex \"/Library/Application Support/[^/]+/Extensions/[^/]/\")\n"
   "      (resolving-regex \"/Library/Application Support/[^/]+/Extensions/[^/]/\")\n"
-  "      (home-regex \"/Library/Application Support/Firefox/Profiles/[^/]+/extensions/\")\n"
-  "      (home-regex \"/Library/Application Support/Firefox/Profiles/[^/]+/weave/\"))\n"
+  "      (profile-subpath \"/extensions\")\n"
+  "      (profile-subpath \"/weave\"))\n"
   "\n"
   "; the following rules should be removed when printing and \n"
   "; opening a file from disk are brokered through the main process\n"
   "  (if\n"
   "    (< sandbox-level 2)\n"
   "    (allow file*\n"
   "        (require-not\n"
   "            (home-subpath \"/Library\")))\n"
@@ -491,16 +495,17 @@ bool StartMacSandbox(MacSandboxInfo aInf
     MOZ_ASSERT(aInfo.level >= 1);
     if (aInfo.level >= 1) {
       asprintf(&profile, contentSandboxRules, aInfo.level,
                OSXVersion::OSXVersionMinor(),
                aInfo.appPath.c_str(),
                aInfo.appBinaryPath.c_str(),
                aInfo.appDir.c_str(),
                aInfo.appTempDir.c_str(),
+               aInfo.profileDir.c_str(),
                getenv("HOME"));
     } else {
       fprintf(stderr,
         "Content sandbox disabled due to sandbox level setting\n");
       return false;
     }
   }
   else {
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -603,23 +603,54 @@ XRE_InitChildProcess(int aArgc,
 
       case GeckoProcessType_Plugin:
         process = new PluginProcessChild(parentPID);
         break;
 
       case GeckoProcessType_Content: {
           process = new ContentProcess(parentPID);
           // If passed in grab the application path for xpcom init
-          nsCString appDir;
+          bool foundAppdir = false;
+
+#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+          // If passed in grab the profile path for sandboxing
+          bool foundProfile = false;
+#endif
+
           for (int idx = aArgc; idx > 0; idx--) {
             if (aArgv[idx] && !strcmp(aArgv[idx], "-appdir")) {
+              MOZ_ASSERT(!foundAppdir);
+              if (foundAppdir) {
+                  continue;
+              }
+              nsCString appDir;
               appDir.Assign(nsDependentCString(aArgv[idx+1]));
               static_cast<ContentProcess*>(process.get())->SetAppDir(appDir);
+              foundAppdir = true;
+            }
+
+#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+            if (aArgv[idx] && !strcmp(aArgv[idx], "-profile")) {
+              MOZ_ASSERT(!foundProfile);
+              if (foundProfile) {
+                continue;
+              }
+              nsCString profile;
+              profile.Assign(nsDependentCString(aArgv[idx+1]));
+              static_cast<ContentProcess*>(process.get())->SetProfile(profile);
+              foundProfile = true;
+            }
+            if (foundProfile && foundAppdir) {
               break;
             }
+#else
+            if (foundAppdir) {
+              break;
+            }
+#endif /* XP_MACOSX && MOZ_CONTENT_SANDBOX */
           }
         }
         break;
 
       case GeckoProcessType_IPDLUnitTest:
 #ifdef MOZ_IPDL_TESTS
         process = new IPDLUnitTestProcessChild(parentPID);
 #else