Bug 1470591 - Part 2: Provide methods to recreate a delegated forker. gsvelto draft
authorThinker <thinker.li@gmail.com>
Mon, 25 Nov 2019 22:43:31 -0800
changeset 2497064 c26c3b7da49ff583fc441ed934a2fe75fda5ecca
parent 2497063 ed2141abd9f2d3922347d0e0e9e67bd397eea444
child 2497065 ce460e8da2a2744a7a94d82217e041722c96fbc0
push id455563
push userthinker.li@gmail.com
push dateTue, 26 Nov 2019 06:43:52 +0000
treeherdertry@60c1683c97b6 [default view] [failures only]
bugs1470591
milestone72.0a1
Bug 1470591 - Part 2: Provide methods to recreate a delegated forker. gsvelto With a fork server, the parameters to fork a new content process are passed through a socket. This patch does following tasks to adapt sandbox to work with a fork server, - passing a FD of a chroot server, - passing flags of SandboxFork, and - setting LaunchOptions and its fork_delegate field at a fork server.
security/sandbox/linux/SandboxChrootProto.h
security/sandbox/linux/launch/SandboxLaunch.cpp
security/sandbox/linux/launch/SandboxLaunch.h
--- a/security/sandbox/linux/SandboxChrootProto.h
+++ b/security/sandbox/linux/SandboxChrootProto.h
@@ -7,15 +7,18 @@
 #ifndef mozilla_SandboxChrootProto_h
 #define mozilla_SandboxChrootProto_h
 
 #include "mozilla/Types.h"
 
 namespace mozilla {
 
 static const int kSandboxChrootClientFd = 6;
+#if defined(MOZ_ENABLE_FORKSERVER)
+static const int kSandboxChrootServerFd = 10;
+#endif
 static const char kSandboxChrootRequest = 'C';
 static const char kSandboxChrootResponse = 'O';
 static const char kSandboxChrootEnvFlag[] = "MOZ_SANDBOX_USE_CHROOT";
 
 }  // namespace mozilla
 
 #endif  // mozilla_SandboxChrootProto_h
--- a/security/sandbox/linux/launch/SandboxLaunch.cpp
+++ b/security/sandbox/linux/launch/SandboxLaunch.cpp
@@ -204,17 +204,19 @@ static void PreloadSandboxLib(base::envi
 static void AttachSandboxReporter(base::file_handle_mapping_vector* aFdMap) {
   int srcFd, dstFd;
   SandboxReporter::Singleton()->GetClientFileDescriptorMapping(&srcFd, &dstFd);
   aFdMap->push_back({srcFd, dstFd});
 }
 
 class SandboxFork : public base::LaunchOptions::ForkDelegate {
  public:
-  explicit SandboxFork(int aFlags, bool aChroot);
+  explicit SandboxFork(int aFlags, bool aChroot,
+                       int aServerFd = -1,
+                       int aClientFd = -1);
   virtual ~SandboxFork();
 
   void PrepareMapping(base::file_handle_mapping_vector* aMap);
   pid_t Fork() override;
 
  private:
   int mFlags;
   int mChrootServer;
@@ -316,43 +318,95 @@ void SandboxLaunchPrepare(GeckoProcessTy
       }
       break;
     default:
       // Nothing yet.
       break;
   }
 
   if (canChroot || flags != 0) {
-    auto forker = MakeUnique<SandboxFork>(flags | CLONE_NEWUSER, canChroot);
+    flags |= CLONE_NEWUSER;
+    auto forker = MakeUnique<SandboxFork>(flags, canChroot);
     forker->PrepareMapping(&aOptions->fds_to_remap);
     aOptions->fork_delegate = std::move(forker);
     if (canChroot) {
-      aOptions->env_map[kSandboxChrootEnvFlag] = "1";
+      aOptions->env_map[kSandboxChrootEnvFlag] = std::to_string(flags);
     }
   }
 }
 
