From: Christian Seiler Date: Tue, 21 Aug 2012 22:03:16 +0000 (+0200) Subject: lxc-attach: Add -R option to remount /sys and /proc when only partially attaching X-Git-Tag: lxc-0.9.0.alpha1~1^2~157 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7a0b0b5672a33c190eefb4b2d3e3693241c130f2;p=thirdparty%2Flxc.git lxc-attach: Add -R option to remount /sys and /proc when only partially attaching 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 Acked-by: Serge Hallyn Cc: Daniel Lezcano --- 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;