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

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

commit 9c44b31e73783a220e43098a1b117e83e6074fdc
Author: Qian Zhang <[email protected]>
AuthorDate: Wed Feb 27 22:22:34 2019 -0800

    Added a test `ROOT_UNPRIVILEGED_USER_ParentTypeDifferentUser`.
    
    Review: https://reviews.apache.org/r/67997/
---
 .../volume_sandbox_path_isolator_tests.cpp         | 128 +++++++++++++++++++++
 1 file changed, 128 insertions(+)

diff --git a/src/tests/containerizer/volume_sandbox_path_isolator_tests.cpp 
b/src/tests/containerizer/volume_sandbox_path_isolator_tests.cpp
index cbe6778..9238d58 100644
--- a/src/tests/containerizer/volume_sandbox_path_isolator_tests.cpp
+++ b/src/tests/containerizer/volume_sandbox_path_isolator_tests.cpp
@@ -28,6 +28,8 @@
 
 #include "slave/containerizer/mesos/containerizer.hpp"
 
+#include "slave/volume_gid_manager/volume_gid_manager.hpp"
+
 #ifdef __linux__
 #include "tests/containerizer/docker_archive.hpp"
 #endif
@@ -41,6 +43,7 @@ using process::Owned;
 using mesos::internal::slave::Containerizer;
 using mesos::internal::slave::Fetcher;
 using mesos::internal::slave::MesosContainerizer;
+using mesos::internal::slave::VolumeGidManager;
 
 using mesos::internal::slave::state::SlaveState;
 
@@ -429,6 +432,131 @@ TEST_F(VolumeSandboxPathIsolatorTest,
   EXPECT_WTERMSIG_EQ(SIGKILL, termination.get()->status());
 }
 
+
+#ifdef __linux__
+// This test verifies that a nested container launched with a
+// non-root user has the permission to write to a PARENT type
+// SANDBOX_PATH volume while its parent container (i.e., the
+// executor container) is launched with a different user (root).
+TEST_F(VolumeSandboxPathIsolatorTest,
+       ROOT_UNPRIVILEGED_USER_ParentTypeDifferentUser)
+{
+  slave::Flags flags = CreateSlaveFlags();
+  flags.isolation = "filesystem/linux,volume/sandbox_path";
+  flags.volume_gid_range = "[10000-20000]";
+
+  Fetcher fetcher(flags);
+
+  Try<VolumeGidManager*> volumeGidManager = VolumeGidManager::create(flags);
+  ASSERT_SOME(volumeGidManager);
+
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      true,
+      &fetcher,
+      nullptr,
+      nullptr,
+      None(),
+      volumeGidManager.get());
+
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
+
+  SlaveState state;
+  state.id = SlaveID();
+
+  AWAIT_READY(containerizer->recover(state));
+
+  ContainerID containerId;
+  containerId.set_value(id::UUID::random().toString());
+
+  ExecutorInfo executor = createExecutorInfo("executor", "sleep 99", "cpus:1");
+
+  Try<string> directory = environment->mkdtemp();
+  ASSERT_SOME(directory);
+
+  // By default this directory is created with the mode 0700,
+  // here we change it to 0711 to make sure the non-root user
+  // used to launch the nested container can enter it.
+  ASSERT_SOME(os::chmod(directory.get(), 0711));
+
+  // Launch the executor. Since this is a ROOT test, the agent will
+  // run as root, and by default executor will run as the same user
+  // as the agent, so it will run as root as well.
+  Future<Containerizer::LaunchResult> launch = containerizer->launch(
+      containerId,
+      createContainerConfig(None(), executor, directory.get()),
+      map<string, string>(),
+      None());
+
+  AWAIT_ASSERT_EQ(Containerizer::LaunchResult::SUCCESS, launch);
+
+  ContainerID nestedContainerId;
+  nestedContainerId.mutable_parent()->CopyFrom(containerId);
+  nestedContainerId.set_value(id::UUID::random().toString());
+
+  ContainerInfo containerInfo;
+  containerInfo.set_type(ContainerInfo::MESOS);
+
+  Volume* volume = containerInfo.add_volumes();
+  volume->set_mode(Volume::RW);
+  volume->set_container_path("parent");
+
+  Volume::Source* source = volume->mutable_source();
+  source->set_type(Volume::Source::SANDBOX_PATH);
+
+  Volume::Source::SandboxPath* sandboxPath = source->mutable_sandbox_path();
+  sandboxPath->set_type(Volume::Source::SandboxPath::PARENT);
+  sandboxPath->set_path("shared");
+
+  Option<string> user = os::getenv("SUDO_USER");
+  ASSERT_SOME(user);
+
+  // Launch the nested container with a non-root user.
+  launch = containerizer->launch(
+      nestedContainerId,
+      createContainerConfig(
+          createCommandInfo("echo 'hello' > parent/file"),
+          containerInfo,
+          None(),
+          user.get()),
+      map<string, string>(),
+      None());
+
+  AWAIT_ASSERT_EQ(Containerizer::LaunchResult::SUCCESS, launch);
+
+  Future<Option<ContainerTermination>> wait =
+    containerizer->wait(nestedContainerId);
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+  ASSERT_TRUE(wait.get()->has_status());
+  EXPECT_WEXITSTATUS_EQ(0, wait.get()->status());
+
+  string volumePath = path::join(directory.get(), "shared");
+
+  // The owner group of the volume should be changed to the gid allocated
+  // to it, i.e., the first gid in the agent flag `--volume_gid_range`.
+  struct stat s;
+  EXPECT_EQ(0, ::stat(volumePath.c_str(), &s));
+  EXPECT_EQ(10000u, s.st_gid);
+
+  Future<Option<ContainerTermination>> termination =
+    containerizer->destroy(containerId);
+
+  AWAIT_READY(termination);
+  ASSERT_SOME(termination.get());
+  ASSERT_TRUE(termination.get()->has_status());
+  EXPECT_WTERMSIG_EQ(SIGKILL, termination.get()->status());
+
+  // The owner group of the volume should be changed back to
+  // the original one, i.e., root.
+  EXPECT_EQ(0, ::stat(volumePath.c_str(), &s));
+  EXPECT_EQ(0u, s.st_gid);
+}
+#endif // __linux__
+
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {

Reply via email to