mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-08-14 07:47:05 +00:00
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:
parent
e13eeea2db
commit
7a0b0b5672
@ -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>
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user