Chroot with unionfs-fuse, can’t access /dev/*

chrootdevicesmountunionfs

I have created the a chroot jail in combination with unionfs-fuse so that I don't need to install another system inside it.

However, the resulting system's /dev entries are not readable.This is causing problems with programs needing access to /dev/random, /dev/null and /dev/urandom.

I tried to solve the issue myself by making a directory consisting of persistent files and making equivalents of the aforementioned files using mknod as described here, and then creating an unionfs:

# unionfs-fuse -o cow /chroot/files=RW:/chroot/persistent/:/ /chroot/chroot/

And then,

# chroot chroot/

But, when I try to:

# head -c 10 /dev/random | hexdump -C

I get the error:

head: cannot open `/dev/random' for reading: Permission denied

How should I work around this problem?

(I do not need access to other files in /dev like /dev/sd* or /dev/mem.)

Best Answer

The explanation lies in the mount.fuse man page:

Filesystems are mounted with nodev,nosuid by default, which can only be overridden by a privileged user

With the nodev option, the kernel bans all access to devices in the mounted filesystem. With the nosuid option, the kernel ignores setuid and setgid attributes. Both options are necessary for security when a filesystem is mounted by a non-root user: otherwise the mounting user could create a setuid root shell or devices letting him access all disks bypassing the filesystem.

You'll also want the allow_other option if non-root users are to access that filesystem.

unionfs-fuse -o cow,dev,suid,allow_other /chroot/files=RW:/chroot/persistent/:/ /chroot/chroot/

If you want to restrict which devices are visible in the chroot, then a union mount isn't the way to do that. Instead, leave dev off and mount a separate filesystem containing your desired minimal /dev. You can make that a tmpfs:

unionfs-fuse -o cow,suid,allow_other /chroot/files=RW:/chroot/persistent/:/ /chroot/chroot/
mount -t tmpfs -o mode=755 chroot-dev /chroot/chroot/dev
cp -a /dev/null /dev/zero /dev/urandom /chroot/chroot/dev
mkdir /chroot/chroot/dev/pts
mount --bind /dev/pts /chroot/chroot/dev/pts

Instead of a tmpfs, you could bind-mount a directory containing your devices ready to go. You'll need to bind-mount /dev/pts to get pseudoterminals in the chroot.

Related Question