[lxc-devel] A question about chroot_into_slave()

Andrey Wagin avagin at gmail.com
Fri Oct 3 15:02:08 UTC 2014


On Fri, Oct 03, 2014 at 02:24:55PM +0000, Serge Hallyn wrote:
> Quoting Andrey Wagin (avagin at gmail.com):
> > 2014-10-03 1:23 GMT+04:00 Serge Hallyn <serge.hallyn at ubuntu.com>:
> > > Quoting Andrey Wagin (avagin at gmail.com):
> > >> 2014-10-02 20:25 GMT+04:00 Serge Hallyn <serge.hallyn at ubuntu.com>:
> > >> > Quoting Andrey Wagin (avagin at gmail.com):
> > >> >> Hi All,
> > >> >>
> > >> >> chroot_into_slave() is called if the root / is ramfs.
> > >> >>
> > >> >> chroot_into_slave() mount tmpfs, creates a directory there and
> > >> >> bind-mounts the host root into this directory.
> > >> >> _ host_root
> > >> >>  \_ tmp
> > >> >>   \_ host_root (bind)
> > >> >>    \_ ct_root
> > >> >>
> > >> >> Then pivot_root() exchange "host_root (bind)" and "ct_root" and
> > >> >> "host_root (bind)". After that "host_root (bind)" is umounted.
> > >> >> _host_root
> > >> >>  \_ tmp
> > >> >>    \_ct_root
> > >> >>
> > >> >> Here is my question. Why we can't do chroot(conf->rootfs.mount)
> > >> >> instead of chroot_into_slave() & pivot_root(conf->rootfs.mount). I
> > >> >> think the result will be the same with less amount of not obvious
> > >> >> steps. Have I missed something?
> > >> >
> > >> > Do you mean not to pivot_root at all?  If so, because chroot is not
> > >> > an adequate replacement:  you can trivially escape it, and /proc/mounts
> > >> > wil be polluted.
> > >>
> > >> /proc/ will not be polluted:
> > >>
> > >> root at ubuntu:/home/avagin# chroot centos
> > >> [root at ubuntu /]# mount -t proc proc /proc/
> > >> [root at ubuntu /]# cat /proc/self/mountinfo
> > >> 64 21 0:3 / /proc rw,relatime - proc proc rw
> > >>
> > >> root at ubuntu:/home/avagin# cat /proc/9529/mountinfo
> > >> 64 21 0:3 / /proc rw,relatime - proc proc rw
> > >
> > > cat /proc/$$/mounts
> > >
> > >> Now I want to show you, that chroot_into_slave() & pivot_root()
> > >> doesn't defend you against escaping from a container. Let's repeate
> > >> all actions, which lxc does for the root on ramfs. I don't have a host
> > >> with root on ramfs, so I do all actions in my VM.
> > >>
> > >> # chroot_into_slave()
> > >> root at ubuntu:/home/avagin# unshare -m -- /bin/bash
> > >> root at ubuntu:/home/avagin# mount --bind rootfs rootfs
> > >> root at ubuntu:/home/avagin# mount --make-slave rootfs
> > >> root at ubuntu:/home/avagin# mount -t tmpfs tmpfs rootfs
> > >> root at ubuntu:/home/avagin# mkdir rootfs/root
> > >> root at ubuntu:/home/avagin# mount --rbind / rootfs/root/
> > >> root at ubuntu:/home/avagin# mount --make-rslave rootfs/
> > >> root at ubuntu:/home/avagin# chroot rootfs/root/
> > >> root at ubuntu:/# cd /
> > >>
> > >> # mount_rootfs() & pivot_root()
> > >> root at ubuntu:/# mount /home/avagin/centos /home/avagin/rootfs/
> > >> mount: /home/avagin/centos is not a block device
> > >> root at ubuntu:/# mount --bind /home/avagin/centos /home/avagin/rootfs/
> > >> root at ubuntu:/# cd /home/avagin/rootfs/
> > >> root at ubuntu:/home/avagin/rootfs# mkdir old
> > >> root at ubuntu:/home/avagin/rootfs# pivot_root . old
> > >> root at ubuntu:/home/avagin/rootfs# cd /
> > >> root at ubuntu:/# cat /etc/redhat-release
> > >> CentOS release 5.10 (Final)
> > >> root at ubuntu:/# mount -t proc proc /proc/
> > >> root at ubuntu:/# umount -l old/
> > >> root at ubuntu:/# cat /proc/self/mountinfo
> > >> 153 125 8:1 /home/avagin/centos / rw,relatime - ext4
> > >> /dev/disk/by-uuid/291e7b1a-8396-44cf-9927-578b3401d0bd
> > >> rw,errors=remount-ro,data=ordered
> > >> 154 153 0:3 / /proc rw,relatime - proc proc rw
> > >>
> > >> Now let's try to escape from this CT. I take the code from
> > >> http://www.bpfh.net/simes/computing/chroot-break.html
> > >>
> > >> root at ubuntu:/# ls -l /etc/redhat-release
> > >> -rw-r--r-- 1 root root 28 Oct  7  2013 /etc/redhat-release
> > >> root at ubuntu:/# ./breaking_chroot
> > >> # ls -l /etc/redhat-release
> > >> ls: cannot access /etc/redhat-release: No such file or directory
> > >> #
> > >> # cat /etc/lsb-release
> > >> DISTRIB_ID=Ubuntu
> > >> DISTRIB_RELEASE=14.04
> > >> DISTRIB_CODENAME=trusty
> > >> DISTRIB_DESCRIPTION="Ubuntu 14.04 LTS"
> > >>
> > >> It works. We are able to escape from CT.
> > >
> > > It doesn't work on my system.  I'm curious what the difference might be.
> > 
> > Did you use lxc-start to start a container? If it's yes, did you force
> 
> 
> No, I did it by hand using the same steps you did above.  For
> rootfs I used a utopic container rootfs sitting under
> /var/lib/lxc/lb/rootfs
> 
>

