linux 将挂载注入到私有挂载传播后面的不相交挂载命名空间中?

aurhwmvo  于 2023-01-12  发布在  Linux
关注(0)|答案(1)|浏览(113)

作为我正在为Linux容器系统(如docker和containerd/runc)开发容器诊断工具的工作的一部分,我一直在寻找一种方法,将一个挂载名称空间中的挂载注入或绑定到另一个不相交的挂载名称空间中。

问题陈述

请考虑以下场景

hostdir                                   nsdir
-------                                   -----
/                                         /         [mountns 1, pidns 1, ]
  /var/containers/container1-root         /         [mountns 2, pidns 2, propagation=private]
    [not visible]                         /c1volume [mountns 2, pidns 2]
  /var/containers/container2-root         /         [mountns 3, pidns 1, propagation=private] privileged]

container1是常规容器。它在c1volume上装载了一个卷。由于装载传播规则,主机无法看到c1volume,因为它是在输入新的装载命名空间后装载的。
container2使用主机的pid命名空间运行,因此它可以“看到”容器外与主机交互。它具有特权,也可以使用nsenter以容器方式进入主机挂载命名空间。

目标是使/var/container/container 2-root中的文件系统对container 1的名称空间mount namespace 2中运行的进程可见,例如,这样container1中的进程可以访问通常不包括在其容器映像中的附加注入工具或实用程序,并且它们可以看到pidns 2(container 1)的pid号。

我还没能想出一个办法来做到这一点。
挂载传播规则意味着从主机的挂载命名空间进行绑定挂载不会使绑定挂载对container1的挂载命名空间中的进程可见:

mkdir /var/containers/container1-root/container2
mount -o bind /var/containers/container2-root /var/containers/container1-root/container2

更改/var/containers/container1-root的装载传播似乎对此没有影响。
我可以创建一个新的挂载和进程名称空间,该名称空间可以将/var/containers/container1-root视为/,并具有一个对/var/containers/container2-root可见的绑定挂载,但它不会看到原始container 1 pid名称空间中的任何进程,也不会看到/c1volume的挂载。
我已经尝试了很多变化的技巧与pivot_rootunsharensentermount -o bind等,但尚未无济于事。
container1的leader进程(pid 1)的协作不可用;这是来自容器加工层的外部注入。

演示设置

下面是使用低级Linux原语创建一个手工容器化的演示环境的设置方法,以便您可以看到正在发生的事情。

# create "container images" (static)
mkdir images
cd images
mkdir -p container1-root/{bin,proc,sys,dev,etc} 
curl -sSLf -o container1-root/bin/busybox busybox https://busybox.net/downloads/binaries/1.35.0-x86_64-linux-musl/busybox
chmod +x container1-root/bin/busybox
for cmd in ls mount sh ; do ln -s busybox container1-root/bin/$cmd; done
cat > container1-root/enter <<'__END__'
#!/bin/sh
mount -t sysfs none /sys
exec /bin/busybox sh -i
__END__
chmod +x container1-root/enter
cp -aR container1-root container2-root
touch container1-root/container1
touch container2-root/container2
mkdir container1-root/c1volume
cd ..

# Create a volume for c1
mkdir -p volumes/c1volume
touch volumes/c1volume/i-see-c1volume

# create the container runtime dirs
for c in container1-root container2-root; do
mkdir -p {containers,workdirs,scratch}/$c
mount -t overlay overlay -o lowerdir=$PWD/images/$c,upperdir=$PWD/scratch/$c,workdir=$PWD/workdirs/$c $PWD/containers/$c
mount --make-rprivate $PWD/containers/$c
done

# [Terminal session 1: container1]
# Launch container1, with mounted volume not visible to the host and new pid namespace.
unshare -m 
mount -o bind volumes/c1volume containers/container1-root/c1volume
ls containers/container1-root/c1volume/
unshare -p -m --mount-proc --fork --propagation private --wd=containers/container1-root --root=containers/container1-root /enter
PS1='container1 # '
ls /c1volume
echo $$

# [Terminal session 2: container2]
# This container shares the host pid namespace, but not mount namespace, and does not
# have a mounted volume.
unshare -m
unshare -m --mount-proc --fork --propagation private --wd=containers/container2-root --root=containers/container2-root /enter
PS1='container2 # '

演示

现在,通过主机,您将看到

host # findmnt | egrep 'c1volume|container[12]'
├─/root/containers/container1-root                  overlay                                        overlay         rw,relatime,lowerdir=/root/images/container1-root,upperdir=/root/scratch/container1-root,workdir=/root/workdirs/container1-root
└─/root/containers/container2-root                  overlay                                        overlay         rw,relatime,lowerdir=/root/images/container2-root,upperdir=/root/scratch/container2-root,workdir=/root/workdirs/container2-root

c1体积不可见,且

host # ls /root/containers/container1-root/c1volume/
host #

其绑定安装的内容不可见。
容器2中的进程可以容器中断,然后nsenter容器2:

container2 # /bin/busybox nsenter -t 1 -m -p /bin/bash -w /root
host # nsenter -t "$(lsof -t containers/container1-root)" --all -w -r /bin/sh
# ls /c1volume
i-see-c1volume

但是无法从那里访问container2-root
可以将mount -o bind安装到/proc/$(lsof -t containers/container1-root)/root/中,但挂载传播意味着container1-root中的现有进程看不到这一点。如果使用nsenterunshare首先输入container 1的挂载名称空间,则container 2根文件系统将不再可见,因此无法绑定挂载。

knsnq2tg

knsnq2tg1#

所以我当然是在最终写完这个之后才算出来的。至少对于我的演示env来说,我必须和一个真实的的containerd进行比较才能看到。
诀窍是没有--root--wdnsenter将保留在主机根目录和工作目录中,但输入访客挂载名称空间。* 没有必要同时输入访客(container1)pid名称空间 *。

host # c1leader="$(lsof -t containers/container1-root)"
host # nsenter -t $c1leader -m
host # findmnt -o +PROPAGATION | egrep 'container[12]|c1volume'
├─/root/containers/container1-root                  overlay                                           overlay         rw,relatime,lowerdir=/root/images/container1-root,upperdir=/root/scratch/container1-root,workdir=/root/workdirs/container1-root private
│ ├─/root/containers/container1-root/c1volume       /dev/mapper/vgubuntu-root[/root/volumes/c1volume] ext4            rw,relatime,errors=remount-ro                                                                                                   private
│ ├─/root/containers/container1-root/proc           proc                                              proc            rw,nosuid,nodev,noexec,relatime                                                                                                 private
│ │ └─/root/containers/container1-root/proc         none                                              proc            rw,relatime                                                                                                                     private
│ └─/root/containers/container1-root/sys            none                                              sysfs           rw,relatime                                                                                                                     private
└─/root/containers/container2-root                  overlay                                           overlay         rw,relatime,lowerdir=/root/images/container2-root,upperdir=/root/scratch/container2-root,workdir=/root/workdirs/container2-root private
host # mkdir /root/containers/container1-root/container2-root
host # mount -o bind,ro /root/containers/container2-root /root/containers/container1-root/container2-root

现在在container1的会话中:

container1 # ls /
bin              c1volume         container1       container2-root  dev              enter            etc              foo              proc             sys
container1 # ls /c1volume/
i-see-c1volume
container1 # ls container2-root/
bin         container2  dev         enter       etc         proc        sys
container1 # busybox ps
PID   USER     TIME  COMMAND
    1 0         0:00 /bin/busybox sh -i
   24 0         0:00 busybox ps

相关问题