-SandboxFork::SandboxFork(int aFlags, bool aChroot)
-    : mFlags(aFlags), mChrootServer(-1), mChrootClient(-1) {
-  if (aChroot) {
+#if defined(MOZ_ENABLE_FORKSERVER)
+/**
+ * Called by the fork server to install a fork delegator.
+ *
+ * In the case of fork server, the value of the flags of |SandboxFork|
+ * are passed as an env variable to the fork server so that we can
+ * recreate a |SandboxFork| as a fork delegator at the fork server.
+ */
+void SandboxLaunchForkServerPrepare(const std::vector<std::string>& aArgv,
+                                    base::LaunchOptions& aOptions) {
+  auto chroot = std::find_if(aOptions.env_map.begin(),
+                             aOptions.env_map.end(),
+                             [](auto& elt) {
+                               return elt.first == kSandboxChrootEnvFlag;
+                             });
+  if (chroot == aOptions.env_map.end()) {
+    return;
+  }
+  int flags = atoi(chroot->second.c_str());
+  if (flags == 0) {
+    return;
+  }
+
+  // Find chroot server fd.  It is supposed to be map to
+  // kSandboxChrootServerFd so that we find it out from the mapping.
+  auto fdmap = std::find_if(aOptions.fds_to_remap.begin(),
+                            aOptions.fds_to_remap.end(),
+                            [](auto& elt) {
+                              return elt.second == kSandboxChrootServerFd;
+                            });
+  MOZ_ASSERT(fdmap != aOptions.fds_to_remap.end(),
+             "ChrootServerFd is not found with sandbox chroot");
+  int chrootserverfd = fdmap->first;
+  aOptions.fds_to_remap.erase(fdmap);
+
+  // Set only the chroot server fd, not the client fd.  Because, the
+  // client fd is already in |fds_to_remap|, we don't need the forker
+  // to do it again.  And, the forker need only the server fd, that
+  // chroot server uses it to sync with the client (content).  See
+  // |SandboxFox::StartChrootServer()|.
+  auto forker = MakeUnique<SandboxFork>(flags, true, chrootserverfd);
+  aOptions.fork_delegate = std::move(forker);
+}
+#endif
+
+SandboxFork::SandboxFork(int aFlags, bool aChroot, int aServerFd, int aClientFd)
+    : mFlags(aFlags), mChrootServer(aServerFd), mChrootClient(aClientFd) {
+  if (aChroot && mChrootServer < 0) {
     int fds[2];
     int rv = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fds);
     if (rv != 0) {
       SANDBOX_LOG_ERROR("socketpair: %s", strerror(errno));
       MOZ_CRASH("socketpair failed");
     }
     mChrootClient = fds[0];
     mChrootServer = fds[1];
   }
 }
 
 void SandboxFork::PrepareMapping(base::file_handle_mapping_vector* aMap) {
+  MOZ_ASSERT(XRE_GetProcessType() != GeckoProcessType_ForkServer);
   if (mChrootClient >= 0) {
     aMap->push_back({mChrootClient, kSandboxChrootClientFd});
   }
+#if defined(MOZ_ENABLE_FORKSERVER)
+  if (mChrootServer >= 0) {
+    aMap->push_back({mChrootServer, kSandboxChrootServerFd});
+  }
+#endif
 }
 
 SandboxFork::~SandboxFork() {
   if (mChrootClient >= 0) {
     close(mChrootClient);
   }
   if (mChrootServer >= 0) {
     close(mChrootServer);
--- a/security/sandbox/linux/launch/SandboxLaunch.h
+++ b/security/sandbox/linux/launch/SandboxLaunch.h
@@ -4,21 +4,26 @@
  * 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_SandboxLaunch_h
 #define mozilla_SandboxLaunch_h
 
 #include "base/process_util.h"
 #include "nsXULAppAPI.h"
+#include <vector>
 
 namespace mozilla {
 
 // Called in the parent process to set up launch-time aspects of
 // sandboxing.  If aType is GeckoProcessType_Content, this must be
 // called on the main thread in order to access prefs.
 void SandboxLaunchPrepare(GeckoProcessType aType,
                           base::LaunchOptions* aOptions);
+#if defined(MOZ_ENABLE_FORKSERVER)
+void SandboxLaunchForkServerPrepare(const std::vector<std::string>& aArgv,
+                                    base::LaunchOptions& aOptions);
+#endif
 bool HasAtiDrivers();
 
 }  // namespace mozilla
 
 #endif  // mozilla_SandboxLaunch_h