Detecting a chroot jail from within Detecting a chroot jail from within linux linux

Detecting a chroot jail from within


The inode for / will always be 2 if it's the root directory of a filesystem, but you may be chrooted inside a complete filesystem. If it's just chroot (and not some other virtualization), you could run mount and compare the mounted filesystems against what you see. Verify that every mount point has inode 2.


If you are not in a chroot, the inode for / will always be 2. You may check that using

stat -c %i /

or

ls -id /

Interresting, but let's try to find path of chroot directory. Ask to stat on which device / is located:

stat -c %04D /

First byte is major of device and lest byte is minor. For example, 0802, means major 8, minor 1. If you check in /dev, you will see this device is /dev/sda2. If you are root you can directly create correspondong device in your chroot:

mknode /tmp/root_dev b 8 1

Now, let's find inode associated to our chroot. debugfs allows list contents of files using inode numbers. For exemple, ls -id / returned 923960:

sudo debugfs /tmp/root_dev -R 'ls <923960>' 923960  (12) .       915821  (32) ..     5636100  (12) var   5636319  (12) lib    5636322  (12) usr    5636345  (12) tmp   5636346  (12) sys    5636347  (12) sbin   5636348  (12) run   5636349  (12) root   5636350  (12) proc   5636351  (12) mnt   5636352  (12) home   5636353  (12) dev    5636354  (12) boot   5636355  (12) bin    5636356  (12) etc    5638152  (16) selinux   5769366  (12) srv    5769367  (12) opt    5769375  (3832) media 

Interesting information is inode of .. entry: 915821. I can ask its content:

sudo debugfs /tmp/root_dev -R 'ls <915821>'915821  (12) .              2  (12) ..    923960  (20) debian-jail   923961  (4052) other-jail  

Directory called debian-jail has inode 923960. So last component of my chroot dir is debian-jail. Let's see parent directory (inode 2) now:

sudo debugfs /tmp/root_dev -R 'ls <2>'      2  (12) .           2  (12) ..          11  (20) lost+found    1046529  (12) home    130817  (12) etc    784897  (16) media     3603  (20) initrd.img    261633  (12) var    654081  (12) usr     392449  (12) sys            392450  (12) lib    784898  (12) root   915715  (12) sbin   1046530  (12) tmp   1046531  (12) bin    784899  (12) dev     392451  (12) mnt    915716  (12) run        12  (12) proc   1046532  (12) boot               13  (16) lib64    784945  (12) srv    915821  (12) opt       3604  (3796) vmlinuz 

Directory called opt has inode 915821 and inode 2 is root of filesystem. So my chroot directory is /opt/debian-jail. Sure, /dev/sda1 may be mounted on another filesystem. You need to check that (use lsof or directly picking information /proc).


On Linux with root permissions, test if the root directory of the init process is your root directory. Although /proc/1/root is always a symbolic link to /, following it leads to the “master” root directory (assuming the init process is not chrooted, but that's hardly ever done). If /proc isn't mounted, you can bet you're in a chroot.

[ "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" ]# With ash/bash/ksh/zsh! [ -x /proc/1/root/. ] || [ /proc/1/root/. -ef / ]

This is more precise than looking at /proc/1/exe because that could be different outside a chroot if init has been upgraded since the last boot or if the chroot is on the main root filesystem and init is hard linked in it.

If you do not have root permissions, you can look at /proc/1/mountinfo and /proc/$$/mountinfo (briefly documented in filesystems/proc.txt in the Linux kernel documentation). This file is world-readable and contains a lot of information about each mount point in the process's view of the filesystem. The paths in that file are restricted by the chroot affecting the reader process, if any. If the process reading /proc/1/mountinfo is chrooted into a filesystem that's different from the global root (assuming pid 1's root is the global root), then no entry for / appears in /proc/1/mountinfo. If the process reading /proc/1/mountinfo is chrooted to a directory on the global root filesystem, then an entry for / appears in /proc/1/mountinfo, but with a different mount id. Incidentally, the root field ($4) indicates where the chroot is in its master filesystem. Again, this is specific to Linux.

[ "$(awk '$5=="/" {print $1}' </proc/1/mountinfo)" != "$(awk '$5=="/" {print $1}' </proc/$$/mountinfo)" ]