]> git.proxmox.com Git - mirror_lxc.git/commitdiff
lxc-attach: Add -R option to remount /sys and /proc when only partially attaching
authorChristian Seiler <christian@iwakd.de>
Tue, 21 Aug 2012 22:03:16 +0000 (00:03 +0200)
committerStéphane Graber <stgraber@ubuntu.com>
Mon, 12 Nov 2012 18:16:16 +0000 (13:16 -0500)
When attaching to only some namespaces of the container but not the mount
namespace, the contents of /sys and /proc of the host system do not properly
reflect the context of the container's pid and/or network namespaces, and
possibly others.

The introduced -R option adds the possibility to additionally unshare the
mount namespace (when it is not being attached) and remount /sys and /proc
in order for those filesystems to properly reflect the container's context
even when only attaching to some of the namespaces.

Signed-off-by: Christian Seiler <christian@iwakd.de>
Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
Cc: Daniel Lezcano <daniel.lezcano@free.fr>
doc/lxc-attach.sgml.in
src/lxc/attach.c
src/lxc/attach.h
src/lxc/lxc_attach.c

index d5154fd1869ae2050a6e68ee9b5e3a6c20d894d1..a9a29021b4ea6fb6c2d0df184f4e09bfe2b184f5 100644 (file)
@@ -53,6 +53,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
       <arg choice="opt">-a <replaceable>arch</replaceable></arg>
       <arg choice="opt">-e</arg>
       <arg choice="opt">-s <replaceable>namespaces</replaceable></arg>
+      <arg choice="opt">-R</arg>
       <arg choice="opt">-- <replaceable>command</replaceable></arg>
     </cmdsynopsis>
   </refsynopsisdiv>
@@ -149,7 +150,30 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
        </listitem>
       </varlistentry>
 
-    </variablelist>
+      <varlistentry>
+       <term>
+         <option>-R, --remount-sys-proc</option>
+       </term>
+       <listitem>
+         <para>
+           When using <option>-s</option> and the mount namespace is not
+           included, this flag will cause <command>lxc-attach</command>
+           to remount <replaceable>/proc</replaceable> and
+           <replaceable>/sys</replaceable> to reflect the current other
+           namespace contexts.
+         </para>
+         <para>
+           Please see the <emphasis>Notes</emphasis> section for more
+           details.
+         </para>
+         <para>
+           This option will be ignored if one tries to attach to the
+           mount namespace anyway.
+         </para>
+       </listitem>
+      </varlistentry>
+
+     </variablelist>
 
   </refsect1>
 
@@ -232,13 +256,16 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
       the network namespace.
     </para>
     <para>
-      A workaround is to use <command>lxc-unshare</command> to unshare
-      the mount namespace after using <command>lxc-attach</command> with
-      <replaceable>-s PID</replaceable> and/or <replaceable>-s
-      NETWORK</replaceable> and then unmount and then mount again both
-      pseudo-filesystems within that new mount namespace, before
-      executing a program/script that relies on this information to be
-      correct.
+      To work around this problem, the <option>-R</option> flag provides
+      the option to remount <replaceable>/proc</replaceable> and
+      <replaceable>/sys</replaceable> in order for them to reflect the
+      network/pid namespace context of the attached process. In order
+      not to interfere with the host's actual filesystem, the mount
+      namespace will be unshared (like <command>lxc-unshare</command>
+      does) before this is done, esentially giving the process a new
+      mount namespace, which is identical to the hosts's mount namespace
+      except for the <replaceable>/proc</replaceable> and
+      <replaceable>/sys</replaceable> filesystems.
     </para>
   </refsect1>
 
index 37e667fe1c194aa4319b7f23e412349b17164abb..ec0e08300e28af9148ad90ae89f53a51393708b8 100644 (file)
@@ -30,6 +30,7 @@
 #include <fcntl.h>
 #include <sys/param.h>
 #include <sys/prctl.h>
+#include <sys/mount.h>
 #include <linux/unistd.h>
 
 #if !HAVE_DECL_PR_CAPBSET_DROP
@@ -188,6 +189,49 @@ int lxc_attach_to_ns(pid_t pid, int which)
        return 0;
 }
 
