Package: schroot
Version: 1.7.2-2
Severity: important
Tags: upstream patch

Dear Maintainer,

Schroot users that have /home/$USER as a separate mount point usually
update the various schroot profiles' fstab to include:

  /home           /home           none    rw,rbind        0       0

That has worked pretty well for many filesystems that would be mounted
at /home/$USER. However, I've recently had a lot of eCryptfs users
reporting issues when using systemd as their init system since systemd
uses shared mount propagation for mounts. The biggest issue is that
/home/$USER is unmounted in the host environment when schroot sessions
are ended due to the unmount events being propagated outside of the
schroot session's subdirectory.

I believe that the best fix is to mark bind mount points, under the
schroot session's subdirectory, as private. Also, rbind mount points
will need to be marked as rprivate.

I'll attach a patch developed against schroot's master git branch (which
should apply to 1.7.2-2) and another developed against the schroot-1.6
branch.

Tyler

-- System Information:
Debian Release: jessie/sid
  APT prefers vivid-updates
  APT policy: (500, 'vivid-updates'), (500, 'vivid-security'), (500, 'vivid')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 3.19.0-16-generic (SMP w/4 CPU cores)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
From db5cbc9dd57fc3a13f3f1fb405aa2cc1d2d6d7d0 Mon Sep 17 00:00:00 2001
From: Tyler Hicks <tyhi...@canonical.com>
Date: Fri, 22 May 2015 12:27:40 -0500
Subject: [PATCH] libexec-mount: Make bind mounts use private mount propagation

When creating a bind mount, on a Linux system, mark the target as
private. When creating a recursive bind mount, on a Linux system, mark
the target as recursively private.

This change fixes issues around shared mount points being bind mounted
into a schroot and then when the schroot session is tore down, the mount
point being unmounted in both the schroot and in the host environment.

For example, if the schroot fstab file contains the following line:

  /home           /home           none    rw,rbind        0       0

A user's home directory mounted at /home/$USER is unmounted in both the
schroot and host when the schroot sessions is ended without this change.

Signed-off-by: Tyler Hicks <tyhi...@canonical.com>
---
 libexec/mount/main.cc | 42 ++++++++++++++++++++++++++++++++++++++++++
 libexec/mount/main.h  | 10 ++++++++++
 2 files changed, 52 insertions(+)

diff --git a/libexec/mount/main.cc b/libexec/mount/main.cc
index 9ea6e80..80b0236 100644
--- a/libexec/mount/main.cc
+++ b/libexec/mount/main.cc
@@ -21,6 +21,10 @@
 #include <schroot/mntstream.h>
 #include <schroot/util.h>
 
+#if defined (__linux__)
+#include <schroot/regex.h>
+#endif
+
 #include <libexec/mount/main.h>
 
 #include <cerrno>
@@ -207,7 +211,45 @@ namespace bin
               if (status)
                 exit(status);
             }
+
+            make_mount_private(entry.options, directory);
+        }
+    }
+
+    void
+    main::make_mount_private (const std::string& options,
+                              const std::string& mountpoint)
+    {
+#if defined (__linux__)
+      static schroot::regex bind("(^|,)(|r)bind(,|$)");
+
+      if (regex_search(options, bind))
+        {
+          static schroot::regex rbind("(^|,)rbind(,|$)");
+          bool recursive = regex_search(options, rbind);
+
+          schroot::log_debug(schroot::DEBUG_INFO)
+          << boost::format("Making ‘%1%’ mount point %2%private")
+          % mountpoint
+          % (recursive ? "recursively " : "")
+          << std::endl;
+
+          if (!opts->dry_run)
+            {
+              schroot::string_list command;
+              command.push_back("/bin/mount");
+              if (opts->verbose)
+                command.push_back("-v");
+              command.push_back(recursive ? "--make-rprivate" : "--make-private");
+              command.push_back(mountpoint);
+
+              int status = run_child(command[0], command, schroot::environment());
+
+              if (status)
+                exit(status);
+            }
         }
+#endif
     }
 
     int
