diff --git a/doc/lxc-attach.sgml.in b/doc/lxc-attach.sgml.in
index d5154fd18..a9a29021b 100644
--- a/doc/lxc-attach.sgml.in
+++ b/doc/lxc-attach.sgml.in
@@ -53,6 +53,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-a arch-e-s namespaces
+ -R-- command
@@ -149,7 +150,30 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
+
+
+
+
+
+
+ When using and the mount namespace is not
+ included, this flag will cause lxc-attach
+ to remount /proc and
+ /sys to reflect the current other
+ namespace contexts.
+
+
+ Please see the Notes section for more
+ details.
+
+
+ This option will be ignored if one tries to attach to the
+ mount namespace anyway.
+
+
+
+
+
@@ -232,13 +256,16 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
the network namespace.
- A workaround is to use lxc-unshare to unshare
- the mount namespace after using lxc-attach with
- -s PID and/or -s
- NETWORK 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 flag provides
+ the option to remount /proc and
+ /sys 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 lxc-unshare
+ 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 /proc and
+ /sys filesystems.
diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index 37e667fe1..ec0e08300 100644
--- a/src/lxc/attach.c
+++ b/src/lxc/attach.c
@@ -30,6 +30,7 @@
#include
#include
#include
+#include
#include
#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();
diff --git a/src/lxc/attach.h b/src/lxc/attach.h
index d96fdae42..aab47e33f 100644
--- a/src/lxc/attach.h
+++ b/src/lxc/attach.h
@@ -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
diff --git a/src/lxc/lxc_attach.c b/src/lxc/lxc_attach.c
index 4f2275207..e292bc4be 100644
--- a/src/lxc/lxc_attach.c
+++ b/src/lxc/lxc_attach.c
@@ -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;