+int lxc_attach_remount_sys_proc()
+{
+       int ret;
+
+       ret = unshare(CLONE_NEWNS);
+       if (ret < 0) {
+               SYSERROR("failed to unshare mount namespace");
+               return -1;
+       }
+
+       /* assume /proc is always mounted, so remount it */
+       ret = umount2("/proc", MNT_DETACH);
+       if (ret < 0) {
+               SYSERROR("failed to unmount /proc");
+               return -1;
+       }
+
+       ret = mount("none", "/proc", "proc", 0, NULL);
+       if (ret < 0) {
+               SYSERROR("failed to remount /proc");
+               return -1;
+       }
+
+       /* try to umount /sys - if it's not a mount point,
+        * we'll get EINVAL, then we ignore it because it
+        * may not have been mounted in the first place
+        */
+       ret = umount2("/sys", MNT_DETACH);
+       if (ret < 0 && errno != EINVAL) {
+               SYSERROR("failed to unmount /sys");
+               return -1;
+       } else if (ret == 0) {
+               /* remount it */
+               ret = mount("none", "/sys", "sysfs", 0, NULL);
+               if (ret < 0) {
+                       SYSERROR("failed to remount /sys");
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
 int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx)
 {
        int last_cap = lxc_caps_last_cap();
index d96fdae42e1571a9a0bb7a221628a3de180b6d2f..aab47e33fe24347896ecc34fbf240bf7703c4607 100644 (file)
@@ -34,6 +34,7 @@ struct lxc_proc_context_info {
 extern struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid);
 
 extern int lxc_attach_to_ns(pid_t other_pid, int which);
+extern int lxc_attach_remount_sys_proc();
 extern int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx);
 
 #endif
index 4f2275207c5419a5e19c764a96b41b1ad7a24a4b..e292bc4bed68546d09a998bc24daab8a813ca547 100644 (file)
@@ -48,12 +48,14 @@ static const struct option my_longopts[] = {
        {"elevated-privileges", no_argument, 0, 'e'},
        {"arch", required_argument, 0, 'a'},
        {"namespaces", required_argument, 0, 's'},
+       {"remount-sys-proc", no_argument, 0, 'R'},
        LXC_COMMON_OPTIONS
 };
 
 static int elevated_privileges = 0;
 static signed long new_personality = -1;
 static int namespace_flags = -1;
+static int remount_sys_proc = 0;
 
 static int my_parser(struct lxc_arguments* args, int c, char* arg)
 {
@@ -61,6 +63,7 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
 
        switch (c) {
        case 'e': elevated_privileges = 1; break;
+       case 'R': remount_sys_proc = 1; break;
        case 'a':
                new_personality = lxc_config_parse_arch(arg);
                if (new_personality < 0) {
@@ -102,7 +105,12 @@ Options :\n\
                     but just to the following OR'd list of flags:\n\
                     MOUNT, PID, UTSNAME, IPC, USER or NETWORK\n\
                     WARNING: Using -s implies -e, it may therefore\n\
-                    leak privileges into the container. Use with care.\n",
+                    leak privileges into the container. Use with care.\n\
+  -R, --remount-sys-proc\n\
+                    Remount /sys and /proc if not attaching to the\n\
+                    mount namespace when using -s in order to properly\n\
+                    reflect the correct namespace context. See the\n\
+                    lxc-attach(1) manual page for details.\n",
        .options  = my_longopts,
        .parser   = my_parser,
        .checker  = NULL,
@@ -253,6 +261,18 @@ int main(int argc, char *argv[])
                lxc_sync_fini_parent(handler);
                lxc_cgroup_dispose_attach(cgroup_data);
 
+               /* A description of the purpose of this functionality is
+                * provided in the lxc-attach(1) manual page. We have to
+                * remount here and not in the parent process, otherwise
+                * /proc may not properly reflect the new pid namespace.
+                */
+               if (!(namespace_flags & CLONE_NEWNS) && remount_sys_proc) {
+                       ret = lxc_attach_remount_sys_proc();
+                       if (ret < 0) {
+                               return -1;
+                       }
+               }
+
                if (new_personality < 0)
                        new_personality = init_ctx->personality;