diff --git a/libexec/mount/main.h b/libexec/mount/main.h
index c523bfe..a212b5a 100644
--- a/libexec/mount/main.h
+++ b/libexec/mount/main.h
@@ -70,6 +70,16 @@ namespace bin
       action_mount ();
 
       /**
+       * Make a bind mount use private mount propagation (Linux-specific).
+       *
+       * @param options the mount options
+       * @param mountpoint the mountpiont to make private
+       */
+      void
+      make_mount_private (const std::string& options,
+                          const std::string& mountpoint);
+
+      /**
        * Run the command specified by file (an absolute pathname), using
        * command and env as the argv and environment, respectively.
        *
-- 
2.1.4

From d90df1244e35b7851b93da2f3fb38d48bc9f5229 Mon Sep 17 00:00:00 2001
From: Tyler Hicks <tyhi...@canonical.com>
Date: Fri, 22 May 2015 12:28:28 -0500
Subject: [PATCH] schroot-mount: Make bind mounts use private mount propagation

When creating a bind mount, on a Linux system, mark the target as
private. When creating a recursive bind mount, on a Linux system, mark
the target as recursively private.

This change fixes issues around shared mount points being bind mounted
into a schroot and then when the schroot session is tore down, the mount
point being unmounted in both the schroot and in the host environment.

For example, if the schroot fstab file contains the following line:

  /home           /home           none    rw,rbind        0       0

A user's home directory mounted at /home/$USER is unmounted in both the
schroot and host when the schroot sessions is ended without this change.

Signed-off-by: Tyler Hicks <tyhi...@canonical.com>
---
 bin/schroot-mount/schroot-mount-main.cc | 42 +++++++++++++++++++++++++++++++++
 bin/schroot-mount/schroot-mount-main.h  | 10 ++++++++
 2 files changed, 52 insertions(+)

diff --git a/bin/schroot-mount/schroot-mount-main.cc b/bin/schroot-mount/schroot-mount-main.cc
index 327f5ed..74dca47 100644
--- a/bin/schroot-mount/schroot-mount-main.cc
+++ b/bin/schroot-mount/schroot-mount-main.cc
@@ -21,6 +21,10 @@
 #include <sbuild/sbuild-mntstream.h>
 #include <sbuild/sbuild-util.h>
 
+#if defined (__linux__)
+#include <sbuild/sbuild-regex.h>
+#endif
+
 #include "schroot-mount-main.h"
 
 #include <cerrno>
@@ -214,7 +218,45 @@ main::action_mount ()
           if (status)
             exit(status);
         }
+
+        make_mount_private(entry.options, directory);
+    }
+}
+
+void
+main::make_mount_private (const std::string& options,
+                          const std::string& mountpoint)
+{
+#if defined (__linux__)
+  static sbuild::regex bind("(^|,)(|r)bind(,|$)");
+
+  if (regex_search(options, bind))
+    {
+      static sbuild::regex rbind("(^|,)rbind(,|$)");
+      bool recursive = regex_search(options, rbind);
+
+      sbuild::log_debug(sbuild::DEBUG_INFO)
+      << boost::format("Making ‘%1%’ mount point %2%private")
+      % mountpoint
+      % (recursive ? "recursively " : "")
+      << std::endl;
+
+      if (!opts->dry_run)
+        {
+          sbuild::string_list command;
+          command.push_back("/bin/mount");
+          if (opts->verbose)
+            command.push_back("-v");
+          command.push_back(recursive ? "--make-rprivate" : "--make-private");
+          command.push_back(mountpoint);
+
+          int status = run_child(command[0], command, sbuild::environment());
+
+          if (status)
+            exit(status);
+        }
     }
+#endif
 }
 
 int
diff --git a/bin/schroot-mount/schroot-mount-main.h b/bin/schroot-mount/schroot-mount-main.h
index 06c0333..371b713 100644
--- a/bin/schroot-mount/schroot-mount-main.h
+++ b/bin/schroot-mount/schroot-mount-main.h
@@ -67,6 +67,16 @@ namespace schroot_mount
     action_mount ();
 
     /**
+     * Make a bind mount use private mount propagation (Linux-specific).
+     *
+     * @param options the mount options
+     * @param mountpoint the mountpiont to make private
+     */
+    void
+    make_mount_private (const std::string& options,
+                        const std::string& mountpoint);
+
+    /**
      * Run the command specified by file (an absolute pathname), using
      * command and env as the argv and environment, respectively.
      *
-- 
2.1.4

Attachment: signature.asc
Description: Digital signature

Reply via email to