This is an automated email from the ASF dual-hosted git repository.

gilbert pushed a commit to branch 1.6.x
in repository https://gitbox.apache.org/repos/asf/mesos.git

commit cdf042e534caaba9c835f8eb2340ca1acd5fda79
Author: Gilbert Song <[email protected]>
AuthorDate: Mon Feb 11 12:51:24 2019 -0800

    Cloned a sealed file of launcher binary.
    
    Cloned this binary during mesos containerizer create and command
    executor launch.
    
    This change would copy the mesos-containerizer binary in memory,
    which helps avoid the binary being overwritten.
    
    Review: https://reviews.apache.org/r/69947/
    (cherry picked from commit f7407d3d5f0fe7d5c9a06774921de514012a54da)
---
 src/launcher/executor.cpp                       | 23 +++++++++++++++++--
 src/slave/containerizer/mesos/containerizer.cpp | 30 +++++++++++++++++++++++--
 src/slave/containerizer/mesos/containerizer.hpp | 18 ++++++++++++---
 3 files changed, 64 insertions(+), 7 deletions(-)

diff --git a/src/launcher/executor.cpp b/src/launcher/executor.cpp
index 3f606e5..ec12b89 100644
--- a/src/launcher/executor.cpp
+++ b/src/launcher/executor.cpp
@@ -82,6 +82,10 @@
 #include "internal/devolve.hpp"
 #include "internal/evolve.hpp"
 
+#ifdef __linux__
+#include "linux/memfd.hpp"
+#endif // __linux__
+
 #include "logging/logging.hpp"
 
 #include "messages/messages.hpp"
@@ -478,11 +482,26 @@ protected:
 
     launchFlags.launch_info = JSON::protobuf(launchInfo);
 
+    // Determine the mesos containerizer binary depends on whether we
+    // need to clone and seal it on linux.
+    string initPath = path::join(launcherDir, MESOS_CONTAINERIZER);
+#ifdef __linux__
+    // Clone the launcher binary in memory for security concerns.
+    Try<int_fd> memFd = memfd::cloneSealedFile(initPath);
+    if (memFd.isError()) {
+      ABORT(
+          "Failed to clone a sealed file '" + initPath + "' in memory: " +
+          memFd.error());
+    }
+
+    initPath = "/proc/self/fd/" + stringify(memFd.get());
+#endif // __linux__
+
     // TODO(tillt): Consider using a flag allowing / disallowing the
     // log output of possibly sensitive data. See MESOS-7292.
     string commandString = strings::format(
         "%s %s <POSSIBLY-SENSITIVE-DATA>",
-        path::join(launcherDir, MESOS_CONTAINERIZER),
+        initPath,
         MesosContainerizerLaunch::NAME).get();
 
     LOG(INFO) << "Running '" << commandString << "'";
@@ -508,7 +527,7 @@ protected:
     }
 
     Try<Subprocess> s = subprocess(
-        path::join(launcherDir, MESOS_CONTAINERIZER),
+        initPath,
         argv,
         Subprocess::FD(STDIN_FILENO),
         Subprocess::FD(STDOUT_FILENO),
diff --git a/src/slave/containerizer/mesos/containerizer.cpp 
b/src/slave/containerizer/mesos/containerizer.cpp
index c9af06c..7f00084 100644
--- a/src/slave/containerizer/mesos/containerizer.cpp
+++ b/src/slave/containerizer/mesos/containerizer.cpp
@@ -50,6 +50,10 @@
 
 #include "hook/manager.hpp"
 
+#ifdef __linux__
+#include "linux/memfd.hpp"
+#endif // __linux__
+
 #include "module/manager.hpp"
 
 #include "slave/paths.hpp"
@@ -565,6 +569,23 @@ Try<MesosContainerizer*> MesosContainerizer::create(
   _isolators.push_back(Owned<Isolator>(new MesosIsolator(
       Owned<MesosIsolatorProcess>(ioSwitchboard.get()))));
 
+  Option<int_fd> initMemFd;
+
+#ifdef __linux__
+  // Clone the launcher binary in memory for security concerns.
+  Try<int_fd> memFd = memfd::cloneSealedFile(
+      path::join(flags.launcher_dir, MESOS_CONTAINERIZER));
+
+  if (memFd.isError()) {
+    return Error(
+        "Failed to clone a sealed file '" +
+        path::join(flags.launcher_dir, MESOS_CONTAINERIZER) + "' in memory: " +
+        memFd.error());
+  }
+
+  initMemFd = memFd.get();
+#endif // __linux__
+
   return new MesosContainerizer(Owned<MesosContainerizerProcess>(
       new MesosContainerizerProcess(
           flags,
@@ -572,7 +593,8 @@ Try<MesosContainerizer*> MesosContainerizer::create(
           ioSwitchboard.get(),
           launcher,
           provisioner,
-          _isolators)));
+          _isolators,
+          initMemFd)));
 }
 
 
@@ -1977,13 +1999,17 @@ Future<Containerizer::LaunchResult> 
MesosContainerizerProcess::_launch(
       launchFlagsEnvironment.end());
 
   // Fork the child using launcher.
+  string initPath = initMemFd.isSome()
+    ? ("/proc/self/fd/" + stringify(initMemFd.get()))
+    : path::join(flags.launcher_dir, MESOS_CONTAINERIZER);
+
   vector<string> argv(2);
   argv[0] = path::join(flags.launcher_dir, MESOS_CONTAINERIZER);
   argv[1] = MesosContainerizerLaunch::NAME;
 
   Try<pid_t> forked = launcher->fork(
       containerId,
-      argv[0],
+      initPath,
       argv,
       containerIO.get(),
       nullptr,
diff --git a/src/slave/containerizer/mesos/containerizer.hpp 
b/src/slave/containerizer/mesos/containerizer.hpp
index 22405e6..b0b4aff 100644
--- a/src/slave/containerizer/mesos/containerizer.hpp
+++ b/src/slave/containerizer/mesos/containerizer.hpp
@@ -139,16 +139,27 @@ public:
       IOSwitchboard* _ioSwitchboard,
       const process::Owned<Launcher>& _launcher,
       const process::Shared<Provisioner>& _provisioner,
-      const std::vector<process::Owned<mesos::slave::Isolator>>& _isolators)
+      const std::vector<process::Owned<mesos::slave::Isolator>>& _isolators,
+      const Option<int_fd>& _initMemFd)
     : ProcessBase(process::ID::generate("mesos-containerizer")),
       flags(_flags),
       fetcher(_fetcher),
       ioSwitchboard(_ioSwitchboard),
       launcher(_launcher),
       provisioner(_provisioner),
-      isolators(_isolators) {}
+      isolators(_isolators),
+      initMemFd(_initMemFd) {}
 
-  virtual ~MesosContainerizerProcess() {}
+  virtual ~MesosContainerizerProcess()
+  {
+    if (initMemFd.isSome()) {
+      Try<Nothing> close = os::close(initMemFd.get());
+      if (close.isError()) {
+        LOG(WARNING) << "Failed to close memfd '" << stringify(initMemFd.get())
+                     << "': " << close.error();
+      }
+    }
+  }
 
   virtual process::Future<Nothing> recover(
       const Option<state::SlaveState>& state);
@@ -304,6 +315,7 @@ private:
   const process::Owned<Launcher> launcher;
   const process::Shared<Provisioner> provisioner;
   const std::vector<process::Owned<mesos::slave::Isolator>> isolators;
+  const Option<int_fd> initMemFd;
 
   struct Container
   {

Reply via email to