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 <christian@iwakd.de>
Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
Cc: Daniel Lezcano <daniel.lezcano@free.fr>
This commit is contained in:
Christian Seiler 2012-08-22 00:03:16 +02:00 committed by Stéphane Graber
parent e13eeea2db
commit 7a0b0b5672
4 changed files with 101 additions and 9 deletions

View 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>

View 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();

View 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

View 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;