≡ Menu

Linux / Unix: chroot Command Examples

chroot command

I am a new Linux and Unix user. How do I change the root directory of a command? How do I change the root directory of a process such as web-server using a chroot command to isolate file system? How do I use a chroot to recover password or fix the damaged Linux/Unix based environment?

Each process/command on Linux and Unix-like system has current working directory called root directory of a process/command. You can change the root directory of a command using chroot command, which ends up changing the root directory for both current running process and its children.

chroot command details
DescriptionChange root directory
Category
Difficulty
Root privilegesYes
Estimated completion time30m
Contents
A process/command that is run in such a modified environment cannot access files outside the root directory. This modified environment is commonly known as “jailed directory” or “chroot jail”. Only a privileged process and root user can use chroot command. This is useful to:

  1. Privilege separation for unprivileged process such as Web-server or DNS server.
  2. Setting up a test environment.
  3. Run old programs or ABI in-compatibility programs without crashing application or system.
  4. System recovery.
  5. Reinstall the bootloader such as Grub or Lilo.
  6. Password recovery – Reset a forgotten password and more.

Purpose

The chroot command changes its current and root directories to the provided directory and then run command, if supplied, or an interactive copy of the user’s login shell. Please note that not every application can be chrooted.

Syntax

The basic syntax is as follows:

chroot /path/to/new/root command

OR

chroot /path/to/new/root /path/to/server

OR

chroot [options] /path/to/new/root /path/to/server

chroot command examples

In this example, build a mini-jail for testing purpose with bash and ls command only. First, set jail location using mkdir command:
$ J=$HOME/jail
Create directories inside $J:
$ mkdir -p $J
$ mkdir -p $J/{bin,lib64,lib}
$ cd $J

Copy /bin/bash and /bin/ls into $J/bin/ location using cp command:
$ cp -v /bin/{bash,ls} $J/bin
Copy required libs in $J. Use ldd command to print shared library dependencies for bash:
$ ldd /bin/bash
Sample outputs:

	linux-vdso.so.1 =>  (0x00007fff8d987000)
	libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00000032f7a00000)
	libdl.so.2 => /lib64/libdl.so.2 (0x00000032f6e00000)
	libc.so.6 => /lib64/libc.so.6 (0x00000032f7200000)
	/lib64/ld-linux-x86-64.so.2 (0x00000032f6a00000)

Copy libs in $J correctly from the above output:
$ cp -v /lib64/libtinfo.so.5 /lib64/libdl.so.2 /lib64/libc.so.6 /lib64/ld-linux-x86-64.so.2 $J/lib64/
Sample outputs:

`/lib64/libtinfo.so.5' -> `/home/vivek/jail/lib64/libtinfo.so.5'
`/lib64/libdl.so.2' -> `/home/vivek/jail/lib64/libdl.so.2'
`/lib64/libc.so.6' -> `/home/vivek/jail/lib64/libc.so.6'
`/lib64/ld-linux-x86-64.so.2' -> `/home/vivek/jail/lib64/ld-linux-x86-64.so.2'

Copy required libs in $J for ls command. Use ldd command to print shared library dependencies for ls command:
$ ldd /bin/ls
Sample outputs:

	linux-vdso.so.1 =>  (0x00007fff68dff000)
	libselinux.so.1 => /lib64/libselinux.so.1 (0x00000032f8a00000)
	librt.so.1 => /lib64/librt.so.1 (0x00000032f7a00000)
	libcap.so.2 => /lib64/libcap.so.2 (0x00000032fda00000)
	libacl.so.1 => /lib64/libacl.so.1 (0x00000032fbe00000)
	libc.so.6 => /lib64/libc.so.6 (0x00000032f7200000)
	libdl.so.2 => /lib64/libdl.so.2 (0x00000032f6e00000)
	/lib64/ld-linux-x86-64.so.2 (0x00000032f6a00000)
	libpthread.so.0 => /lib64/libpthread.so.0 (0x00000032f7600000)
	libattr.so.1 => /lib64/libattr.so.1 (0x00000032f9600000)

You can copy libs one-by-one or try bash shell for loop as follows:

list="$(ldd /bin/ls | egrep -o '/lib.*\.[0-9]')"
for i in $list; do cp  -v "$i" "${J}${i}"; done

Sample outputs:

`/lib64/libselinux.so.1' -> `/home/vivek/jail/lib64/libselinux.so.1'
`/lib64/librt.so.1' -> `/home/vivek/jail/lib64/librt.so.1'
`/lib64/libcap.so.2' -> `/home/vivek/jail/lib64/libcap.so.2'
`/lib64/libacl.so.1' -> `/home/vivek/jail/lib64/libacl.so.1'
`/lib64/libc.so.6' -> `/home/vivek/jail/lib64/libc.so.6'
`/lib64/libdl.so.2' -> `/home/vivek/jail/lib64/libdl.so.2'
`/lib64/ld-linux-x86-64.so.2' -> `/home/vivek/jail/lib64/ld-linux-x86-64.so.2'
`/lib64/libpthread.so.0' -> `/home/vivek/jail/lib64/libpthread.so.0'
`/lib64/libattr.so.1' -> `/home/vivek/jail/lib64/libattr.so.1'

Finally, chroot into your new jail:
$ sudo chroot $J /bin/bash
Try browsing /etc or /var:
# ls /
# ls /etc/
# ls /var/

A chrooted bash and ls application is locked into a particular directory called $HOME/$J and unable to wander around the rest of the directory tree, and sees that directory as its “/” (root) directory. This is a tremendous boost to security if configured properly. I usually lock down the following applications using the same techniques:

  1. Apache – Red Hat / CentOS: Chroot Apache 2 Web Server
  2. Nginx – Linux nginx: Chroot (Jail) Setup
  3. chroot(8) command man page:

      --userspec=USER:GROUP  specify user and group (ID or name) to use
      --groups=G_LIST        specify supplementary groups as g1,g2,..,gN
          --help     display this help and exit
          --version  output version information and exit
    
    See also
    CategoryList of Unix and Linux commands
    File Managementcat
    Network Utilitiesdighostip
    Package Managerapt
    Processes Managementbgchrootdisownfgjobskillkillallpwdxtimepidofpstree
    Searchingwhereiswhich
    User Informationgroupsidlastlastcommlognameuserswwhowhoamilidmembers

    Sysadmin because even developers need heroes!!!

    Share this tutorial on:
{ 9 comments… add one }
  • autarch princeps March 9, 2014, 6:16 pm

    You should really have a look at lxc. I’ve tried it on Fedora. It even comes with scripts to initialize a minimum Fedora or Debian inside a container. You can just install the necessary libraries and software using the package manager.

  • Prasad March 10, 2014, 3:25 am

    Best document on chroot. Thanks for sharing.

  • Mesut Tasci March 10, 2014, 4:06 pm

    How you make this gif?

  • Kettu March 17, 2014, 8:57 pm

    I see some similarities between Docker and chroot, although they are made for quite different purposes.

  • Sebastien December 23, 2014, 2:34 pm

    list="$(ldd /bin/ls | egrep -o '/lib.*\.[0-9]')"

    I would recommend:

    #!/bin/bash
    JAIL="$(pwd)" #-- if you run this in your jail directory
    echo -n "Give command name to seach libs for: "
    read bashcmd
    [ ! -e "$bashcmd" ] && echo "$bashcmd command not found. Abording." && exit
    list="$(ldd $bashcmd | egrep -o ' /.*/lib.*\.[0-9]* '|sed 's/ //g')"
    for i in $list; do cp -v "$i" "$JAIL${i}"; done

  • Christian February 16, 2015, 9:18 am

    Enhancement for your loop to copy the bash and ls dependencies:

    for i in $list; do cp -v --parents "$i" "${J}"; done

    What it does:
    It copies the whole directory structure of the dependencies so you won’t get an error if a subfolder like $HOME/jail/lib/x86_64-linux-gnu/ doesn’t exist.

  • Faron May 14, 2015, 9:46 pm

    Aren’t we supposed to `chdir` a folder first before ‘chroot’-ing it as it will tighten holes in chroot environment?

  • Diromedes Malta July 13, 2015, 9:47 pm

    Very useful. Thanks.

  • ceneblock June 15, 2016, 8:17 pm

    There are other options that will automate this for you. I’m personally fond of debootstrap.

Security: Are you a robot or human?

Leave a Comment

You can use these HTML tags and attributes: <strong> <em> <pre> <code> <a href="" title="">


   Tagged with: ,