Could you repeat the same sequence of commands in your environment and
show console output?

root at ubuntu:~# uname -a
Linux ubuntu 3.13.0-30-generic #54-Ubuntu SMP Mon Jun 9 22:45:01 UTC
2014 x86_64 x86_64 x86_64 GNU/Linux
root at ubuntu:~# cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.1 LTS"

root at ubuntu:/home/avagin# mkdir -p /var/lib/lxc/lb/rootfs
root at ubuntu:/home/avagin# set -e
root at ubuntu:/home/avagin# unshare -m -- /bin/bash
root at ubuntu:/home/avagin# set -e
root at ubuntu:/home/avagin# mount --bind /var/lib/lxc/lb/rootfs /var/lib/lxc/lb/rootfs
root at ubuntu:/home/avagin# mount --make-slave /var/lib/lxc/lb/rootfs
root at ubuntu:/home/avagin# mount -t tmpfs tmpfs /var/lib/lxc/lb/rootfs
root at ubuntu:/home/avagin# mkdir /var/lib/lxc/lb/rootfs/root
root at ubuntu:/home/avagin# mount --rbind / /var/lib/lxc/lb/rootfs/root/
root at ubuntu:/home/avagin# mount --make-rslave /var/lib/lxc/lb/rootfs
root at ubuntu:/home/avagin# chroot /var/lib/lxc/lb/rootfs/root/
root at ubuntu:/# set -e
root at ubuntu:/# cd /
root at ubuntu:/# mount --bind /home/avagin/centos /var/lib/lxc/lb/rootfs
root at ubuntu:/# cd /var/lib/lxc/lb/rootfs
root at ubuntu:/var/lib/lxc/lb/rootfs# mkdir -p old
root at ubuntu:/var/lib/lxc/lb/rootfs# pivot_root . old
root at ubuntu:/var/lib/lxc/lb/rootfs# cd /
root at ubuntu:/# cat /etc/redhat-release
CentOS release 5.10 (Final)
root at ubuntu:/# mount -t proc proc /proc/
root at ubuntu:/# umount -l old/
root at ubuntu:/# cat /proc/self/mountinfo
125 96 8:1 /home/avagin/centos / rw,relatime - ext4
/dev/disk/by-uuid/291e7b1a-8396-44cf-9927-578b3401d0bd
rw,errors=remount-ro,data=ordered
126 125 0:3 / /proc rw,relatime - proc proc rw
root at ubuntu:/# echo $$
2703

And from another console:
root at ubuntu:~# cat nsenter.c 
#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <sched.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
	int fd;

	fd = open("/proc/2703/ns/mnt", O_RDONLY); // Don't foget to set a proper pid here.
	if (fd < 0)
		return 1;
	if (setns(fd, CLONE_NEWNS))
		return 1;

	execl("/bin/bash", "/bin/bash", NULL);
	return 1;
}
root at ubuntu:~# gcc -o nsenter nsenter.c
root at ubuntu:~# ./nsenter 
root at ubuntu:/# cat /proc/self/mountinfo | head -n 1
69 68 8:1 / / rw,relatime - ext4 /dev/disk/by-uuid/291e7b1a-8396-44cf-9927-578b3401d0bd rw,errors=remount-ro,data=ordered

Thank you for your time.


More information about the lxc-devel mailing list